From 1bdc94ef22bb18723eda6a08252916c2778e58b2 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Oct 30 2018 04:53:40 +0000 Subject: import qemu-kvm-ma-2.12.0-18.el7 --- diff --git a/.gitignore b/.gitignore index 9bb96ef..1afb20f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ SOURCES/bios-256k.bin SOURCES/kvm-unit-tests.git-4ea7633.tar.bz2 SOURCES/pxe-e1000e.rom -SOURCES/qemu-2.10.0.tar.xz +SOURCES/qemu-2.12.0.tar.xz SOURCES/rhel6-e1000.rom SOURCES/rhel6-ne2k_pci.rom SOURCES/rhel6-pcnet.rom diff --git a/.qemu-kvm-ma.metadata b/.qemu-kvm-ma.metadata index 189fa8b..37bd308 100644 --- a/.qemu-kvm-ma.metadata +++ b/.qemu-kvm-ma.metadata @@ -1,7 +1,7 @@ 5678cee702e664634abf28dce0688d01683611dd SOURCES/bios-256k.bin 8d79fca1e904b82272ebf96bbb65f858e1c491a9 SOURCES/kvm-unit-tests.git-4ea7633.tar.bz2 e304721d2b96cdf9dfa89e07947f19ef3e26107e SOURCES/pxe-e1000e.rom -5d6815fa3ab1c6163c7e886f26153feabdcbb0f8 SOURCES/qemu-2.10.0.tar.xz +5a62c911b2cebbd41decd5c77c524395212411cf SOURCES/qemu-2.12.0.tar.xz 957fd6b653b4550c6be727385331d58f1381e082 SOURCES/rhel6-e1000.rom 3f183b9c65e959ab346a013828f1d7530bc4a14e SOURCES/rhel6-ne2k_pci.rom 5bf1eb9f40dc52fa2c9bfecd9330af03a49b35f9 SOURCES/rhel6-pcnet.rom diff --git a/SOURCES/0001-Revert-qemu-pr-helper-use-new-libmultipath-API.patch b/SOURCES/0001-Revert-qemu-pr-helper-use-new-libmultipath-API.patch new file mode 100644 index 0000000..a02426c --- /dev/null +++ b/SOURCES/0001-Revert-qemu-pr-helper-use-new-libmultipath-API.patch @@ -0,0 +1,75 @@ +From 1bd23e669764623512441f335b3a09b46265a9fa Mon Sep 17 00:00:00 2001 +From: Miroslav Rezanina +Date: Tue, 5 Dec 2017 17:28:56 +0100 +Subject: Revert "qemu-pr-helper: use new libmultipath API" + +This reverts commit b3f1c8c413bc83e4a2cc7a63e4eddf9fe6449052. + +We have to revert this change in RHEL 7 as new libmultipath API is +not available. +--- + configure | 12 ++---------- + scsi/qemu-pr-helper.c | 17 +++-------------- + 2 files changed, 5 insertions(+), 24 deletions(-) + +diff --git a/configure b/configure +index 0a19b03..e9243f5 100755 +--- a/configure ++++ b/configure +@@ -3472,17 +3472,9 @@ if test "$mpath" != "no" ; then + #include + unsigned mpath_mx_alloc_len = 1024; + int logsink; +-static struct config *multipath_conf; +-extern struct udev *udev; +-extern struct config *get_multipath_config(void); +-extern void put_multipath_config(struct config *conf); +-struct udev *udev; +-struct config *get_multipath_config(void) { return multipath_conf; } +-void put_multipath_config(struct config *conf) { } +- + int main(void) { +- udev = udev_new(); +- multipath_conf = mpath_lib_init(); ++ struct udev *udev = udev_new(); ++ mpath_lib_init(udev); + return 0; + } + EOF +diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c +index d0f8317..7a29e64 100644 +--- a/scsi/qemu-pr-helper.c ++++ b/scsi/qemu-pr-helper.c +@@ -276,26 +276,15 @@ static void dm_init(void) + + /* Variables required by libmultipath and libmpathpersist. */ + QEMU_BUILD_BUG_ON(PR_HELPER_DATA_SIZE > MPATH_MAX_PARAM_LEN); +-static struct config *multipath_conf; + unsigned mpath_mx_alloc_len = PR_HELPER_DATA_SIZE; + int logsink; +-struct udev *udev; +- +-extern struct config *get_multipath_config(void); +-struct config *get_multipath_config(void) +-{ +- return multipath_conf; +-} +- +-extern void put_multipath_config(struct config *conf); +-void put_multipath_config(struct config *conf) +-{ +-} + + static void multipath_pr_init(void) + { ++ static struct udev *udev; ++ + udev = udev_new(); +- multipath_conf = mpath_lib_init(); ++ mpath_lib_init(udev); + } + + static int is_mpath(int fd) +-- +1.8.3.1 + diff --git a/SOURCES/0002-Initial-redhat-build.patch b/SOURCES/0002-Initial-redhat-build.patch deleted file mode 100644 index b0a528f..0000000 --- a/SOURCES/0002-Initial-redhat-build.patch +++ /dev/null @@ -1,938 +0,0 @@ -From ba7591ec4a0906121d15ffbf740580bd79ec5814 Mon Sep 17 00:00:00 2001 -From: Miroslav Rezanina -Date: Mon, 11 Sep 2017 07:11:00 +0200 -Subject: Initial redhat build - -This patch introduces redhat build structure in redhat subdirectory. In addition, -several issues are fixed in QEMU tree: - -- Change of app name for sasl_server_init in VNC code from qemu to qemu-kvm - - As we use qemu-kvm as name in all places, this is updated to be consistent -- Man page renamed from qemu to qemu-kvm - - man page is installed using make install so we have to fix it in qemu tree -- Added live-block-migration configuration option support - - Downstream differentiation support -- Use "/share/qemu-kvm" as SHARE_SUFFIX - - We reconfigured our share to qemu-kvm to be consistent with used name -- Added .gitpublish configuration file - - Support for git publish has to be stored in repository root - --- -Rebase notes (2.10.0): -- live_block_migration option added upstream -- moved qmp-spec.txt file (upstream) -- added s390-netboot.img (added upstream) -- removed qemu_vga.ndrv (added upstream) -- switch to (rhevh-)rhel-7.5-candidate -- switched differentiation defaults -- moved binary files to separate commit - -Rebase notes (2.9.0): -- documentation files handling changes (upstrem) -- removed --enable-colo option and --disable-archipelago (upstream) -- bump BuildRequires versions -- new mandatory argument for tracetool.py (upstream) -- updated RHEL 6 roms -- switch from sha1sum to sha256sum -- Moved adding rhel6-e1000.rom from machine types commit -- Moved adding pxe-e1000e.rom from device disable commit -- Use rdma-core instead of librdmacm -- Add upstream tarballs tar.xz to .gitignore -- Updated git-backport-diff script - -Rebase notes (2.8.0): -- removed vhdx option (upstream) -- qemu-tech.html merged to qemu-doc.html (upstream) -- removed skiboot.lid firmware -- Changed tracetool.py parameters -- Added support for easy z-stream switch - -Rebase notes (2.7.0): -- removed kvm_stat -- added efi-e1000e.rom -- added efi-vmxnet.rom -- added linuxboot_dma.bin -- trace-events renamed to trace-events-all -- reverted dependency to seccomp on aarch64 -- Add ipxe-qemu-roms ad build dependency to pass tests - -Rebase notes (2.6.0): -- removed q35-acpi-dsdt.aml -- add enable-gcrypt option - -Rebase notes (2.5.0): -- New seccomp hadling in configure -- New condition format in migration/migration.c -- libcacard extracted -- vnc fixes -- libsecomp for aarch64 requirements changed downstream - -Rebase notes (2.4.0): -- remove --enable-ws-vnc -- use error_setg instead of error_set in migration/migration.c -- remove target-x86_64.conf -- create /etc/qemu-kvm on copying of bridge.conf -- disabled opengl -- rebased to version 2.3.0-30.el7 - -Merged patches (rebase 2.10.0) -- feefd46 qemu-kvm.spec: Enable s390x build -- 985051e Removing texi2html from build requirements -- 7c64a2a Update ignore files for redhat usage -- 8f9a95a Disable replication feature -- 1b7bbc5 block/vxhs: modularize VXHS via g_module -- 7511527 Remove the dependencies to seavgabios-bin and ipxe-roms-qemu on s390x -- aa0891c Downstream: Don't disable SMT on POWER9 hosts -- a13a0e9 Update configuration for qemu 2.9 -- bbf46dd disable pulseaudio and alsa -- 9124839 redhat/Makefile: honor BREW_FLAGS like the kernel -- 53c03bd copy SLIT test reference blobs into tests directory -- c4c77e6 Differentiation support -- f1ec0e8 configure: allow to disable VT-d emulation -- b972023 Disable VT-d for rhel builds -- 29a0414 RHEL Diff.: Add option in configure to disable live block ops -- 1f33b29 RHEL Diff.: Unregister live block operations -- c590551 RHEL Diff.: Disable live block operations in HMP monitor -- c7e208f RHEL Diff.: Add rpm spec options for live block ops -- 733af5c pegas: add rpm spec options for vhost-user -- ff16138 Add support for local build -- fb426d4 qemu-kvm.spec: Configure vm.allocate_pgste for s390x - -Merged patches (rebase 2.9.0) -- 9c7ab94 Enable seccomp for ppc64/ppc64le architecture -- f6d7e9d Update qemu-kvm package Summary and Description -- a9e55b6 Disable usbredir and libcacard for unsupported architectures -- 0218220 Update configuration for 2.8.0 release - -Merged patches (rebase 2.7.0) -- 2be6077 Fix SLOF dependency -- dc58590 spec: Remove dependency to ipxe-roms-qemu for aarch64 -- 357ef43 spec: link sgabios.bin only for x86_64 -- 08d82cc spec: Update rules before triggering for kvm device -- 8980a76 spec: Do not package ivshmem-server and ivshmem-client -- 027067c spec: add a sample kvm.conf to enable Nested Virtualization -- ba2ba30 Adjust locked memory limits to allow unprivileged VMs on Power -- e9740b0 Increase locked memory limit for all users, not just kvm group -- 8c301be add vgabios-virtio.bin symlink -- 4d03723 usb: enable streams support -- 2a9363e Add install dependency required for usb streams -- 9a54442 Add dump-guest-memory.py to all archs -- 73fffc9 add e1000e ipxe rom symlink -- aaaa2a9 Add 'luks' to block driver whitelist -- c78c3a8 redhat: switch from gcrypt to nettle for crypto -- bb51a69 redhat: include username and date in RPM N-E-V-R for scratch builds - -Merged patches (rebase 2.4.0) -- 9201274 spec: Remove obsolete differentiation code -- a938a8c spec: Use external configuration script -- 5ca8d0e spec: Use configure options to prevent default resolution -- 5dca391 spec: Ship complete QMP documentation files -- 7899edd aarch64: allow --enable-seccomp -- a56fb9c aarch64: redhat spec: enable seccomp -- a9571e6 rhel: Update package version for SLOF dependency -- 25c70c4 configure: Add support for tcmalloc -- db72485 Change fsreeze-hook default location -- 14b8a9e redhat: add kvm-unit-tests tarball to environment -- 5ee4238 spec: Build tscdeadline_latency.flat from kvm-unit-tests -- 6ba800b Downstream-only: Start kvm-setup service before libvirtd service -- 59b43d6 Do not stop qemu-guest-agent service on target switch -- 4d851fa provide vhost module config file with max_mem_regions set to 509 -- 0b18027 spec: Require proper version of SLOF -- 3c436c7 Fix rh-brew-aarch64, rh-brew-ppc rh-brew-ga-ppc target - -(cherry picked from commit a4e4a2f66d7a4efc873c5c1cafc502db480ff363) ---- - .gitignore | 1 + - .gitpublish | 8 + - Makefile | 2 +- - block/vxhs.c | 122 +- - configure | 56 +- - hmp-commands-info.hx | 4 + - hmp-commands.hx | 12 + - hmp.c | 12 + - hw/i386/Makefile.objs | 3 +- - include/block/vxhs_shim.h | 143 + - monitor.c | 16 + - os-posix.c | 2 +- - redhat/.gitignore | 5 + - redhat/50-kvm-pgste.conf | 3 + - redhat/80-kvm.rules | 1 + - redhat/85-kvm.preset | 5 + - redhat/95-kvm-memlock.conf | 10 + - redhat/99-qemu-guest-agent.rules | 2 + - redhat/Makefile | 90 + - redhat/Makefile.common | 26 + - redhat/Makefile.local | 76 + - redhat/README.rhel6-gpxe-source | 9 + - redhat/bridge.conf | 1 + - redhat/build_configure.sh | 156 + - redhat/ksm.service | 13 + - redhat/ksm.sysconfig | 4 + - redhat/ksmctl.c | 77 + - redhat/ksmtuned | 138 + - redhat/ksmtuned.conf | 21 + - redhat/ksmtuned.service | 12 + - redhat/kvm-setup | 40 + - redhat/kvm-setup.service | 14 + - redhat/kvm.conf | 12 + - redhat/kvm.modules | 21 + - redhat/qemu-ga.sysconfig | 19 + - redhat/qemu-guest-agent.service | 21 + - redhat/qemu-kvm.spec.template | 6143 ++++++++++++++++++++++++++++++++++++ - redhat/rpmbuild/BUILD/.gitignore | 2 + - redhat/rpmbuild/RPMS/.gitignore | 2 + - redhat/rpmbuild/SOURCES/.gitignore | 2 + - redhat/rpmbuild/SPECS/.gitignore | 2 + - redhat/rpmbuild/SRPMS/.gitignore | 2 + - redhat/scripts/frh.py | 27 + - redhat/scripts/git-backport-diff | 327 ++ - redhat/scripts/git-compile-check | 215 ++ - redhat/scripts/process-patches.sh | 81 + - redhat/scripts/tarball_checksum.sh | 3 + - redhat/vhost.conf | 3 + - ui/vnc.c | 2 +- - 49 files changed, 7923 insertions(+), 45 deletions(-) - create mode 100644 .gitpublish - create mode 100644 include/block/vxhs_shim.h - create mode 100644 redhat/.gitignore - create mode 100644 redhat/50-kvm-pgste.conf - create mode 100644 redhat/80-kvm.rules - create mode 100644 redhat/85-kvm.preset - create mode 100644 redhat/95-kvm-memlock.conf - create mode 100644 redhat/99-qemu-guest-agent.rules - create mode 100644 redhat/Makefile - create mode 100644 redhat/Makefile.common - create mode 100644 redhat/Makefile.local - create mode 100644 redhat/README.rhel6-gpxe-source - create mode 100644 redhat/bridge.conf - create mode 100755 redhat/build_configure.sh - create mode 100644 redhat/ksm.service - create mode 100644 redhat/ksm.sysconfig - create mode 100644 redhat/ksmctl.c - create mode 100644 redhat/ksmtuned - create mode 100644 redhat/ksmtuned.conf - create mode 100644 redhat/ksmtuned.service - create mode 100644 redhat/kvm-setup - create mode 100644 redhat/kvm-setup.service - create mode 100644 redhat/kvm.conf - create mode 100644 redhat/kvm.modules - create mode 100644 redhat/qemu-ga.sysconfig - create mode 100644 redhat/qemu-guest-agent.service - create mode 100644 redhat/qemu-kvm.spec.template - create mode 100644 redhat/rpmbuild/BUILD/.gitignore - create mode 100644 redhat/rpmbuild/RPMS/.gitignore - create mode 100644 redhat/rpmbuild/SOURCES/.gitignore - create mode 100644 redhat/rpmbuild/SPECS/.gitignore - create mode 100644 redhat/rpmbuild/SRPMS/.gitignore - create mode 100755 redhat/scripts/frh.py - create mode 100755 redhat/scripts/git-backport-diff - create mode 100755 redhat/scripts/git-compile-check - create mode 100755 redhat/scripts/process-patches.sh - create mode 100755 redhat/scripts/tarball_checksum.sh - create mode 100644 redhat/vhost.conf - -diff --git a/Makefile b/Makefile -index 81447b1..2cb2442 100644 ---- a/Makefile -+++ b/Makefile -@@ -570,7 +570,7 @@ install-doc: $(DOCS) - $(INSTALL_DATA) docs/interop/qemu-qmp-ref.txt "$(DESTDIR)$(qemu_docdir)" - ifdef CONFIG_POSIX - $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1" -- $(INSTALL_DATA) qemu.1 "$(DESTDIR)$(mandir)/man1" -+ $(INSTALL_DATA) qemu.1 "$(DESTDIR)$(mandir)/man1/qemu-kvm.1" - $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man7" - $(INSTALL_DATA) docs/interop/qemu-qmp-ref.7 "$(DESTDIR)$(mandir)/man7" - ifneq ($(TOOLS),) -diff --git a/block/vxhs.c b/block/vxhs.c -index 75cc6c8..a18154c 100644 ---- a/block/vxhs.c -+++ b/block/vxhs.c -@@ -9,7 +9,8 @@ - */ - - #include "qemu/osdep.h" --#include -+#include "block/vxhs_shim.h" -+#include - #include - #include "block/block_int.h" - #include "qapi/qmp/qerror.h" -@@ -58,6 +59,96 @@ typedef struct BDRVVXHSState { - char *tlscredsid; /* tlscredsid */ - } BDRVVXHSState; - -+#define LIBVXHS_FULL_PATHNAME "/usr/lib64/qemu/libvxhs.so.1" -+static bool libvxhs_loaded; -+static GModule *libvxhs_handle; -+ -+static LibVXHSFuncs libvxhs; -+ -+typedef struct LibVXHSSymbols { -+ const char *name; -+ gpointer *addr; -+} LibVXHSSymbols; -+ -+static LibVXHSSymbols libvxhs_symbols[] = { -+ {"iio_init", (gpointer *) &libvxhs.iio_init}, -+ {"iio_fini", (gpointer *) &libvxhs.iio_fini}, -+ {"iio_min_version", (gpointer *) &libvxhs.iio_min_version}, -+ {"iio_max_version", (gpointer *) &libvxhs.iio_max_version}, -+ {"iio_open", (gpointer *) &libvxhs.iio_open}, -+ {"iio_close", (gpointer *) &libvxhs.iio_close}, -+ {"iio_writev", (gpointer *) &libvxhs.iio_writev}, -+ {"iio_readv", (gpointer *) &libvxhs.iio_readv}, -+ {"iio_ioctl", (gpointer *) &libvxhs.iio_ioctl}, -+ {NULL} -+}; -+ -+static void bdrv_vxhs_set_funcs(GModule *handle, Error **errp) -+{ -+ int i = 0; -+ while (libvxhs_symbols[i].name) { -+ const char *name = libvxhs_symbols[i].name; -+ if (!g_module_symbol(handle, name, libvxhs_symbols[i].addr)) { -+ error_setg(errp, "%s could not be loaded from libvxhs: %s", -+ name, g_module_error()); -+ return; -+ } -+ ++i; -+ } -+} -+ -+static void bdrv_vxhs_load_libs(Error **errp) -+{ -+ Error *local_err = NULL; -+ int32_t ver; -+ -+ if (libvxhs_loaded) { -+ return; -+ } -+ -+ if (!g_module_supported()) { -+ error_setg(errp, "modules are not supported on this platform: %s", -+ g_module_error()); -+ return; -+ } -+ -+ libvxhs_handle = g_module_open(LIBVXHS_FULL_PATHNAME, -+ G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); -+ if (!libvxhs_handle) { -+ error_setg(errp, "error loading libvxhs: %s", g_module_error()); -+ return; -+ } -+ -+ g_module_make_resident(libvxhs_handle); -+ -+ bdrv_vxhs_set_funcs(libvxhs_handle, &local_err); -+ if (local_err) { -+ error_propagate(errp, local_err); -+ return; -+ } -+ -+ /* Now check to see if the libvxhs we are using here is supported -+ * by the loaded version */ -+ -+ ver = (*libvxhs.iio_min_version)(); -+ if (ver > QNIO_VERSION) { -+ error_setg(errp, "Trying to use libvxhs version %"PRId32" API, but " -+ "only %"PRId32" or newer is supported by %s", -+ QNIO_VERSION, ver, LIBVXHS_FULL_PATHNAME); -+ return; -+ } -+ -+ ver = (*libvxhs.iio_max_version)(); -+ if (ver < QNIO_VERSION) { -+ error_setg(errp, "Trying to use libvxhs version %"PRId32" API, but " -+ "only %"PRId32" or earlier is supported by %s", -+ QNIO_VERSION, ver, LIBVXHS_FULL_PATHNAME); -+ return; -+ } -+ -+ libvxhs_loaded = true; -+} -+ - static void vxhs_complete_aio_bh(void *opaque) - { - VXHSAIOCB *acb = opaque; -@@ -219,7 +310,7 @@ static void vxhs_parse_filename(const char *filename, QDict *options, - static int vxhs_init_and_ref(void) - { - if (vxhs_ref++ == 0) { -- if (iio_init(QNIO_VERSION, vxhs_iio_callback)) { -+ if ((*libvxhs.iio_init)(QNIO_VERSION, vxhs_iio_callback)) { - return -ENODEV; - } - } -@@ -229,7 +320,7 @@ static int vxhs_init_and_ref(void) - static void vxhs_unref(void) - { - if (--vxhs_ref == 0) { -- iio_fini(); -+ (*libvxhs.iio_fini)(); - } - } - -@@ -299,8 +390,17 @@ static int vxhs_open(BlockDriverState *bs, QDict *options, - char *client_key = NULL; - char *client_cert = NULL; - -+ bdrv_vxhs_load_libs(&local_err); -+ if (local_err) { -+ error_propagate(errp, local_err); -+ /* on error, cannot cleanup because the iio_fini() function -+ * is not loaded */ -+ return -EINVAL; -+ } -+ - ret = vxhs_init_and_ref(); - if (ret < 0) { -+ error_setg(&local_err, "libvxhs iio_init() failed"); - ret = -EINVAL; - goto out; - } -@@ -385,8 +485,8 @@ static int vxhs_open(BlockDriverState *bs, QDict *options, - /* - * Open qnio channel to storage agent if not opened before - */ -- dev_handlep = iio_open(of_vsa_addr, s->vdisk_guid, 0, -- cacert, client_key, client_cert); -+ dev_handlep = (*libvxhs.iio_open)(of_vsa_addr, s->vdisk_guid, 0, -+ cacert, client_key, client_cert); - if (dev_handlep == NULL) { - trace_vxhs_open_iio_open(of_vsa_addr); - ret = -ENODEV; -@@ -450,12 +550,12 @@ static BlockAIOCB *vxhs_aio_rw(BlockDriverState *bs, int64_t sector_num, - - switch (iodir) { - case VDISK_AIO_WRITE: -- ret = iio_writev(dev_handle, acb, qiov->iov, qiov->niov, -- offset, (uint64_t)size, iio_flags); -+ ret = (*libvxhs.iio_writev)(dev_handle, acb, qiov->iov, qiov->niov, -+ offset, (uint64_t)size, iio_flags); - break; - case VDISK_AIO_READ: -- ret = iio_readv(dev_handle, acb, qiov->iov, qiov->niov, -- offset, (uint64_t)size, iio_flags); -+ ret = (*libvxhs.iio_readv)(dev_handle, acb, qiov->iov, qiov->niov, -+ offset, (uint64_t)size, iio_flags); - break; - default: - trace_vxhs_aio_rw_invalid(iodir); -@@ -505,7 +605,7 @@ static void vxhs_close(BlockDriverState *bs) - * Close vDisk device - */ - if (s->vdisk_hostinfo.dev_handle) { -- iio_close(s->vdisk_hostinfo.dev_handle); -+ (*libvxhs.iio_close)(s->vdisk_hostinfo.dev_handle); - s->vdisk_hostinfo.dev_handle = NULL; - } - -@@ -527,7 +627,7 @@ static int64_t vxhs_get_vdisk_stat(BDRVVXHSState *s) - int ret = 0; - void *dev_handle = s->vdisk_hostinfo.dev_handle; - -- ret = iio_ioctl(dev_handle, IOR_VDISK_STAT, &vdisk_size, 0); -+ ret = (*libvxhs.iio_ioctl)(dev_handle, IOR_VDISK_STAT, &vdisk_size, 0); - if (ret < 0) { - trace_vxhs_get_vdisk_stat_err(s->vdisk_guid, ret, errno); - return -EIO; -diff --git a/configure b/configure -index dd73cce..355c364 100755 ---- a/configure -+++ b/configure -@@ -400,11 +400,13 @@ virglrenderer="" - tpm="yes" - libssh2="" - live_block_migration="yes" -+live_block_ops="yes" - numa="" - tcmalloc="no" - jemalloc="no" - replication="yes" - vxhs="" -+vtd="yes" - - supported_cpu="no" - supported_os="no" -@@ -1279,6 +1281,10 @@ for opt do - ;; - --enable-replication) replication="yes" - ;; -+ --disable-live-block-ops) live_block_ops="no" -+ ;; -+ --enable-live-block-ops) live_block_ops="yes" -+ ;; - --disable-vxhs) vxhs="no" - ;; - --enable-vxhs) vxhs="yes" -@@ -1291,6 +1297,10 @@ for opt do - error_exit "vhost-user isn't available on win32" - fi - ;; -+ --disable-vtd) vtd="no" -+ ;; -+ --enable-vtd) vtd="yes" -+ ;; - *) - echo "ERROR: unknown option $opt" - echo "Try '$0 --help' for more information" -@@ -1523,6 +1533,8 @@ disabled with --disable-FEATURE, default is enabled if available: - glusterfs GlusterFS backend - tpm TPM support - libssh2 ssh block device support -+ live-block-migration live block migration support -+ live-block-ops live block operations support - numa libnuma support - tcmalloc tcmalloc support - jemalloc jemalloc support -@@ -1534,6 +1546,7 @@ disabled with --disable-FEATURE, default is enabled if available: - qom-cast-debug cast debugging support - tools build qemu-io, qemu-nbd and qemu-image tools - vxhs Veritas HyperScale vDisk backend support -+ vtd Emulated VT-d support (only affects x86 targets) - crypto-afalg Linux AF_ALG crypto backend driver - vhost-user vhost-user support - -@@ -3217,7 +3230,7 @@ else - glib_req_ver=2.22 - fi - glib_modules=gthread-2.0 --if test "$modules" = yes; then -+if test "$modules" = yes -o "$vxhs" = yes; then - glib_modules="$glib_modules gmodule-2.0" - fi - -@@ -4940,33 +4953,6 @@ if compile_prog "" "" ; then - fi - - ########################################## --# Veritas HyperScale block driver VxHS --# Check if libvxhs is installed -- --if test "$vxhs" != "no" ; then -- cat > $TMPC < --#include -- --void *vxhs_callback; -- --int main(void) { -- iio_init(QNIO_VERSION, vxhs_callback); -- return 0; --} --EOF -- vxhs_libs="-lvxhs -lssl" -- if compile_prog "" "$vxhs_libs" ; then -- vxhs=yes -- else -- if test "$vxhs" = "yes" ; then -- feature_not_found "vxhs block device" "Install libvxhs See github" -- fi -- vxhs=no -- fi --fi -- --########################################## - # check for _Static_assert() - - have_static_assert=no -@@ -5398,6 +5384,7 @@ echo "libssh2 support $libssh2" - echo "TPM passthrough $tpm_passthrough" - echo "QOM debugging $qom_cast_debug" - echo "Live block migration $live_block_migration" -+echo "Live block ops $live_block_ops" - echo "lzo support $lzo" - echo "snappy support $snappy" - echo "bzip2 support $bzip2" -@@ -5407,6 +5394,7 @@ echo "jemalloc support $jemalloc" - echo "avx2 optimization $avx2_opt" - echo "replication support $replication" - echo "VxHS block device $vxhs" -+echo "VT-d emulation $vtd" - - if test "$sdl_too_old" = "yes"; then - echo "-> Your SDL version is too old - please upgrade to have SDL support" -@@ -5976,6 +5964,10 @@ if test "$live_block_migration" = "yes" ; then - echo "CONFIG_LIVE_BLOCK_MIGRATION=y" >> $config_host_mak - fi - -+if test "$live_block_ops" = "yes" ; then -+ echo "CONFIG_LIVE_BLOCK_OPS=y" >> $config_host_mak -+fi -+ - # USB host support - if test "$libusb" = "yes"; then - echo "HOST_USB=libusb legacy" >> $config_host_mak -@@ -6071,8 +6063,12 @@ if test "$pthread_setname_np" = "yes" ; then - fi - - if test "$vxhs" = "yes" ; then -- echo "CONFIG_VXHS=y" >> $config_host_mak -- echo "VXHS_LIBS=$vxhs_libs" >> $config_host_mak -+ echo "CONFIG_VXHS=m" >> $config_host_mak -+ echo "VXHS_LIBS= -lssl" >> $config_host_mak -+fi -+ -+if test "$vtd" = "yes" ; then -+ echo "CONFIG_VTD=y" >> $config_host_mak - fi - - if test "$tcg_interpreter" = "yes"; then -diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx -index d9df238..0967e41 100644 ---- a/hmp-commands-info.hx -+++ b/hmp-commands-info.hx -@@ -84,6 +84,8 @@ STEXI - Show block device statistics. - ETEXI - -+#ifdef CONFIG_LIVE_BLOCK_OPS -+ - { - .name = "block-jobs", - .args_type = "", -@@ -98,6 +100,8 @@ STEXI - Show progress of ongoing block device operations. - ETEXI - -+#endif /* CONFIG_LIVE_BLOCK_OPS */ -+ - { - .name = "registers", - .args_type = "cpustate_all:-a", -diff --git a/hmp-commands.hx b/hmp-commands.hx -index 1941e19..2d137a1 100644 ---- a/hmp-commands.hx -+++ b/hmp-commands.hx -@@ -73,6 +73,8 @@ but should be used with extreme caution. Note that this command only - resizes image files, it can not resize block devices like LVM volumes. - ETEXI - -+#ifdef CONFIG_LIVE_BLOCK_OPS -+ - { - .name = "block_stream", - .args_type = "device:B,speed:o?,base:s?", -@@ -159,6 +161,8 @@ STEXI - Resume a paused block streaming operation. - ETEXI - -+#endif /* CONFIG_LIVE_BLOCK_OPS */ -+ - { - .name = "eject", - .args_type = "force:-f,device:B", -@@ -1169,6 +1173,8 @@ STEXI - Enables or disables migration mode. - ETEXI - -+#ifdef CONFIG_LIVE_BLOCK_OPS -+ - { - .name = "snapshot_blkdev", - .args_type = "reuse:-n,device:B,snapshot-file:s?,format:s?", -@@ -1190,6 +1196,8 @@ STEXI - Snapshot device, using snapshot file as target if provided - ETEXI - -+#endif /* CONFIG_LIVE_BLOCK_OPS */ -+ - { - .name = "snapshot_blkdev_internal", - .args_type = "device:B,name:s", -@@ -1224,6 +1232,8 @@ STEXI - Delete an internal snapshot on device if it support - ETEXI - -+#ifdef CONFIG_LIVE_BLOCK_OPS -+ - { - .name = "drive_mirror", - .args_type = "reuse:-n,full:-f,device:B,target:s,format:s?", -@@ -1267,6 +1277,8 @@ STEXI - Start a point-in-time copy of a block device to a specificed target. - ETEXI - -+#endif /* CONFIG_LIVE_BLOCK_OPS */ -+ - { - .name = "drive_add", - .args_type = "node:-n,pci_addr:s,opts:s", -diff --git a/hmp.c b/hmp.c -index fd80dce..ab985c6 100644 ---- a/hmp.c -+++ b/hmp.c -@@ -951,6 +951,8 @@ void hmp_info_pci(Monitor *mon, const QDict *qdict) - qapi_free_PciInfoList(info_list); - } - -+#ifdef CONFIG_LIVE_BLOCK_OPS -+ - void hmp_info_block_jobs(Monitor *mon, const QDict *qdict) - { - BlockJobInfoList *list; -@@ -989,6 +991,8 @@ void hmp_info_block_jobs(Monitor *mon, const QDict *qdict) - qapi_free_BlockJobInfoList(list); - } - -+#endif /* CONFIG_LIVE_BLOCK_OPS */ -+ - void hmp_info_tpm(Monitor *mon, const QDict *qdict) - { - TPMInfoList *info_list, *info; -@@ -1197,6 +1201,8 @@ void hmp_block_resize(Monitor *mon, const QDict *qdict) - hmp_handle_error(mon, &err); - } - -+#ifdef CONFIG_LIVE_BLOCK_OPS -+ - void hmp_drive_mirror(Monitor *mon, const QDict *qdict) - { - const char *filename = qdict_get_str(qdict, "target"); -@@ -1280,6 +1286,8 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict) - hmp_handle_error(mon, &err); - } - -+#endif /* CONFIG_LIVE_BLOCK_OPS */ -+ - void hmp_snapshot_blkdev_internal(Monitor *mon, const QDict *qdict) - { - const char *device = qdict_get_str(qdict, "device"); -@@ -1776,6 +1784,8 @@ void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict) - hmp_handle_error(mon, &err); - } - -+#ifdef CONFIG_LIVE_BLOCK_OPS -+ - void hmp_block_stream(Monitor *mon, const QDict *qdict) - { - Error *error = NULL; -@@ -1842,6 +1852,8 @@ void hmp_block_job_complete(Monitor *mon, const QDict *qdict) - hmp_handle_error(mon, &error); - } - -+#endif /* CONFIG_LIVE_BLOCK_OPS */ -+ - typedef struct HMPMigrationStatus - { - QEMUTimer *timer; -diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs -index 909ead6..c14559b 100644 ---- a/hw/i386/Makefile.objs -+++ b/hw/i386/Makefile.objs -@@ -2,7 +2,8 @@ obj-$(CONFIG_KVM) += kvm/ - obj-y += multiboot.o - obj-y += pc.o pc_piix.o pc_q35.o - obj-y += pc_sysfw.o --obj-y += x86-iommu.o intel_iommu.o -+obj-y += x86-iommu.o -+obj-$(CONFIG_VTD) += intel_iommu.o - obj-y += amd_iommu.o - obj-$(CONFIG_XEN) += ../xenpv/ xen/ - -diff --git a/include/block/vxhs_shim.h b/include/block/vxhs_shim.h -new file mode 100644 -index 0000000..42519ae ---- /dev/null -+++ b/include/block/vxhs_shim.h -@@ -0,0 +1,143 @@ -+/* -+ * Network IO library for VxHS QEMU block driver (Veritas Technologies) -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2. See -+ * the COPYING file in the top-level directory. -+ * -+ * Contributions after 2014-08-15 are licensed under the terms of the -+ * GNU GPL, version 2 or (at your option) any later version. -+ */ -+ -+#ifndef QNIO_API_H -+#define QNIO_API_H -+ -+#include -+ -+/* -+ * Bump up the version everytime this file is modified -+ */ -+#define QNIO_VERSION 34 -+ -+/* -+ * These are the opcodes referenced by callback routine. -+ */ -+#define IRP_READ_REQUEST 0x1FFF -+#define IRP_WRITE_REQUEST 0x2FFF -+#define IRP_VDISK_CHECK_IO_FAILOVER_READY 2020 -+ -+/* -+ * opcodes for iio_ioctl. -+ */ -+#define IOR_VDISK_STAT 1005 -+ -+/* -+ * Error values for iio_cb_t callback function. -+ */ -+#define QNIOERROR_HUP 901 /* Retriable error */ -+#define QNIOERROR_NOCONN 902 /* Non-retriable error */ -+ -+ -+/* Operation Flags */ -+#define IIO_FLAG_ASYNC 0x0001 /* Do an async send */ -+ -+/* -+ * INPUT: -+ * ctx - opaque context -+ * opcode - Operation -+ * error - 0 for sucess, non-zero for failure. -+ * RETURNS: -+ * void -+ * DESCRIPTION: -+ * This callback is called, after Async request completes. -+ * -+ * CONTEXT: -+ * The callback should be wait-free. -+ */ -+typedef void (*iio_cb_t) (void *ctx, uint32_t opcode, uint32_t error); -+ -+typedef struct LibVXHSFuncs { -+/* -+ * RETURNS: -+ * 0 for sucess, non-zero for failure. -+ * DESCRIPTION: -+ * Intilize the library state. This should be called at the -+ * begining before issuing any library call. -+ */ -+ int (*iio_init)(int32_t version, iio_cb_t cb); -+/* -+ * RETURNS: -+ * void -+ * DESCRIPTION: -+ * Relinquish library resources. This should be called on the -+ * close of last open device. -+ */ -+ void (*iio_fini)(void); -+/* -+ * DESCRIPTION: -+ * Returns minimum QNIO API version supported by library. -+ */ -+ int32_t (*iio_min_version)(void); -+/* -+ * DESCRIPTION: -+ * Returns maximum QNIO API version supported by library. -+ */ -+ int32_t (*iio_max_version)(void); -+/* -+ * INPUT: -+ * uri - const string of the format of://:port -+ * devid - Device ID. -+ * flags - currently unused, this must be set to 0 -+ * cacert - CA certificates file in PEM format -+ * client_key - Client private key file in PEM format -+ * client_cert - Client certificate file in PEM format -+ * RETURNS: -+ * opeque device handle on success, NULL on failure. -+ * DESCRIPTION: -+ * This call returns device handle on success. Returns NULL on -+ * failure with errno set -+ * errno can be one of: -+ * ENODEV - remote device not found -+ * EBADF - Unable to open communication channel. -+ * EBUSY - The call cannot be completed right now -+ */ -+ void *(*iio_open)(const char *uri, const char *devid, uint32_t flags, -+ const char *cacert, const char *client_key, -+ const char *client_cert); -+/* -+ * Close the device. -+ * For every matching iio_open() there should be a matching iio_close() -+ * The last close free all data structures associated with the device. -+ */ -+ int32_t (*iio_close)(void *dev_handle); -+/* -+ * INPUT: -+ * dev_handle - device descriptor on which read/write needs to be performed -+ * ctx - an opaque context that is not interpreted This is set for -+ * async calls only. It can be NULL. -+ * iov - an array of iovecs (This is a scatter gather operation) -+ * iovcnt - the number of iovecs -+ * offset - an offset to perform the write -+ * size - I/O size -+ * flags - can be one of -+ * IIO_FLAG_ASYNC - indicating this is a aio call. -+ * RETURNS: -+ * -1 on error, sets errno -+ * EBADF - the remote fd is bad -+ * EBUSY - The call cannot be completed right now -+ * EPIPE - the channel got disconnected, call back would be called in -+ * addition to this. -+ */ -+ int32_t (*iio_writev)(void *dev_handle, void *ctx, struct iovec *iov, -+ int iovcnt, uint64_t offset, uint64_t size, -+ uint32_t flags); -+ -+ int32_t (*iio_readv)(void *dev_handle, void *ctx, struct iovec *iov, -+ int iovcnt, uint64_t offset, uint64_t size, -+ uint32_t flags); -+ -+ int32_t (*iio_ioctl)(void *dev_handle, uint32_t opcode, void *opaque, -+ uint32_t flags); -+ -+} LibVXHSFuncs; -+ -+#endif -diff --git a/monitor.c b/monitor.c -index e0f8801..de0a70e 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -998,6 +998,22 @@ static void qmp_unregister_commands_hack(void) - && !defined(TARGET_S390X) - qmp_unregister_command(&qmp_commands, "query-cpu-definitions"); - #endif -+#ifndef CONFIG_LIVE_BLOCK_OPS -+ qmp_unregister_command(&qmp_commands, "block-stream"); -+ qmp_unregister_command(&qmp_commands, "block-commit"); -+ qmp_unregister_command(&qmp_commands, "drive-mirror"); -+ qmp_unregister_command(&qmp_commands, "blockdev-mirror"); -+ qmp_unregister_command(&qmp_commands, "drive-backup"); -+ qmp_unregister_command(&qmp_commands, "blockdev-backup"); -+ qmp_unregister_command(&qmp_commands, "blockdev-snapshot"); -+ qmp_unregister_command(&qmp_commands, "blockdev-snapshot-sync"); -+ qmp_unregister_command(&qmp_commands, "block-job-set-speed"); -+ qmp_unregister_command(&qmp_commands, "block-job-cancel"); -+ qmp_unregister_command(&qmp_commands, "block-job-pause"); -+ qmp_unregister_command(&qmp_commands, "block-job-resume"); -+ qmp_unregister_command(&qmp_commands, "block-job-complete"); -+ qmp_unregister_command(&qmp_commands, "query-block-jobs"); -+#endif - } - - void monitor_init_qmp_commands(void) -diff --git a/os-posix.c b/os-posix.c -index 92e9d85..9625679 100644 ---- a/os-posix.c -+++ b/os-posix.c -@@ -76,7 +76,7 @@ void os_setup_signal_handling(void) - /* Find a likely location for support files using the location of the binary. - For installed binaries this will be "$bindir/../share/qemu". When - running from the build tree this will be "$bindir/../pc-bios". */ --#define SHARE_SUFFIX "/share/qemu" -+#define SHARE_SUFFIX "/share/qemu-kvm" - #define BUILD_SUFFIX "/pc-bios" - char *os_find_datadir(void) - { -diff --git a/ui/vnc.c b/ui/vnc.c -index 651cbb8..5b1e264 100644 ---- a/ui/vnc.c -+++ b/ui/vnc.c -@@ -3945,7 +3945,7 @@ void vnc_display_open(const char *id, Error **errp) - } - - #ifdef CONFIG_VNC_SASL -- if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) { -+ if ((saslErr = sasl_server_init(NULL, "qemu-kvm")) != SASL_OK) { - error_setg(errp, "Failed to initialize SASL auth: %s", - sasl_errstring(saslErr, NULL, NULL)); - goto fail; --- -1.8.3.1 - diff --git a/SOURCES/0003-Add-RHEL-7-machine-types.patch b/SOURCES/0003-Add-RHEL-7-machine-types.patch deleted file mode 100644 index b15c41d..0000000 --- a/SOURCES/0003-Add-RHEL-7-machine-types.patch +++ /dev/null @@ -1,3026 +0,0 @@ -From 44f7e7595c416686a00015e317e74183037a8136 Mon Sep 17 00:00:00 2001 -From: Miroslav Rezanina -Date: Sun, 14 Dec 2014 18:32:18 +0100 -Subject: Add RHEL 7 machine types - -This commit adds all changes related to machine types applied in -qemu-kvm-rhev-2.1.2-16.el7. - -Signed-off-by: Miroslav Rezanina - -Conflicts (on 2.3 rebase): - default-configs/ppc64-softmmu.mak - hw/arm/Makefile.objs - hw/i386/pc_piix.c - hw/i386/pc_q35.c - hw/ppc/spapr.c - savevm.c - has to change shadow_bios tail to rcu list handling - target-i386/machine.c - use xmm instead of ymmh register - --- -Rebase notes (2.10.0): -- Commented out new unused functions in hw/arm/virt.c -- savevm_skip_section_footers changed to COMPAT variable (upstream) -- global_state_set_optional changed to COMPAT variable (upstream) -- savevm_skip_configuration changed to COMPAT variable (upstream) -- move shadow_bios() to separate module with stub version available -- set possible_cpu_arch_ids and cpu_index_to_instance_props fields for arm machine type -- Re-enable older machine types for ppc64 -- Commented 7.2 rebase error for compat qemu-extended-regs - -Rebase notes (2.9.0): -- new header file for arm (upstream) -- query_hotpluggable_cpus renamed to has_hotpluggable_cpus (upstream) -- replace MAX_CPUMASK_BITS with max_cpus -- Adding rhel6-e1000.rom moved to Initial redhat commit -- Fixed conflict on cirrus_vga.c - -Rebase notes (2.8.0): -- new "m->max_cpus = 288" in pc_q35_machine_options hw/i386/pc_q35.c - -Rebase notes (2.7.0): -- Additional fsl-imx6.o sabrelito.o files in arm hw dir - -Rebase notes (2.6.0): -- Changes in handling of some compat properties -- Fixes in x86_64 copmat models -- Added required devices for aarch64 -- Fixes for ppc machine types - -Rebase notes (2.5.0): -- changed cpu defaults structure -- chnaged cpu compat properties handling -- added fix for arm machine type - -Rebase notes (2.4.0) -- Moved needed attribute (due to 5cd8cadae8db905afcbf877cae568c27d1d55a8a) -- Fixes to machine types changes - -Merged patches (2.10.0) -- 5090ba1 Fix qemu-kvm does not quit when booting guest w/ 241 vcpus and "-no-kvm" -- 3c52050 x86: bump maximum vcpu count of pc-q35-rhel7.4.0 to 288 -- 0ed92ca x86: Work around SMI breakages -- f7b5a7f spapr: update SPAPR_COMPAT_RHEL7_3 -- 04faf4d migration: update HW_COMPAT_RHEL7_3 -- 9982768 x86: bump maximum vcpu count of pc-q35-rhel7.4.0 to 384 -- f5095ba re-enable DMA for 7.3 machine type -- d6ec65d x86 machine compat: 2.9 stragglers -- eda659a disable linuxboot_dma.bin option rom for 7.3 machine types -- 8c122a5 Revert "hw/pci: disable pci-bridge's shpc by default" (partial) -- 627adfa virtio_net: Bypass backends for MTU feature negotiation (partial) -- b430787 pc: Use "min[x]level" on compat_props on RHEL machine-types -- 8c3f45a AArch64: remove mach-virt-7.3 machine type -- d5df1ef Downstream: Update pseries machine types for RHEL-ALT-7.4 - -Merged patches (2.9.0) -- 8475d69 hw/arm/virt: Disable virtio-net-pci option ROM file loading -- 73fe1f6 Workaround rhel6 ctrl_guest_offloads machine type mismatch -- 21d32ca pc_piix: fix compat props typo for RHEL6 machine types -- 55a5002 compat: define HW_COMPAT_RHEL7_3 -- 1b8e927 spapr: define pseries-rhel7.4.0 machine type -- cdb76ec hw/arm/virt: remove aarch64 rhel machine type -- 7dfa88b hw/arm/virt: create virt-rhel7.3.0 machine type -- 6894f91 hw/arm/virt: create virt-rhel7.4.0 machine type -- a9d2d39 x86: Split out options for the head rhel7 machine types -- fdafbdc x86: Create PC_RHEL7_3_COMPAT definition -- 3427c72 x86: Define pc-i440fx-rhel7.4.0 -- aea20ab x86: Define pc-q35-rhel7.4.0 -- 0185c0f x86: Remove downstream opteron rdtscp override -- 6b51073 fix abort in acpi_setup() since 2.8 with rhel6 machine types -- 954fc0d intel-hda: fix rhel6 compat property -- 1b57274 kvmclock: reduce kvmclock difference on migration (rhel only part) - -Merged patches (2.8.0) -- a1da2f0 virtio-pci: reduce modern_mem_bar size (rhel only part) - -Merged patches (2.7.0): -- fe9d1cf pc: Use right HW_COMPAT_* macros at PC_RHEL7* compat macros -- 3938189 compat: Add missing "any_layout" in HW_COMPAT_RHEL7_1 -- 6dffc9d spapr: update RHEL-7.2 machine type -- c5d5910 migration: fix HW_COMPAT_RHEL7_2 -- 2da9bb8 pc: New (default) pc-i440fx-rhel7.3.0 machine-type -- 0520d7e 7.3 mismerge fix: Fix ich9-intel-hda compatibility -- 89528b3 PC migration compat: Section footers/global state -- 2231e35 fw_cfg for 7.2 compatibility -- b8a3ade pc: Create new pc-q35-rhel7.3.0 machine-type -- 340929b q35: Remove 7.0, 7.1, 7.2 machine types -- bb7fc95 machine types: fix pc_machine_*_options chain -- d9fa9aa Fix rhel6 rom file -- dc39363 fix vga type for older machines -- 255a2d1 7.2 machine type compatibility -- 16c3d25 target-i386: Remove SSE4a from qemu64 CPU model (rhel only part) -- 76a1796 target-i386: Remove ABM from qemu64 CPU model (rhel only part) -- a9f8773 pc: Recover PC_RHEL7_1_COMPAT from RHEL-7.2 code -- 7a6ed67 pc: Include missing PC_COMPAT_2_3 entries in PC_RHEL7_2_COMPAT -- 07428f6 Revert "static checker: e1000-82540em got aliased to e1000" -- 446cf1f Revert "e1000: use alias for default model" -- 615096e 7.x compat: e1000-82540em -- 0855905 hw/arm/virt: kill 7.2 machine type -- 18bbea2 usbredir: turn off streams for rhel7.2 & older -- 910cf4a target-i386: Fill high bits of mtrr mask (rhel only part) -- 0e8ab1b target-i386: Enable host-phys-bits on RHEL -- 8c5f8a5 pc: Fix rhel6.3.0 compat_props setting -- 8f869f1 pc: use new CPU hotplug interface since 2.7 machine type (rhel only part) -- d9d646f machine: add properties to compat_props incrementaly (rhel only part) -- acb18fd apic: Use apic_id as apic's migration instance_id (rhel only part) -- c7e37d4 apic: fix broken migration for kvm-apic (rhel only part) -- eca64aee hw/virtio-pci: fix virtio behaviour -- c56b8F6e pc-rhel-7.2: pcie: fix link active status bit migration -- 5522aa3 q35-rhel: allow dynamic sysbus - -Merged patches (2.6.0): -- f915d7f arm: virt: Add an abstract RHEL ARM virt machine type -- deffcc0 arm: virt: Add RHEL 7.3.0 virt machine type -- 04ca07d arm: virt: Consolidate the naming of RHEL virt machine types -- 2856ce2 Define HW_COMPAT_RHEL7_2 -- 1869242 spapr: move pseries-2.5 machine to RHEL disabled machine zone -- cc59ce7 spapr: add RHEL-7.3 machine type -- 98549c5 pc: Fix property names on CPU compat code -- caa47bb Fix ich9-intel-hda compatibility - -Merged patches (2.3.0): -- bb4e53c2 pc: add rhel6.6.0 machine type -- 129a2b3 Downstream-only: Restore "pseries" machine alias - -Merged patches (2.4.0): -- 8e8107c numa: Don't allow memdev= on RHEL-6 machine-types -- 8b220c0 pc_sysfw: prevent pflash and/or mis-sized firmware for rhel6.x.0 machtypes -- 9dba3a5 Add pc-i440fx-rhel7.2.0 machine type -- 1c88ffa Add pc-q35-rhel7.2.0 machine type -- 6f74d0c Downstream-only: Add rhel7.2.0 machine type -- a7d6105 Add flag for pre-2.2 migration compatibility -- 17f9a18 Serial: Migration compatibility pre 2.2/7.2 -- 3799a57 Migration compat for mc146818rtc/irq_reinject_on_ack_count subsection -- 5668cc1 Fix reported machine type -- 2417534 386: drop FDC in pc-q35-rhel7.2.0 if neither it nor fl. drives are anted -- f42eee5 global_state: Make section optional -- 8640f84 migration: Add configuration section -- 48c857b pc: memhotplug: fix incorrectly set reserved-memory-end -- f33f0b6 pc: memhotplug: keep reserved-memory-end broken on rhel71 and earlier machines - -(cherry picked from commit d682dec685d0a342b990068b20dbef5aebc30a23) ---- - default-configs/aarch64-softmmu.mak | 2 + - default-configs/arm-softmmu.mak | 1 - - hw/acpi/piix4.c | 6 +- - hw/arm/Makefile.objs | 19 +- - hw/arm/virt.c | 120 +++++- - hw/char/serial.c | 28 ++ - hw/display/cirrus_vga.c | 4 +- - hw/display/vga-isa.c | 2 +- - hw/i386/Makefile.objs | 1 + - hw/i386/pc.c | 3 +- - hw/i386/pc_piix.c | 772 +++++++++++++++++++++++++++++++++++- - hw/i386/pc_q35.c | 55 ++- - hw/i386/pc_sysfw.c | 16 + - hw/i386/shadow-bios.c | 64 +++ - hw/net/e1000.c | 20 +- - hw/net/ne2000.c | 2 +- - hw/net/pcnet-pci.c | 2 +- - hw/net/rtl8139.c | 2 +- - hw/ppc/Makefile.objs | 2 +- - hw/ppc/spapr.c | 124 ++++++ - hw/smbios/smbios.c | 1 + - hw/timer/i8254_common.c | 2 +- - hw/timer/mc146818rtc.c | 6 + - hw/usb/hcd-uhci.c | 15 +- - hw/usb/hcd-xhci.c | 18 + - hw/usb/hcd-xhci.h | 2 + - hw/virtio/virtio-pci.c | 2 +- - hw/virtio/virtio.c | 22 +- - include/hw/arm/virt.h | 22 + - include/hw/compat.h | 180 +++++++++ - include/hw/i386/pc.h | 442 +++++++++++++++++++++ - include/hw/usb.h | 7 + - include/hw/virtio/virtio.h | 1 + - include/sysemu/sysemu.h | 2 + - migration/migration.c | 2 + - migration/migration.h | 6 + - migration/savevm.c | 9 + - numa.c | 13 + - qdev-monitor.c | 1 - - redhat/qemu-kvm.spec.template | 11 +- - scripts/vmstate-static-checker.py | 1 - - stubs/Makefile.objs | 1 + - stubs/shadow-bios.c | 7 + - target/i386/cpu.c | 51 ++- - target/i386/machine.c | 21 + - 45 files changed, 2030 insertions(+), 60 deletions(-) - create mode 100644 hw/i386/shadow-bios.c - create mode 100644 stubs/shadow-bios.c - -diff --git a/default-configs/aarch64-softmmu.mak b/default-configs/aarch64-softmmu.mak -index 2449483..abd18c2 100644 ---- a/default-configs/aarch64-softmmu.mak -+++ b/default-configs/aarch64-softmmu.mak -@@ -7,3 +7,5 @@ CONFIG_AUX=y - CONFIG_DDC=y - CONFIG_DPCD=y - CONFIG_XLNX_ZYNQMP=y -+CONFIG_PL061=y -+CONFIG_GPIO_KEY=y -diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak -index bbdd3c1..05aaf8f 100644 ---- a/default-configs/arm-softmmu.mak -+++ b/default-configs/arm-softmmu.mak -@@ -76,7 +76,6 @@ CONFIG_ARM11SCU=y - CONFIG_A9SCU=y - CONFIG_DIGIC=y - CONFIG_MARVELL_88W8618=y --CONFIG_OMAP=y - CONFIG_TSC210X=y - CONFIG_BLIZZARD=y - CONFIG_ONENAND=y -diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c -index f276967..efd80d1 100644 ---- a/hw/acpi/piix4.c -+++ b/hw/acpi/piix4.c -@@ -311,7 +311,7 @@ static const VMStateDescription vmstate_cpuhp_state = { - static const VMStateDescription vmstate_acpi = { - .name = "piix4_pm", - .version_id = 3, -- .minimum_version_id = 3, -+ .minimum_version_id = 2, - .minimum_version_id_old = 1, - .load_state_old = acpi_load_old, - .post_load = vmstate_acpi_post_load, -@@ -675,8 +675,8 @@ static void piix4_send_gpe(AcpiDeviceIf *adev, AcpiEventStatusBits ev) - - static Property piix4_pm_properties[] = { - DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0), -- DEFINE_PROP_UINT8(ACPI_PM_PROP_S3_DISABLED, PIIX4PMState, disable_s3, 0), -- DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_DISABLED, PIIX4PMState, disable_s4, 0), -+ DEFINE_PROP_UINT8(ACPI_PM_PROP_S3_DISABLED, PIIX4PMState, disable_s3, 1), -+ DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_DISABLED, PIIX4PMState, disable_s4, 1), - DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_VAL, PIIX4PMState, s4_val, 2), - DEFINE_PROP_BOOL("acpi-pci-hotplug-with-bridge-support", PIIX4PMState, - use_acpi_pci_hotplug, true), -diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs -index a2e56ec..906367c 100644 ---- a/hw/arm/Makefile.objs -+++ b/hw/arm/Makefile.objs -@@ -1,21 +1,4 @@ --obj-y += boot.o collie.o exynos4_boards.o gumstix.o highbank.o --obj-$(CONFIG_DIGIC) += digic_boards.o --obj-y += integratorcp.o mainstone.o musicpal.o nseries.o --obj-y += omap_sx1.o palm.o realview.o spitz.o stellaris.o --obj-y += tosa.o versatilepb.o vexpress.o virt.o xilinx_zynq.o z2.o - obj-$(CONFIG_ACPI) += virt-acpi-build.o --obj-y += netduino2.o - obj-y += sysbus-fdt.o - --obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o --obj-$(CONFIG_DIGIC) += digic.o --obj-y += omap1.o omap2.o strongarm.o --obj-$(CONFIG_ALLWINNER_A10) += allwinner-a10.o cubieboard.o --obj-$(CONFIG_RASPI) += bcm2835_peripherals.o bcm2836.o raspi.o --obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o --obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp.o xlnx-ep108.o --obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o --obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o --obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o sabrelite.o --obj-$(CONFIG_ASPEED_SOC) += aspeed_soc.o aspeed.o --obj-$(CONFIG_MPS2) += mps2.o -+obj-y += boot.o virt.o -diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index 6b7a0fe..b14e16d 100644 ---- a/hw/arm/virt.c -+++ b/hw/arm/virt.c -@@ -57,6 +57,7 @@ - #include "qapi/visitor.h" - #include "standard-headers/linux/input.h" - -+#if 0 /* disabled Red Hat Enterprise Linux */ - #define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \ - static void virt_##major##_##minor##_class_init(ObjectClass *oc, \ - void *data) \ -@@ -84,7 +85,36 @@ - DEFINE_VIRT_MACHINE_LATEST(major, minor, true) - #define DEFINE_VIRT_MACHINE(major, minor) \ - DEFINE_VIRT_MACHINE_LATEST(major, minor, false) -- -+#endif /* disabled for RHEL */ -+ -+#define DEFINE_RHEL_MACHINE_LATEST(m, n, s, latest) \ -+ static void rhel##m##n##s##_virt_class_init(ObjectClass *oc, \ -+ void *data) \ -+ { \ -+ MachineClass *mc = MACHINE_CLASS(oc); \ -+ rhel##m##n##s##_virt_options(mc); \ -+ mc->desc = "RHEL " # m "." # n "." # s " ARM Virtual Machine"; \ -+ if (latest) { \ -+ mc->alias = "virt"; \ -+ mc->is_default = 1; \ -+ } \ -+ } \ -+ static const TypeInfo rhel##m##n##s##_machvirt_info = { \ -+ .name = MACHINE_TYPE_NAME("virt-rhel" # m "." # n "." # s), \ -+ .parent = TYPE_RHEL_MACHINE, \ -+ .instance_init = rhel##m##n##s##_virt_instance_init, \ -+ .class_init = rhel##m##n##s##_virt_class_init, \ -+ }; \ -+ static void rhel##m##n##s##_machvirt_init(void) \ -+ { \ -+ type_register_static(&rhel##m##n##s##_machvirt_info); \ -+ } \ -+ type_init(rhel##m##n##s##_machvirt_init); -+ -+#define DEFINE_RHEL_MACHINE_AS_LATEST(major, minor, subminor) \ -+ DEFINE_RHEL_MACHINE_LATEST(major, minor, subminor, true) -+#define DEFINE_RHEL_MACHINE(major, minor, subminor) \ -+ DEFINE_RHEL_MACHINE_LATEST(major, minor, subminor, false) - - /* Number of external interrupt lines to configure the GIC with */ - #define NUM_IRQS 256 -@@ -1484,6 +1514,7 @@ static void machvirt_init(MachineState *machine) - create_platform_bus(vms, pic); - } - -+#if 0 /* disabled for RHEL */ - static bool virt_get_secure(Object *obj, Error **errp) - { - VirtMachineState *vms = VIRT_MACHINE(obj); -@@ -1512,6 +1543,7 @@ static void virt_set_virt(Object *obj, bool value, Error **errp) - vms->virt = value; - } - -+#endif /* disabled for RHEL */ - static bool virt_get_highmem(Object *obj, Error **errp) - { - VirtMachineState *vms = VIRT_MACHINE(obj); -@@ -1604,6 +1636,7 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) - return ms->possible_cpus; - } - -+#if 0 /* disabled for RHEL */ - static void virt_machine_class_init(ObjectClass *oc, void *data) - { - MachineClass *mc = MACHINE_CLASS(oc); -@@ -1780,3 +1813,88 @@ static void virt_machine_2_6_options(MachineClass *mc) - vmc->no_pmu = true; - } - DEFINE_VIRT_MACHINE(2, 6) -+#endif /* disabled for RHEL */ -+ -+static void rhel_machine_class_init(ObjectClass *oc, void *data) -+{ -+ MachineClass *mc = MACHINE_CLASS(oc); -+ -+ mc->family = "virt-rhel-Z"; -+ mc->init = machvirt_init; -+ /* Start max_cpus at the maximum QEMU supports. We'll further restrict -+ * it later in machvirt_init, where we have more information about the -+ * configuration of the particular instance. -+ */ -+ mc->max_cpus = 255; -+ mc->has_dynamic_sysbus = false; -+ mc->block_default_type = IF_VIRTIO; -+ mc->no_cdrom = 1; -+ mc->pci_allow_0_address = true; -+ /* We know we will never create a pre-ARMv7 CPU which needs 1K pages */ -+ mc->minimum_page_bits = 12; -+ mc->possible_cpu_arch_ids = virt_possible_cpu_arch_ids; -+ mc->cpu_index_to_instance_props = virt_cpu_index_to_props; -+} -+ -+static const TypeInfo rhel_machine_info = { -+ .name = TYPE_RHEL_MACHINE, -+ .parent = TYPE_MACHINE, -+ .abstract = true, -+ .instance_size = sizeof(VirtMachineState), -+ .class_size = sizeof(VirtMachineClass), -+ .class_init = rhel_machine_class_init, -+}; -+ -+static void rhel_machine_init(void) -+{ -+ type_register_static(&rhel_machine_info); -+} -+type_init(rhel_machine_init); -+ -+static void rhel740_virt_instance_init(Object *obj) -+{ -+ VirtMachineState *vms = VIRT_MACHINE(obj); -+ VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); -+ -+ /* EL3 is disabled by default and non-configurable for RHEL */ -+ vms->secure = false; -+ /* EL2 is disabled by default and non-configurable for RHEL */ -+ vms->virt = false; -+ /* High memory is enabled by default for RHEL */ -+ vms->highmem = true; -+ object_property_add_bool(obj, "highmem", virt_get_highmem, -+ virt_set_highmem, NULL); -+ object_property_set_description(obj, "highmem", -+ "Set on/off to enable/disable using " -+ "physical address space above 32 bits", -+ NULL); -+ /* Default GIC type is still v2, but became configurable for RHEL */ -+ vms->gic_version = 2; -+ object_property_add_str(obj, "gic-version", virt_get_gic_version, -+ virt_set_gic_version, NULL); -+ object_property_set_description(obj, "gic-version", -+ "Set GIC version. " -+ "Valid values are 2, 3 and host", NULL); -+ -+ if (vmc->no_its) { -+ vms->its = false; -+ } else { -+ /* Default allows ITS instantiation */ -+ vms->its = true; -+ object_property_add_bool(obj, "its", virt_get_its, -+ virt_set_its, NULL); -+ object_property_set_description(obj, "its", -+ "Set on/off to enable/disable " -+ "ITS instantiation", -+ NULL); -+ } -+ -+ vms->memmap=a15memmap; -+ vms->irqmap=a15irqmap; -+} -+ -+static void rhel740_virt_options(MachineClass *mc) -+{ -+ SET_MACHINE_COMPAT(mc, ARM_RHEL_COMPAT); -+} -+DEFINE_RHEL_MACHINE_AS_LATEST(7, 4, 0) -diff --git a/hw/char/serial.c b/hw/char/serial.c -index 9aec6c6..fe4f41d 100644 ---- a/hw/char/serial.c -+++ b/hw/char/serial.c -@@ -30,6 +30,7 @@ - #include "qemu/timer.h" - #include "exec/address-spaces.h" - #include "qemu/error-report.h" -+#include "migration/migration.h" - - //#define DEBUG_SERIAL - -@@ -689,6 +690,9 @@ static int serial_post_load(void *opaque, int version_id) - static bool serial_thr_ipending_needed(void *opaque) - { - SerialState *s = opaque; -+ if (migrate_pre_2_2) { -+ return false; -+ } - - if (s->ier & UART_IER_THRI) { - bool expected_value = ((s->iir & UART_IIR_ID) == UART_IIR_THRI); -@@ -716,6 +720,10 @@ static const VMStateDescription vmstate_serial_thr_ipending = { - static bool serial_tsr_needed(void *opaque) - { - SerialState *s = (SerialState *)opaque; -+ if (migrate_pre_2_2) { -+ return false; -+ } -+ - return s->tsr_retry != 0; - } - -@@ -735,6 +743,10 @@ static const VMStateDescription vmstate_serial_tsr = { - static bool serial_recv_fifo_needed(void *opaque) - { - SerialState *s = (SerialState *)opaque; -+ if (migrate_pre_2_2) { -+ return false; -+ } -+ - return !fifo8_is_empty(&s->recv_fifo); - - } -@@ -753,6 +765,10 @@ static const VMStateDescription vmstate_serial_recv_fifo = { - static bool serial_xmit_fifo_needed(void *opaque) - { - SerialState *s = (SerialState *)opaque; -+ if (migrate_pre_2_2) { -+ return false; -+ } -+ - return !fifo8_is_empty(&s->xmit_fifo); - } - -@@ -770,6 +786,10 @@ static const VMStateDescription vmstate_serial_xmit_fifo = { - static bool serial_fifo_timeout_timer_needed(void *opaque) - { - SerialState *s = (SerialState *)opaque; -+ if (migrate_pre_2_2) { -+ return false; -+ } -+ - return timer_pending(s->fifo_timeout_timer); - } - -@@ -787,6 +807,10 @@ static const VMStateDescription vmstate_serial_fifo_timeout_timer = { - static bool serial_timeout_ipending_needed(void *opaque) - { - SerialState *s = (SerialState *)opaque; -+ if (migrate_pre_2_2) { -+ return false; -+ } -+ - return s->timeout_ipending != 0; - } - -@@ -804,6 +828,10 @@ static const VMStateDescription vmstate_serial_timeout_ipending = { - static bool serial_poll_needed(void *opaque) - { - SerialState *s = (SerialState *)opaque; -+ if (migrate_pre_2_2) { -+ return false; -+ } -+ - return s->poll_msl >= 0; - } - -diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c -index afc290a..14008aa 100644 ---- a/hw/display/cirrus_vga.c -+++ b/hw/display/cirrus_vga.c -@@ -3063,7 +3063,7 @@ static void isa_cirrus_vga_realizefn(DeviceState *dev, Error **errp) - - static Property isa_cirrus_vga_properties[] = { - DEFINE_PROP_UINT32("vgamem_mb", struct ISACirrusVGAState, -- cirrus_vga.vga.vram_size_mb, 4), -+ cirrus_vga.vga.vram_size_mb, 16), - DEFINE_PROP_BOOL("blitter", struct ISACirrusVGAState, - cirrus_vga.enable_blitter, true), - DEFINE_PROP_END_OF_LIST(), -@@ -3134,7 +3134,7 @@ static void pci_cirrus_vga_realize(PCIDevice *dev, Error **errp) - - static Property pci_vga_cirrus_properties[] = { - DEFINE_PROP_UINT32("vgamem_mb", struct PCICirrusVGAState, -- cirrus_vga.vga.vram_size_mb, 4), -+ cirrus_vga.vga.vram_size_mb, 16), - DEFINE_PROP_BOOL("blitter", struct PCICirrusVGAState, - cirrus_vga.enable_blitter, true), - DEFINE_PROP_END_OF_LIST(), -diff --git a/hw/display/vga-isa.c b/hw/display/vga-isa.c -index 1af9556..91a675d 100644 ---- a/hw/display/vga-isa.c -+++ b/hw/display/vga-isa.c -@@ -80,7 +80,7 @@ static void vga_isa_realizefn(DeviceState *dev, Error **errp) - } - - static Property vga_isa_properties[] = { -- DEFINE_PROP_UINT32("vgamem_mb", ISAVGAState, state.vram_size_mb, 8), -+ DEFINE_PROP_UINT32("vgamem_mb", ISAVGAState, state.vram_size_mb, 16), - DEFINE_PROP_END_OF_LIST(), - }; - -diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs -index c14559b..9b5686b 100644 ---- a/hw/i386/Makefile.objs -+++ b/hw/i386/Makefile.objs -@@ -10,3 +10,4 @@ obj-$(CONFIG_XEN) += ../xenpv/ xen/ - obj-y += kvmvapic.o - obj-y += acpi-build.o - obj-y += pci-assign-load-rom.o -+obj-y += shadow-bios.o -diff --git a/hw/i386/pc.c b/hw/i386/pc.c -index 2108104..64929ea 100644 ---- a/hw/i386/pc.c -+++ b/hw/i386/pc.c -@@ -2353,7 +2353,8 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) - mc->default_boot_order = "cad"; - mc->hot_add_cpu = pc_hot_add_cpu; - mc->block_default_type = IF_IDE; -- mc->max_cpus = 255; -+ /* 240: max CPU count for RHEL */ -+ mc->max_cpus = 240; - mc->reset = pc_machine_reset; - hc->pre_plug = pc_machine_device_pre_plug_cb; - hc->plug = pc_machine_device_plug_cb; -diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c -index 46dfd2c..7f12ce3 100644 ---- a/hw/i386/pc_piix.c -+++ b/hw/i386/pc_piix.c -@@ -48,6 +48,7 @@ - #include "hw/acpi/acpi.h" - #include "cpu.h" - #include "qemu/error-report.h" -+#include "migration/migration.h" - #ifdef CONFIG_XEN - #include - #include "hw/xen/xen_pt.h" -@@ -168,8 +169,8 @@ static void pc_init1(MachineState *machine, - if (pcmc->smbios_defaults) { - MachineClass *mc = MACHINE_GET_CLASS(machine); - /* These values are guest ABI, do not change */ -- smbios_set_defaults("QEMU", "Standard PC (i440FX + PIIX, 1996)", -- mc->name, pcmc->smbios_legacy_mode, -+ smbios_set_defaults("Red Hat", "KVM", -+ mc->desc, pcmc->smbios_legacy_mode, - pcmc->smbios_uuid_encoded, - SMBIOS_ENTRY_POINT_21); - } -@@ -311,6 +312,7 @@ static void pc_init1(MachineState *machine, - * HW_COMPAT_*, PC_COMPAT_*, or * pc_*_machine_options(). - */ - -+#if 0 /* Disabled for Red Hat Enterprise Linux */ - static void pc_compat_2_3(MachineState *machine) - { - PCMachineState *pcms = PC_MACHINE(machine); -@@ -1122,3 +1124,769 @@ static void xenfv_machine_options(MachineClass *m) - DEFINE_PC_MACHINE(xenfv, "xenfv", pc_xen_hvm_init, - xenfv_machine_options); - #endif -+machine_init(pc_machine_init); -+ -+#endif /* Disabled for Red Hat Enterprise Linux */ -+ -+/* Red Hat Enterprise Linux machine types */ -+ -+/* Options for the latest rhel7 machine type */ -+static void pc_machine_rhel7_options(MachineClass *m) -+{ -+ m->family = "pc_piix_Y"; -+ m->default_machine_opts = "firmware=bios-256k.bin"; -+ m->default_display = "std"; -+ SET_MACHINE_COMPAT(m, PC_RHEL_COMPAT); -+ m->alias = "pc"; -+ m->is_default = 1; -+} -+ -+static void pc_init_rhel740(MachineState *machine) -+{ -+ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \ -+ TYPE_I440FX_PCI_DEVICE); -+} -+ -+static void pc_machine_rhel740_options(MachineClass *m) -+{ -+ pc_machine_rhel7_options(m); -+ m->desc = "RHEL 7.4.0 PC (i440FX + PIIX, 1996)"; -+} -+ -+DEFINE_PC_MACHINE(rhel740, "pc-i440fx-rhel7.4.0", pc_init_rhel740, -+ pc_machine_rhel740_options); -+ -+static void pc_init_rhel730(MachineState *machine) -+{ -+ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \ -+ TYPE_I440FX_PCI_DEVICE); -+} -+ -+static void pc_machine_rhel730_options(MachineClass *m) -+{ -+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m); -+ pc_machine_rhel740_options(m); -+ m->alias = NULL; -+ m->is_default = 0; -+ m->desc = "RHEL 7.3.0 PC (i440FX + PIIX, 1996)"; -+ pcmc->linuxboot_dma_enabled = false; -+ SET_MACHINE_COMPAT(m, PC_RHEL7_3_COMPAT); -+} -+ -+DEFINE_PC_MACHINE(rhel730, "pc-i440fx-rhel7.3.0", pc_init_rhel730, -+ pc_machine_rhel730_options); -+ -+ -+static void pc_init_rhel720(MachineState *machine) -+{ -+ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \ -+ TYPE_I440FX_PCI_DEVICE); -+} -+ -+static void pc_machine_rhel720_options(MachineClass *m) -+{ -+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m); -+ pc_machine_rhel730_options(m); -+ m->desc = "RHEL 7.2.0 PC (i440FX + PIIX, 1996)"; -+ /* From pc_i440fx_2_5_machine_options */ -+ pcmc->save_tsc_khz = false; -+ m->legacy_fw_cfg_order = 1; -+ /* Note: broken_reserved_end was already in 7.2 */ -+ /* From pc_i440fx_2_6_machine_options */ -+ pcmc->legacy_cpu_hotplug = true; -+ SET_MACHINE_COMPAT(m, PC_RHEL7_2_COMPAT); -+} -+ -+DEFINE_PC_MACHINE(rhel720, "pc-i440fx-rhel7.2.0", pc_init_rhel720, -+ pc_machine_rhel720_options); -+ -+static void pc_compat_rhel710(MachineState *machine) -+{ -+ PCMachineState *pcms = PC_MACHINE(machine); -+ PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); -+ -+ /* From pc_compat_2_2 */ -+ pcmc->rsdp_in_ram = false; -+ machine->suppress_vmdesc = true; -+ -+ /* From pc_compat_2_1 */ -+ pcmc->smbios_uuid_encoded = false; -+ x86_cpu_change_kvm_default("svm", NULL); -+ pcmc->enforce_aligned_dimm = false; -+ -+ /* Disable all the extra subsections that were added in 2.2 */ -+ migrate_pre_2_2 = true; -+ -+ /* From pc_i440fx_2_4_machine_options */ -+ pcmc->broken_reserved_end = true; -+} -+ -+static void pc_init_rhel710(MachineState *machine) -+{ -+ pc_compat_rhel710(machine); -+ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \ -+ TYPE_I440FX_PCI_DEVICE); -+} -+ -+static void pc_machine_rhel710_options(MachineClass *m) -+{ -+ pc_machine_rhel720_options(m); -+ m->family = "pc_piix_Y"; -+ m->desc = "RHEL 7.1.0 PC (i440FX + PIIX, 1996)"; -+ m->default_display = "cirrus"; -+ SET_MACHINE_COMPAT(m, PC_RHEL7_1_COMPAT); -+} -+ -+DEFINE_PC_MACHINE(rhel710, "pc-i440fx-rhel7.1.0", pc_init_rhel710, -+ pc_machine_rhel710_options); -+ -+static void pc_compat_rhel700(MachineState *machine) -+{ -+ PCMachineState *pcms = PC_MACHINE(machine); -+ PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); -+ -+ pc_compat_rhel710(machine); -+ -+ /* Upstream enables it for everyone, we're a little more selective */ -+ x86_cpu_change_kvm_default("x2apic", NULL); -+ x86_cpu_change_kvm_default("svm", NULL); -+ pcmc->legacy_acpi_table_size = 6418; /* see pc_compat_2_0() */ -+ pcmc->smbios_legacy_mode = true; -+ pcmc->has_reserved_memory = false; -+ migrate_cve_2014_5263_xhci_fields = true; -+} -+ -+static void pc_init_rhel700(MachineState *machine) -+{ -+ pc_compat_rhel700(machine); -+ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \ -+ TYPE_I440FX_PCI_DEVICE); -+} -+ -+static void pc_machine_rhel700_options(MachineClass *m) -+{ -+ pc_machine_rhel710_options(m); -+ m->family = "pc_piix_Y"; -+ m->desc = "RHEL 7.0.0 PC (i440FX + PIIX, 1996)"; -+ SET_MACHINE_COMPAT(m, PC_RHEL7_0_COMPAT); -+} -+ -+DEFINE_PC_MACHINE(rhel700, "pc-i440fx-rhel7.0.0", pc_init_rhel700, -+ pc_machine_rhel700_options); -+ -+#define PC_RHEL6_6_COMPAT \ -+ {\ -+ .driver = "scsi-hd",\ -+ .property = "discard_granularity",\ -+ .value = stringify(0),\ -+ },{\ -+ .driver = "scsi-cd",\ -+ .property = "discard_granularity",\ -+ .value = stringify(0),\ -+ },{\ -+ .driver = "scsi-disk",\ -+ .property = "discard_granularity",\ -+ .value = stringify(0),\ -+ },{\ -+ .driver = "ide-hd",\ -+ .property = "discard_granularity",\ -+ .value = stringify(0),\ -+ },{\ -+ .driver = "ide-cd",\ -+ .property = "discard_granularity",\ -+ .value = stringify(0),\ -+ },{\ -+ .driver = "ide-drive",\ -+ .property = "discard_granularity",\ -+ .value = stringify(0),\ -+ },{\ -+ .driver = "virtio-blk-pci",\ -+ .property = "discard_granularity",\ -+ .value = stringify(0),\ -+ },{\ -+ .driver = "virtio-serial-pci",\ -+ .property = "vectors",\ -+ /* DEV_NVECTORS_UNSPECIFIED as a uint32_t string */\ -+ .value = stringify(0xFFFFFFFF),\ -+ },{\ -+ .driver = "486-" TYPE_X86_CPU,\ -+ .property = "model",\ -+ .value = stringify(0),\ -+ },{\ -+ .driver = "usb-tablet",\ -+ .property = "usb_version",\ -+ .value = stringify(1),\ -+ },{\ -+ .driver = "virtio-net-pci",\ -+ .property = "mq",\ -+ .value = "off",\ -+ },{\ -+ .driver = "VGA",\ -+ .property = "mmio",\ -+ .value = "off",\ -+ },{\ -+ .driver = "virtio-blk-pci",\ -+ .property = "config-wce",\ -+ .value = "off",\ -+ },{\ -+ .driver = TYPE_ISA_FDC,\ -+ .property = "check_media_rate",\ -+ .value = "off",\ -+ },{\ -+ .driver = "virtio-balloon-pci",\ -+ .property = "class",\ -+ .value = stringify(PCI_CLASS_MEMORY_RAM),\ -+ },{\ -+ .driver = TYPE_PCI_DEVICE,\ -+ .property = "command_serr_enable",\ -+ .value = "off",\ -+ },{\ -+ .driver = "AC97",\ -+ .property = "use_broken_id",\ -+ .value = stringify(1),\ -+ },{\ -+ .driver = "intel-hda",\ -+ .property = "msi",\ -+ .value = "off",\ -+ },{\ -+ .driver = "qemu32-" TYPE_X86_CPU,\ -+ .property = "min-xlevel",\ -+ .value = stringify(0),\ -+ },{\ -+ .driver = "486-" TYPE_X86_CPU,\ -+ .property = "min-level",\ -+ .value = stringify(0),\ -+ },{\ -+ .driver = "qemu32-" TYPE_X86_CPU,\ -+ .property = "model",\ -+ .value = stringify(3),\ -+ },{\ -+ .driver = "usb-ccid",\ -+ .property = "serial",\ -+ .value = "1",\ -+ },{\ -+ .driver = "ne2k_pci",\ -+ .property = "romfile",\ -+ .value = "rhel6-ne2k_pci.rom",\ -+ },{\ -+ .driver = "pcnet",\ -+ .property = "romfile",\ -+ .value = "rhel6-pcnet.rom",\ -+ },{\ -+ .driver = "rtl8139",\ -+ .property = "romfile",\ -+ .value = "rhel6-rtl8139.rom",\ -+ },{\ -+ .driver = "e1000",\ -+ .property = "romfile",\ -+ .value = "rhel6-e1000.rom",\ -+ },{\ -+ .driver = "virtio-net-pci",\ -+ .property = "romfile",\ -+ .value = "rhel6-virtio.rom",\ -+ },{\ -+ .driver = "virtio-net-pci",\ -+ .property = "any_layout",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = "pentium" "-" TYPE_X86_CPU,\ -+ .property = "apic",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = "pentium2" "-" TYPE_X86_CPU,\ -+ .property = "apic",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = "pentium3" "-" TYPE_X86_CPU,\ -+ .property = "apic",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = "Conroe" "-" TYPE_X86_CPU,\ -+ .property = "x2apic",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "Penryn" "-" TYPE_X86_CPU,\ -+ .property = "x2apic",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "Nehalem" "-" TYPE_X86_CPU,\ -+ .property = "x2apic",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "Westmere" "-" TYPE_X86_CPU,\ -+ .property = "x2apic",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "Westmere" "-" TYPE_X86_CPU,\ -+ .property = "pclmulqdq",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = "Westmere" "-" TYPE_X86_CPU,\ -+ .property = "fxsr",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "Westmere" "-" TYPE_X86_CPU,\ -+ .property = "mmx",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "Westmere" "-" TYPE_X86_CPU,\ -+ .property = "pat",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "Westmere" "-" TYPE_X86_CPU,\ -+ .property = "cmov",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "Westmere" "-" TYPE_X86_CPU,\ -+ .property = "pge",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "Westmere" "-" TYPE_X86_CPU,\ -+ .property = "apic",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "Westmere" "-" TYPE_X86_CPU,\ -+ .property = "cx8",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "Westmere" "-" TYPE_X86_CPU,\ -+ .property = "mce",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "Westmere" "-" TYPE_X86_CPU,\ -+ .property = "pae",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "Westmere" "-" TYPE_X86_CPU,\ -+ .property = "msr",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "Westmere" "-" TYPE_X86_CPU,\ -+ .property = "tsc",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "Westmere" "-" TYPE_X86_CPU,\ -+ .property = "pse",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "Westmere" "-" TYPE_X86_CPU,\ -+ .property = "de",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "Westmere" "-" TYPE_X86_CPU,\ -+ .property = "fpu",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "Broadwell" "-" TYPE_X86_CPU,\ -+ .property = "rdtscp",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = "Broadwell" "-" TYPE_X86_CPU,\ -+ .property = "smap",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = TYPE_X86_CPU,\ -+ .property = "rdtscp",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = "Opteron_G1" "-" TYPE_X86_CPU,\ -+ .property = "x2apic",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "Opteron_G2" "-" TYPE_X86_CPU,\ -+ .property = "x2apic",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "Opteron_G3" "-" TYPE_X86_CPU,\ -+ .property = "x2apic",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "Opteron_G4" "-" TYPE_X86_CPU,\ -+ .property = "x2apic",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = "Opteron_G5" "-" TYPE_X86_CPU,\ -+ .property = "x2apic",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = TYPE_X86_CPU,\ -+ .property = "3dnow",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = TYPE_X86_CPU,\ -+ .property = "3dnowext",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = "virtio-net-pci",\ -+ .property = "__com.redhat_rhel6_ctrl_guest_workaround", \ -+ .value = "on",\ -+ }, -+ -+static void pc_compat_rhel660(MachineState *machine) -+{ -+ PCMachineState *pcms = PC_MACHINE(machine); -+ PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); -+ -+ pc_compat_rhel700(machine); -+ if (!machine->cpu_model) { -+ machine->cpu_model = "cpu64-rhel6"; -+ } -+ -+ x86_cpu_change_kvm_default("kvm-pv-unhalt", NULL); -+ -+ pcmc->gigabyte_align = false; -+ shadow_bios_after_incoming = true; -+ ich9_uhci123_irqpin_override = true; -+} -+ -+static void pc_init_rhel660(MachineState *machine) -+{ -+ pc_compat_rhel660(machine); -+ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \ -+ TYPE_I440FX_PCI_DEVICE);} -+ -+static void pc_machine_rhel660_options(MachineClass *m) -+{ -+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m); -+ pc_machine_rhel700_options(m); -+ m->family = "pc_piix_Z"; -+ m->desc = "RHEL 6.6.0 PC"; -+ m->rom_file_has_mr = false; -+ m->default_machine_opts = "firmware=bios.bin"; -+ pcmc->has_acpi_build = false; -+ SET_MACHINE_COMPAT(m, PC_RHEL6_6_COMPAT); -+} -+ -+DEFINE_PC_MACHINE(rhel660, "rhel6.6.0", pc_init_rhel660, -+ pc_machine_rhel660_options); -+ -+#define PC_RHEL6_5_COMPAT \ -+ {\ -+ .driver = TYPE_USB_DEVICE,\ -+ .property = "msos-desc",\ -+ .value = "no",\ -+ }, -+ -+static void pc_compat_rhel650(MachineState *machine) -+{ -+ pc_compat_rhel660(machine); -+} -+ -+static void pc_init_rhel650(MachineState *machine) -+{ -+ pc_compat_rhel650(machine); -+ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \ -+ TYPE_I440FX_PCI_DEVICE);} -+ -+static void pc_machine_rhel650_options(MachineClass *m) -+{ -+ pc_machine_rhel660_options(m); -+ m->family = "pc_piix_Z"; -+ m->desc = "RHEL 6.5.0 PC"; -+ SET_MACHINE_COMPAT(m, PC_RHEL6_5_COMPAT); -+} -+ -+DEFINE_PC_MACHINE(rhel650, "rhel6.5.0", pc_init_rhel650, -+ pc_machine_rhel650_options); -+ -+#define PC_RHEL6_4_COMPAT \ -+ {\ -+ .driver = "virtio-scsi-pci",\ -+ .property = "vectors",\ -+ .value = stringify(2),\ -+ },{\ -+ .driver = "hda-micro",\ -+ .property = "mixer",\ -+ .value = "off",\ -+ },{\ -+ .driver = "hda-duplex",\ -+ .property = "mixer",\ -+ .value = "off",\ -+ },{\ -+ .driver = "hda-output",\ -+ .property = "mixer",\ -+ .value = "off",\ -+ },{\ -+ .driver = "virtio-net-pci",\ -+ .property = "ctrl_mac_addr",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = TYPE_X86_CPU,\ -+ .property = "sep",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = "virtio-net-pci",\ -+ .property = "__com.redhat_rhel6_ctrl_guest_workaround", \ -+ .value = "off",\ -+ }, -+ -+static void pc_compat_rhel640(MachineState *machine) -+{ -+ pc_compat_rhel650(machine); -+} -+ -+static void pc_init_rhel640(MachineState *machine) -+{ -+ pc_compat_rhel640(machine); -+ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \ -+ TYPE_I440FX_PCI_DEVICE);} -+ -+static void pc_machine_rhel640_options(MachineClass *m) -+{ -+ pc_machine_rhel650_options(m); -+ m->family = "pc_piix_Z"; -+ m->desc = "RHEL 6.4.0 PC"; -+ SET_MACHINE_COMPAT(m, PC_RHEL6_4_COMPAT); -+} -+ -+DEFINE_PC_MACHINE(rhel640, "rhel6.4.0", pc_init_rhel640, -+ pc_machine_rhel640_options); -+ -+#define PC_RHEL6_3_COMPAT \ -+ {\ -+ .driver = "Conroe-" TYPE_X86_CPU,\ -+ .property = "min-level",\ -+ .value = stringify(2),\ -+ },{\ -+ .driver = "Penryn-" TYPE_X86_CPU,\ -+ .property = "min-level",\ -+ .value = stringify(2),\ -+ },{\ -+ .driver = "Nehalem-" TYPE_X86_CPU,\ -+ .property = "min-level",\ -+ .value = stringify(2),\ -+ },{\ -+ .driver = "e1000",\ -+ .property = "autonegotiation",\ -+ .value = "off",\ -+ },{\ -+ .driver = "qxl",\ -+ .property = "revision",\ -+ .value = stringify(3),\ -+ },{\ -+ .driver = "qxl-vga",\ -+ .property = "revision",\ -+ .value = stringify(3),\ -+ },{\ -+ .driver = "virtio-scsi-pci",\ -+ .property = "hotplug",\ -+ .value = "off",\ -+ },{\ -+ .driver = "virtio-scsi-pci",\ -+ .property = "param_change",\ -+ .value = "off",\ -+ },{\ -+ .driver = TYPE_X86_CPU,\ -+ .property = "pmu",\ -+ .value = "on",\ -+ },{\ -+ .driver = "usb-hub",\ -+ .property = "serial",\ -+ .value = "314159",\ -+ },{\ -+ .driver = "usb-storage",\ -+ .property = "serial",\ -+ .value = "1",\ -+ },\ -+ {\ -+ .driver = "SandyBridge" "-" TYPE_X86_CPU,\ -+ .property = "tsc-deadline",\ -+ .value = "off",\ -+ }, -+ -+static void pc_compat_rhel630(MachineState *machine) -+{ -+ pc_compat_rhel640(machine); -+ x86_cpu_change_kvm_default("kvm-pv-eoi",NULL); -+ enable_compat_apic_id_mode(); -+} -+ -+static void pc_init_rhel630(MachineState *machine) -+{ -+ pc_compat_rhel630(machine); -+ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \ -+ TYPE_I440FX_PCI_DEVICE);} -+ -+static void pc_machine_rhel630_options(MachineClass *m) -+{ -+ pc_machine_rhel640_options(m); -+ m->family = "pc_piix_Z"; -+ m->desc = "RHEL 6.3.0 PC"; -+ SET_MACHINE_COMPAT(m, PC_RHEL6_3_COMPAT); -+} -+ -+DEFINE_PC_MACHINE(rhel630, "rhel6.3.0", pc_init_rhel630, -+ pc_machine_rhel630_options); -+ -+ -+#define PC_RHEL6_2_COMPAT \ -+ {\ -+ .driver = TYPE_X86_CPU,\ -+ .property = "pmu",\ -+ .value = "off",\ -+ }, -+ -+static void pc_compat_rhel620(MachineState *machine) -+{ -+ pc_compat_rhel630(machine); -+} -+ -+static void pc_init_rhel620(MachineState *machine) -+{ -+ pc_compat_rhel620(machine); -+ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \ -+ TYPE_I440FX_PCI_DEVICE);} -+ -+static void pc_machine_rhel620_options(MachineClass *m) -+{ -+ pc_machine_rhel630_options(m); -+ m->family = "pc_piix_Z"; -+ m->desc = "RHEL 6.2.0 PC"; -+ SET_MACHINE_COMPAT(m, PC_RHEL6_2_COMPAT); -+} -+ -+DEFINE_PC_MACHINE(rhel620, "rhel6.2.0", pc_init_rhel620, -+ pc_machine_rhel620_options); -+ -+/* -+ * NOTE: We don't have the event_idx compat entry for the -+ * virtio-balloon-pci driver because RHEL6 doesn't disable -+ * it either due to a bug (see RHBZ 1029539 fo more info) -+ */ -+#define PC_RHEL6_1_COMPAT \ -+ {\ -+ .driver = "PIIX4_PM",\ -+ .property = "disable_s3",\ -+ .value = "0",\ -+ },{\ -+ .driver = "PIIX4_PM",\ -+ .property = "disable_s4",\ -+ .value = "0",\ -+ },{\ -+ .driver = "qxl",\ -+ .property = "revision",\ -+ .value = stringify(2),\ -+ },{\ -+ .driver = "qxl-vga",\ -+ .property = "revision",\ -+ .value = stringify(2),\ -+ },{\ -+ .driver = "virtio-blk-pci",\ -+ .property = "event_idx",\ -+ .value = "off",\ -+ },{\ -+ .driver = "virtio-serial-pci",\ -+ .property = "event_idx",\ -+ .value = "off",\ -+ },{\ -+ .driver = "virtio-net-pci",\ -+ .property = "event_idx",\ -+ .value = "off",\ -+ },{\ -+ .driver = "usb-kbd",\ -+ .property = "serial",\ -+ .value = "1",\ -+ },{\ -+ .driver = "usb-mouse",\ -+ .property = "serial",\ -+ .value = "1",\ -+ },{\ -+ .driver = "usb-tablet",\ -+ .property = "serial",\ -+ .value = "1",\ -+ }, -+ -+static void pc_compat_rhel610(MachineState *machine) -+{ -+ pc_compat_rhel620(machine); -+} -+ -+static void pc_init_rhel610(MachineState *machine) -+{ -+ pc_compat_rhel610(machine); -+ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \ -+ TYPE_I440FX_PCI_DEVICE);} -+ -+static void pc_machine_rhel610_options(MachineClass *m) -+{ -+ pc_machine_rhel620_options(m); -+ m->family = "pc_piix_Z"; -+ m->desc = "RHEL 6.1.0 PC"; -+ SET_MACHINE_COMPAT(m, PC_RHEL6_1_COMPAT); -+} -+ -+DEFINE_PC_MACHINE(rhel610, "rhel6.1.0", pc_init_rhel610, -+ pc_machine_rhel610_options); -+ -+#define PC_RHEL6_0_COMPAT \ -+ {\ -+ .driver = "qxl",\ -+ .property = "revision",\ -+ .value = stringify(1),\ -+ },{\ -+ .driver = "qxl-vga",\ -+ .property = "revision",\ -+ .value = stringify(1),\ -+ },{\ -+ .driver = "VGA",\ -+ .property = "rombar",\ -+ .value = stringify(0),\ -+ }, -+ -+static void pc_compat_rhel600(MachineState *machine) -+{ -+ pc_compat_rhel610(machine); -+} -+ -+static void pc_init_rhel600(MachineState *machine) -+{ -+ pc_compat_rhel600(machine); -+ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \ -+ TYPE_I440FX_PCI_DEVICE);} -+ -+static void pc_machine_rhel600_options(MachineClass *m) -+{ -+ pc_machine_rhel610_options(m); -+ m->family = "pc_piix_Z"; -+ m->desc = "RHEL 6.0.0 PC"; -+ SET_MACHINE_COMPAT(m, PC_RHEL6_0_COMPAT); -+} -+ -+DEFINE_PC_MACHINE(rhel600, "rhel6.0.0", pc_init_rhel600, -+ pc_machine_rhel600_options); -+ -diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c -index 169a214..575d407 100644 ---- a/hw/i386/pc_q35.c -+++ b/hw/i386/pc_q35.c -@@ -137,8 +137,8 @@ static void pc_q35_init(MachineState *machine) - - if (pcmc->smbios_defaults) { - /* These values are guest ABI, do not change */ -- smbios_set_defaults("QEMU", "Standard PC (Q35 + ICH9, 2009)", -- mc->name, pcmc->smbios_legacy_mode, -+ smbios_set_defaults("Red Hat", "KVM", -+ mc->desc, pcmc->smbios_legacy_mode, - pcmc->smbios_uuid_encoded, - SMBIOS_ENTRY_POINT_21); - } -@@ -289,6 +289,7 @@ static void pc_q35_init(MachineState *machine) - DEFINE_PC_MACHINE(suffix, name, pc_init_##suffix, optionfn) - - -+#if 0 /* Disabled for Red Hat Enterprise Linux */ - static void pc_q35_machine_options(MachineClass *m) - { - m->family = "pc_q35"; -@@ -300,6 +301,7 @@ static void pc_q35_machine_options(MachineClass *m) - m->no_floppy = 1; - m->has_dynamic_sysbus = true; - m->max_cpus = 288; -+ SET_MACHINE_COMPAT(m, PC_RHEL_COMPAT); - } - - static void pc_q35_2_10_machine_options(MachineClass *m) -@@ -376,3 +378,52 @@ static void pc_q35_2_4_machine_options(MachineClass *m) - - DEFINE_Q35_MACHINE(v2_4, "pc-q35-2.4", NULL, - pc_q35_2_4_machine_options); -+#endif /* Disabled for Red Hat Enterprise Linux */ -+ -+/* Red Hat Enterprise Linux machine types */ -+ -+/* Options for the latest rhel7 q35 machine type */ -+static void pc_q35_machine_rhel7_options(MachineClass *m) -+{ -+ m->family = "pc_q35_Z"; -+ m->default_machine_opts = "firmware=bios-256k.bin"; -+ m->default_display = "std"; -+ m->no_floppy = 1; -+ m->has_dynamic_sysbus = true; -+ m->alias = "q35"; -+ m->max_cpus = 384; -+ SET_MACHINE_COMPAT(m, PC_RHEL_COMPAT); -+} -+ -+static void pc_q35_init_rhel740(MachineState *machine) -+{ -+ pc_q35_init(machine); -+} -+ -+static void pc_q35_machine_rhel740_options(MachineClass *m) -+{ -+ pc_q35_machine_rhel7_options(m); -+ m->desc = "RHEL-7.4.0 PC (Q35 + ICH9, 2009)"; -+} -+ -+DEFINE_PC_MACHINE(q35_rhel740, "pc-q35-rhel7.4.0", pc_q35_init_rhel740, -+ pc_q35_machine_rhel740_options); -+ -+static void pc_q35_init_rhel730(MachineState *machine) -+{ -+ pc_q35_init(machine); -+} -+ -+static void pc_q35_machine_rhel730_options(MachineClass *m) -+{ -+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m); -+ pc_q35_machine_rhel740_options(m); -+ m->alias = NULL; -+ m->desc = "RHEL-7.3.0 PC (Q35 + ICH9, 2009)"; -+ m->max_cpus = 255; -+ pcmc->linuxboot_dma_enabled = false; -+ SET_MACHINE_COMPAT(m, PC_RHEL7_3_COMPAT); -+} -+ -+DEFINE_PC_MACHINE(q35_rhel730, "pc-q35-rhel7.3.0", pc_q35_init_rhel730, -+ pc_q35_machine_rhel730_options); -diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c -index 6b18374..04db39a 100644 ---- a/hw/i386/pc_sysfw.c -+++ b/hw/i386/pc_sysfw.c -@@ -193,6 +193,13 @@ static void old_pc_system_rom_init(MemoryRegion *rom_memory, bool isapc_ram_fw) - (bios_size % 65536) != 0) { - goto bios_error; - } -+ if (shadow_bios_after_incoming && bios_size != 128 * 1024) { -+ MachineClass *mc; -+ -+ mc = MACHINE_GET_CLASS(current_machine); -+ error_report("machine %s only supports a 128KB BIOS image", mc->name); -+ exit(1); -+ } - bios = g_malloc(sizeof(*bios)); - memory_region_init_ram(bios, NULL, "pc.bios", bios_size, &error_fatal); - if (!isapc_ram_fw) { -@@ -240,6 +247,15 @@ void pc_system_firmware_init(MemoryRegion *rom_memory, bool isapc_ram_fw) - return; - } - -+ if (shadow_bios_after_incoming) { -+ MachineClass *mc; -+ -+ mc = MACHINE_GET_CLASS(current_machine); -+ error_report("flash-based firmware is not supported by machine %s", -+ mc->name); -+ exit(1); -+ } -+ - if (kvm_enabled() && !kvm_readonly_mem_enabled()) { - /* Older KVM cannot execute from device memory. So, flash memory - * cannot be used unless the readonly memory kvm capability is present. */ -diff --git a/hw/i386/shadow-bios.c b/hw/i386/shadow-bios.c -new file mode 100644 -index 0000000..65a4cb8 ---- /dev/null -+++ b/hw/i386/shadow-bios.c -@@ -0,0 +1,64 @@ -+#include "qemu/osdep.h" -+#include "sysemu/sysemu.h" -+#include "target/i386/cpu.h" -+#include "exec/ram_addr.h" -+#include "qemu/cutils.h" -+ -+void shadow_bios(void) -+{ -+ RAMBlock *block, *ram, *oprom, *bios; -+ size_t one_meg, oprom_size, bios_size; -+ uint8_t *cd_seg_host, *ef_seg_host; -+ -+ ram = NULL; -+ oprom = NULL; -+ bios = NULL; -+ rcu_read_lock(); -+ QLIST_FOREACH_RCU(block, &ram_list.blocks, next) { -+ if (strcmp("pc.ram", block->idstr) == 0) { -+ assert(ram == NULL); -+ ram = block; -+ } else if (strcmp("pc.rom", block->idstr) == 0) { -+ assert(oprom == NULL); -+ oprom = block; -+ } else if (strcmp("pc.bios", block->idstr) == 0) { -+ assert(bios == NULL); -+ bios = block; -+ } -+ } -+ assert(ram != NULL); -+ assert(oprom != NULL); -+ assert(bios != NULL); -+ assert(memory_region_is_ram(ram->mr)); -+ assert(memory_region_is_ram(oprom->mr)); -+ assert(memory_region_is_ram(bios->mr)); -+ assert(int128_eq(ram->mr->size, int128_make64(ram->used_length))); -+ assert(int128_eq(oprom->mr->size, int128_make64(oprom->used_length))); -+ assert(int128_eq(bios->mr->size, int128_make64(bios->used_length))); -+ -+ one_meg = 1024 * 1024; -+ oprom_size = 128 * 1024; -+ bios_size = 128 * 1024; -+ assert(ram->used_length >= one_meg); -+ assert(oprom->used_length == oprom_size); -+ assert(bios->used_length == bios_size); -+ -+ ef_seg_host = memory_region_get_ram_ptr(ram->mr) + (one_meg - bios_size); -+ cd_seg_host = ef_seg_host - oprom_size; -+ -+ /* This is a crude hack, but we must distinguish a rhel6.x.0 machtype guest -+ * coming in from a RHEL-6 emulator (where shadowing has had no effect on -+ * "pc.ram") from a similar guest coming in from a RHEL-7 emulator (where -+ * shadowing has worked). In the latter case we must not trample the live -+ * SeaBIOS variables in "pc.ram". -+ */ -+ if (buffer_is_zero(ef_seg_host, bios_size)) { -+ fprintf(stderr, "copying E and F segments from pc.bios to pc.ram\n"); -+ memcpy(ef_seg_host, memory_region_get_ram_ptr(bios->mr), bios_size); -+ } -+ if (buffer_is_zero(cd_seg_host, oprom_size)) { -+ fprintf(stderr, "copying C and D segments from pc.rom to pc.ram\n"); -+ memcpy(cd_seg_host, memory_region_get_ram_ptr(oprom->mr), oprom_size); -+ } -+ rcu_read_unlock(); -+} -diff --git a/hw/net/e1000.c b/hw/net/e1000.c -index f2e5072..3d86146 100644 ---- a/hw/net/e1000.c -+++ b/hw/net/e1000.c -@@ -1595,6 +1595,16 @@ static void pci_e1000_realize(PCIDevice *pci_dev, Error **errp) - - pci_conf = pci_dev->config; - -+ if (!(d->compat_flags & E1000_FLAG_AUTONEG)) { -+ /* -+ * We have no capabilities, so capability list bit should normally be 0. -+ * Keep it on for compat machine types to avoid breaking migration. -+ * HACK: abuse E1000_FLAG_AUTONEG, which is off exactly for -+ * the machine types that need this. -+ */ -+ pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_CAP_LIST); -+ } -+ - /* TODO: RST# value should be 0, PCI spec 6.2.4 */ - pci_conf[PCI_CACHE_LINE_SIZE] = 0x10; - -@@ -1657,7 +1667,7 @@ static void e1000_class_init(ObjectClass *klass, void *data) - - k->realize = pci_e1000_realize; - k->exit = pci_e1000_uninit; -- k->romfile = "efi-e1000.rom"; -+ k->romfile = "pxe-e1000.rom"; - k->vendor_id = PCI_VENDOR_ID_INTEL; - k->device_id = info->device_id; - k->revision = info->revision; -@@ -1689,7 +1699,7 @@ static const TypeInfo e1000_base_info = { - - static const E1000Info e1000_devices[] = { - { -- .name = "e1000", -+ .name = "e1000-82540em", - .device_id = E1000_DEV_ID_82540EM, - .revision = 0x03, - .phy_id2 = E1000_PHY_ID2_8254xx_DEFAULT, -@@ -1708,6 +1718,11 @@ static const E1000Info e1000_devices[] = { - }, - }; - -+static const TypeInfo e1000_default_info = { -+ .name = "e1000", -+ .parent = "e1000-82540em", -+}; -+ - static void e1000_register_types(void) - { - int i; -@@ -1725,6 +1740,7 @@ static void e1000_register_types(void) - - type_register(&type_info); - } -+ type_register_static(&e1000_default_info); - } - - type_init(e1000_register_types) -diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c -index 798d681..8660955 100644 ---- a/hw/net/ne2000.c -+++ b/hw/net/ne2000.c -@@ -771,7 +771,7 @@ static void ne2000_class_init(ObjectClass *klass, void *data) - - k->realize = pci_ne2000_realize; - k->exit = pci_ne2000_exit; -- k->romfile = "efi-ne2k_pci.rom", -+ k->romfile = "pxe-ne2k_pci.rom", - k->vendor_id = PCI_VENDOR_ID_REALTEK; - k->device_id = PCI_DEVICE_ID_REALTEK_8029; - k->class_id = PCI_CLASS_NETWORK_ETHERNET; -diff --git a/hw/net/pcnet-pci.c b/hw/net/pcnet-pci.c -index 0acf8a4..eeab4ca 100644 ---- a/hw/net/pcnet-pci.c -+++ b/hw/net/pcnet-pci.c -@@ -348,7 +348,7 @@ static void pcnet_class_init(ObjectClass *klass, void *data) - - k->realize = pci_pcnet_realize; - k->exit = pci_pcnet_uninit; -- k->romfile = "efi-pcnet.rom", -+ k->romfile = "pxe-pcnet.rom", - k->vendor_id = PCI_VENDOR_ID_AMD; - k->device_id = PCI_DEVICE_ID_AMD_LANCE; - k->revision = 0x10; -diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c -index 671c7e4..450658c 100644 ---- a/hw/net/rtl8139.c -+++ b/hw/net/rtl8139.c -@@ -3472,7 +3472,7 @@ static void rtl8139_class_init(ObjectClass *klass, void *data) - - k->realize = pci_rtl8139_realize; - k->exit = pci_rtl8139_uninit; -- k->romfile = "efi-rtl8139.rom"; -+ k->romfile = "pxe-rtl8139.rom"; - k->vendor_id = PCI_VENDOR_ID_REALTEK; - k->device_id = PCI_DEVICE_ID_REALTEK_8139; - k->revision = RTL8139_PCI_REVID; /* >=0x20 is for 8139C+ */ -diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs -index 7efc686..645ffdf 100644 ---- a/hw/ppc/Makefile.objs -+++ b/hw/ppc/Makefile.objs -@@ -12,7 +12,7 @@ obj-y += spapr_pci_vfio.o - endif - obj-$(CONFIG_PSERIES) += spapr_rtas_ddw.o - # PowerPC 4xx boards --obj-y += ppc405_boards.o ppc4xx_devs.o ppc405_uc.o ppc440_bamboo.o -+obj-y += ppc4xx_devs.o ppc405_uc.o - obj-y += ppc4xx_pci.o - # PReP - obj-$(CONFIG_PREP) += prep.o -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index cec441c..268fd44 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -3537,6 +3537,7 @@ static const TypeInfo spapr_machine_info = { - } \ - type_init(spapr_machine_register_##suffix) - -+#if 0 /* Disabled for Red Hat Enterprise Linux */ - /* - * pseries-2.10 - */ -@@ -3630,6 +3631,7 @@ DEFINE_SPAPR_MACHINE(2_8, "2.8", false); - .property = "pre-2.8-migration", \ - .value = "on", \ - }, -+#endif - - static void phb_placement_2_7(sPAPRMachineState *spapr, uint32_t index, - uint64_t *buid, hwaddr *pio, -@@ -3680,6 +3682,7 @@ static void phb_placement_2_7(sPAPRMachineState *spapr, uint32_t index, - */ - } - -+#if 0 /* Disabled for Red Hat Enterprise Linux */ - static void spapr_machine_2_7_instance_options(MachineState *machine) - { - sPAPRMachineState *spapr = SPAPR_MACHINE(machine); -@@ -3839,6 +3842,127 @@ static void spapr_machine_2_1_class_options(MachineClass *mc) - SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_1); - } - DEFINE_SPAPR_MACHINE(2_1, "2.1", false); -+#endif -+ -+/* -+ * pseries-rhel7.4.0alt -+ */ -+static void spapr_machine_rhel740alt_instance_options(MachineState *machine) -+{ -+} -+ -+static void spapr_machine_rhel740alt_class_options(MachineClass *mc) -+{ -+ /* Defaults for the latest behaviour inherited from the base class */ -+} -+ -+DEFINE_SPAPR_MACHINE(rhel740alt, "rhel7.4.0alt", true); -+ -+ -+/* -+ * pseries-rhel7.4.0 -+ */ -+ -+static void spapr_machine_rhel740_instance_options(MachineState *machine) -+{ -+ spapr_machine_rhel740alt_instance_options(machine); -+} -+ -+static void spapr_machine_rhel740_class_options(MachineClass *mc) -+{ -+ spapr_machine_rhel740alt_class_options(mc); -+} -+ -+DEFINE_SPAPR_MACHINE(rhel740, "rhel7.4.0", false); -+ -+/* -+ * pseries-rhel7.3.0 -+ * like SPAPR_COMPAT_2_6/_2_7/_2_8 but "ddw" has been backported to RHEL7_3 -+ */ -+#define SPAPR_COMPAT_RHEL7_3 \ -+ HW_COMPAT_RHEL7_3 \ -+ { \ -+ .driver = TYPE_SPAPR_PCI_HOST_BRIDGE, \ -+ .property = "mem_win_size", \ -+ .value = stringify(SPAPR_PCI_2_7_MMIO_WIN_SIZE),\ -+ }, \ -+ { \ -+ .driver = TYPE_SPAPR_PCI_HOST_BRIDGE, \ -+ .property = "mem64_win_size", \ -+ .value = "0", \ -+ }, \ -+ { \ -+ .driver = TYPE_POWERPC_CPU, \ -+ .property = "pre-2.8-migration", \ -+ .value = "on", \ -+ }, \ -+ { \ -+ .driver = TYPE_SPAPR_PCI_HOST_BRIDGE, \ -+ .property = "pre-2.8-migration", \ -+ .value = "on", \ -+ }, \ -+ { \ -+ .driver = TYPE_SPAPR_PCI_HOST_BRIDGE, \ -+ .property = "pcie-extended-configuration-space",\ -+ .value = "off", \ -+ }, -+ -+static void spapr_machine_rhel730_instance_options(MachineState *machine) -+{ -+ sPAPRMachineState *spapr = SPAPR_MACHINE(machine); -+ -+ spapr_machine_rhel740_instance_options(machine); -+ spapr->use_hotplug_event_source = false; -+} -+ -+static void spapr_machine_rhel730_class_options(MachineClass *mc) -+{ -+ sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); -+ -+ spapr_machine_rhel740_class_options(mc); -+ smc->tcg_default_cpu = "POWER7"; -+ SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_RHEL7_3); -+ smc->phb_placement = phb_placement_2_7; -+} -+ -+DEFINE_SPAPR_MACHINE(rhel730, "rhel7.3.0", false); -+ -+/* -+ * pseries-rhel7.2.0 -+ */ -+/* Should be like SPAPR_COMPAT_2_5 + 2_4 + 2_3, but "dynamic-reconfiguration" -+ * has been backported to RHEL7_2 so we don't need it here. -+ */ -+ -+#define SPAPR_COMPAT_RHEL7_2 \ -+ HW_COMPAT_RHEL7_2 \ -+ { \ -+ .driver = "spapr-vlan", \ -+ .property = "use-rx-buffer-pools", \ -+ .value = "off", \ -+ },{ \ -+ .driver = TYPE_SPAPR_PCI_HOST_BRIDGE,\ -+ .property = "ddw",\ -+ .value = stringify(off),\ -+ }, -+ -+ -+static void spapr_machine_rhel720_instance_options(MachineState *machine) -+{ -+ spapr_machine_rhel730_instance_options(machine); -+} -+ -+static void spapr_machine_rhel720_class_options(MachineClass *mc) -+{ -+ sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); -+ -+ spapr_machine_rhel730_class_options(mc); -+ smc->use_ohci_by_default = true; -+ mc->has_hotpluggable_cpus = NULL; -+ SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_RHEL7_2); -+} -+ -+DEFINE_SPAPR_MACHINE(rhel720, "rhel7.2.0", false); - - static void spapr_machine_register_types(void) - { -diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c -index 1a5437a..cd9cdfa 100644 ---- a/hw/smbios/smbios.c -+++ b/hw/smbios/smbios.c -@@ -743,6 +743,7 @@ void smbios_set_defaults(const char *manufacturer, const char *product, - SMBIOS_SET_DEFAULT(type1.manufacturer, manufacturer); - SMBIOS_SET_DEFAULT(type1.product, product); - SMBIOS_SET_DEFAULT(type1.version, version); -+ SMBIOS_SET_DEFAULT(type1.family, "Red Hat Enterprise Linux"); - SMBIOS_SET_DEFAULT(type2.manufacturer, manufacturer); - SMBIOS_SET_DEFAULT(type2.product, product); - SMBIOS_SET_DEFAULT(type2.version, version); -diff --git a/hw/timer/i8254_common.c b/hw/timer/i8254_common.c -index 976d520..339f336 100644 ---- a/hw/timer/i8254_common.c -+++ b/hw/timer/i8254_common.c -@@ -267,7 +267,7 @@ static const VMStateDescription vmstate_pit_common = { - .pre_save = pit_dispatch_pre_save, - .post_load = pit_dispatch_post_load, - .fields = (VMStateField[]) { -- VMSTATE_UINT32_V(channels[0].irq_disabled, PITCommonState, 3), -+ VMSTATE_UINT32(channels[0].irq_disabled, PITCommonState), /* qemu-kvm's v2 had 'flags' here */ - VMSTATE_STRUCT_ARRAY(channels, PITCommonState, 3, 2, - vmstate_pit_channel, PITChannelState), - VMSTATE_INT64(channels[0].next_transition_time, -diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c -index 82843ed..f2ed447 100644 ---- a/hw/timer/mc146818rtc.c -+++ b/hw/timer/mc146818rtc.c -@@ -32,6 +32,7 @@ - #include "qapi/visitor.h" - #include "qapi-event.h" - #include "qmp-commands.h" -+#include "migration/migration.h" - - #ifdef TARGET_I386 - #include "hw/i386/apic.h" -@@ -835,6 +836,11 @@ static int rtc_post_load(void *opaque, int version_id) - static bool rtc_irq_reinject_on_ack_count_needed(void *opaque) - { - RTCState *s = (RTCState *)opaque; -+ -+ if (migrate_pre_2_2) { -+ return false; -+ } -+ - return s->irq_reinject_on_ack_count != 0; - } - -diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c -index e3562a4..465ed42 100644 ---- a/hw/usb/hcd-uhci.c -+++ b/hw/usb/hcd-uhci.c -@@ -152,6 +152,8 @@ typedef struct UHCI_QH { - uint32_t el_link; - } UHCI_QH; - -+bool ich9_uhci123_irqpin_override; -+ - static void uhci_async_cancel(UHCIAsync *async); - static void uhci_queue_fill(UHCIQueue *q, UHCI_TD *td); - static void uhci_resume(void *opaque); -@@ -1214,12 +1216,23 @@ static void usb_uhci_common_realize(PCIDevice *dev, Error **errp) - UHCIState *s = UHCI(dev); - uint8_t *pci_conf = s->dev.config; - int i; -+ int irq_pin; - - pci_conf[PCI_CLASS_PROG] = 0x00; - /* TODO: reset value should be 0. */ - pci_conf[USB_SBRN] = USB_RELEASE_1; // release number - -- pci_config_set_interrupt_pin(pci_conf, u->info.irq_pin + 1); -+ if (ich9_uhci123_irqpin_override && -+ u->info.vendor_id == PCI_VENDOR_ID_INTEL && -+ (u->info.device_id == PCI_DEVICE_ID_INTEL_82801I_UHCI1 || -+ u->info.device_id == PCI_DEVICE_ID_INTEL_82801I_UHCI2 || -+ u->info.device_id == PCI_DEVICE_ID_INTEL_82801I_UHCI3)) { -+ fprintf(stderr, "RHEL-6 compat: %s: irq_pin = 3\n", u->info.name); -+ irq_pin = 3; -+ } else { -+ irq_pin = u->info.irq_pin; -+ } -+ pci_config_set_interrupt_pin(pci_conf, irq_pin + 1); - - if (s->masterbus) { - USBPort *ports[NB_PORTS]; -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index 204ea69..10848db 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -3555,9 +3555,25 @@ static const VMStateDescription vmstate_xhci_slot = { - } - }; - -+static void xhci_event_pre_save(void *opaque) -+{ -+ XHCIEvent *s = opaque; -+ -+ s->cve_2014_5263_a = ((uint8_t *)&s->type)[0]; -+ s->cve_2014_5263_b = ((uint8_t *)&s->type)[1]; -+} -+ -+bool migrate_cve_2014_5263_xhci_fields; -+ -+static bool xhci_event_cve_2014_5263(void *opaque, int version_id) -+{ -+ return migrate_cve_2014_5263_xhci_fields; -+} -+ - static const VMStateDescription vmstate_xhci_event = { - .name = "xhci-event", - .version_id = 1, -+ .pre_save = xhci_event_pre_save, - .fields = (VMStateField[]) { - VMSTATE_UINT32(type, XHCIEvent), - VMSTATE_UINT32(ccode, XHCIEvent), -@@ -3566,6 +3582,8 @@ static const VMStateDescription vmstate_xhci_event = { - VMSTATE_UINT32(flags, XHCIEvent), - VMSTATE_UINT8(slotid, XHCIEvent), - VMSTATE_UINT8(epid, XHCIEvent), -+ VMSTATE_UINT8_TEST(cve_2014_5263_a, XHCIEvent, xhci_event_cve_2014_5263), -+ VMSTATE_UINT8_TEST(cve_2014_5263_b, XHCIEvent, xhci_event_cve_2014_5263), - VMSTATE_END_OF_LIST() - } - }; -diff --git a/hw/usb/hcd-xhci.h b/hw/usb/hcd-xhci.h -index fc36a4c..89d4cf7 100644 ---- a/hw/usb/hcd-xhci.h -+++ b/hw/usb/hcd-xhci.h -@@ -153,6 +153,8 @@ typedef struct XHCIEvent { - uint32_t flags; - uint8_t slotid; - uint8_t epid; -+ uint8_t cve_2014_5263_a; -+ uint8_t cve_2014_5263_b; - } XHCIEvent; - - typedef struct XHCIInterrupter { -diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c -index 8b0d6b6..eccf809 100644 ---- a/hw/virtio/virtio-pci.c -+++ b/hw/virtio/virtio-pci.c -@@ -2394,7 +2394,7 @@ static void virtio_net_pci_class_init(ObjectClass *klass, void *data) - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass); - -- k->romfile = "efi-virtio.rom"; -+ k->romfile = "pxe-virtio.rom"; - k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - k->device_id = PCI_DEVICE_ID_VIRTIO_NET; - k->revision = VIRTIO_PCI_ABI_VERSION; -diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c -index 464947f..e7a2bc2 100644 ---- a/hw/virtio/virtio.c -+++ b/hw/virtio/virtio.c -@@ -24,6 +24,7 @@ - #include "hw/virtio/virtio-access.h" - #include "sysemu/dma.h" - -+#include "standard-headers/linux/virtio_net.h" - /* - * The alignment to use between consumer and producer parts of vring. - * x86 pagesize again. This is the default, used by transports like PCI -@@ -1984,7 +1985,24 @@ const VMStateInfo virtio_vmstate_info = { - static int virtio_set_features_nocheck(VirtIODevice *vdev, uint64_t val) - { - VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); -- bool bad = (val & ~(vdev->host_features)) != 0; -+ bool bad; -+ uint64_t ctrl_guest_mask = 1ull << VIRTIO_NET_F_CTRL_GUEST_OFFLOADS; -+ -+ if (vdev->rhel6_ctrl_guest_workaround && (val & ctrl_guest_mask) && -+ !(vdev->host_features & ctrl_guest_mask)) { -+ /* -+ * This works around a mistake in the definition of the rhel6.[56].0 -+ * machinetypes, ctrl-guest-offload was not set in qemu-kvm-rhev for -+ * those machine types, but is set on the rhel6 qemu-kvm-rhev build. -+ * If an incoming rhel6 guest uses it then we need to allow it. -+ * Note: There's a small race where a guest read the flag but didn't -+ * declare it's useage yet. -+ */ -+ fprintf(stderr, "RHEL6 ctrl_guest_offload workaround\n"); -+ vdev->host_features |= ctrl_guest_mask; -+ } -+ -+ bad = (val & ~(vdev->host_features)) != 0; - - val &= vdev->host_features; - if (k->set_features) { -@@ -2548,6 +2566,8 @@ static void virtio_device_instance_finalize(Object *obj) - - static Property virtio_properties[] = { - DEFINE_VIRTIO_COMMON_FEATURES(VirtIODevice, host_features), -+ DEFINE_PROP_BOOL("__com.redhat_rhel6_ctrl_guest_workaround", VirtIODevice, -+ rhel6_ctrl_guest_workaround, false), - DEFINE_PROP_END_OF_LIST(), - }; - -diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h -index 33b0ff3..a1f533d 100644 ---- a/include/hw/arm/virt.h -+++ b/include/hw/arm/virt.h -@@ -108,6 +108,7 @@ typedef struct { - int psci_conduit; - } VirtMachineState; - -+#if 0 /* disabled for Red Hat Enterprise Linux */ - #define TYPE_VIRT_MACHINE MACHINE_TYPE_NAME("virt") - #define VIRT_MACHINE(obj) \ - OBJECT_CHECK(VirtMachineState, (obj), TYPE_VIRT_MACHINE) -@@ -116,6 +117,27 @@ typedef struct { - #define VIRT_MACHINE_CLASS(klass) \ - OBJECT_CLASS_CHECK(VirtMachineClass, klass, TYPE_VIRT_MACHINE) - -+#else -+#define TYPE_RHEL_MACHINE MACHINE_TYPE_NAME("virt-rhel") -+#define VIRT_MACHINE(obj) \ -+ OBJECT_CHECK(VirtMachineState, (obj), TYPE_RHEL_MACHINE) -+#define VIRT_MACHINE_GET_CLASS(obj) \ -+ OBJECT_GET_CLASS(VirtMachineClass, obj, TYPE_RHEL_MACHINE) -+#define VIRT_MACHINE_CLASS(klass) \ -+ OBJECT_CLASS_CHECK(VirtMachineClass, klass, TYPE_RHEL_MACHINE) -+#endif -+ -+/* This macro is for changes to properties that are RHEL specific, -+ * different to the current upstream and to be applied to the latest -+ * machine type. -+ */ -+#define ARM_RHEL_COMPAT \ -+ {\ -+ .driver = "virtio-net-pci",\ -+ .property = "romfile",\ -+ .value = "",\ -+ }, -+ - void virt_acpi_setup(VirtMachineState *vms); - - #endif /* QEMU_ARM_VIRT_H */ -diff --git a/include/hw/compat.h b/include/hw/compat.h -index 08f3600..bb138cd 100644 ---- a/include/hw/compat.h -+++ b/include/hw/compat.h -@@ -227,6 +227,186 @@ - .driver = "virtio-pci",\ - .property = "virtio-pci-bus-master-bug-migration",\ - .value = "on",\ -+ },{ /* HW_COMPAT_RHEL7_3 */ \ -+ .driver = "virtio-net-device",\ -+ .property = "x-mtu-bypass-backend",\ -+ .value = "off",\ -+ }, -+ -+/* Mostly like HW_COMPAT_2_1 but: -+ * we don't need virtio-scsi-pci since 7.0 already had that on -+ * -+ * RH: Note, qemu-extended-regs should have been enabled in the 7.1 -+ * machine type, but was accidentally turned off in 7.2 onwards. -+ * -+ */ -+#define HW_COMPAT_RHEL7_1 \ -+ { /* COMPAT_RHEL7.1 */ \ -+ .driver = "intel-hda-generic",\ -+ .property = "old_msi_addr",\ -+ .value = "on",\ -+ },{\ -+ .driver = "VGA",\ -+ .property = "qemu-extended-regs",\ -+ .value = "off",\ -+ },{\ -+ .driver = "secondary-vga",\ -+ .property = "qemu-extended-regs",\ -+ .value = "off",\ -+ },{\ -+ .driver = "usb-mouse",\ -+ .property = "usb_version",\ -+ .value = stringify(1),\ -+ },{\ -+ .driver = "usb-kbd",\ -+ .property = "usb_version",\ -+ .value = stringify(1),\ -+ },{\ -+ .driver = "virtio-pci",\ -+ .property = "virtio-pci-bus-master-bug-migration",\ -+ .value = "on",\ -+ },{\ -+ .driver = "virtio-blk-pci",\ -+ .property = "any_layout",\ -+ .value = "off",\ -+ },{\ -+ .driver = "virtio-balloon-pci",\ -+ .property = "any_layout",\ -+ .value = "off",\ -+ },{\ -+ .driver = "virtio-serial-pci",\ -+ .property = "any_layout",\ -+ .value = "off",\ -+ },{\ -+ .driver = "virtio-9p-pci",\ -+ .property = "any_layout",\ -+ .value = "off",\ -+ },{\ -+ .driver = "virtio-rng-pci",\ -+ .property = "any_layout",\ -+ .value = "off",\ -+ },{ /* HW_COMPAT_RHEL7_1 - introduced with 2.10.0 */ \ -+ .driver = "migration",\ -+ .property = "send-configuration",\ -+ .value = "off",\ -+ }, -+ -+/* Mostly like HW_COMPAT_2_4 + 2_3 but: -+ * we don't need "any_layout" as it has been backported to 7.2 -+ */ -+ -+#define HW_COMPAT_RHEL7_2 \ -+ {\ -+ .driver = "virtio-blk-device",\ -+ .property = "scsi",\ -+ .value = "true",\ -+ },{\ -+ .driver = "e1000-82540em",\ -+ .property = "extra_mac_registers",\ -+ .value = "off",\ -+ },{\ -+ .driver = "virtio-pci",\ -+ .property = "x-disable-pcie",\ -+ .value = "on",\ -+ },{\ -+ .driver = "virtio-pci",\ -+ .property = "migrate-extra",\ -+ .value = "off",\ -+ },{ /* HW_COMPAT_RHEL7_2 */ \ -+ .driver = "fw_cfg_mem",\ -+ .property = "dma_enabled",\ -+ .value = "off",\ -+ },{ /* HW_COMPAT_RHEL7_2 */ \ -+ .driver = "fw_cfg_io",\ -+ .property = "dma_enabled",\ -+ .value = "off",\ -+ },{ /* HW_COMPAT_RHEL7_2 */ \ -+ .driver = "isa-fdc",\ -+ .property = "fallback",\ -+ .value = "144",\ -+ },{ /* HW_COMPAT_RHEL7_2 */ \ -+ .driver = "virtio-pci",\ -+ .property = "disable-modern",\ -+ .value = "on",\ -+ },{ /* HW_COMPAT_RHEL7_2 */ \ -+ .driver = "virtio-pci",\ -+ .property = "disable-legacy",\ -+ .value = "off",\ -+ },{ /* HW_COMPAT_RHEL7_2 */ \ -+ .driver = TYPE_PCI_DEVICE,\ -+ .property = "x-pcie-lnksta-dllla",\ -+ .value = "off",\ -+ },{ /* HW_COMPAT_RHEL7_2 */ \ -+ .driver = "virtio-pci",\ -+ .property = "page-per-vq",\ -+ .value = "on",\ -+ },{ /* HW_COMPAT_RHEL7_2 from HW_COMPAT_2_4 added in 2.9 */ \ -+ .driver = "vmgenid",\ -+ .property = "x-write-pointer-available",\ -+ .value = "off",\ -+ },{ /* HW_COMPAT_RHEL7_2 - introduced with 2.10.0 */ \ -+ .driver = "migration",\ -+ .property = "send-section-footer",\ -+ .value = "off",\ -+ },{ /* HW_COMPAT_RHEL7_2 - introduced with 2.10.0 */ \ -+ .driver = "migration",\ -+ .property = "store-global-state",\ -+ .value = "off",\ -+ }, -+ -+/* Mostly like HW_COMPAT_2_6 + HW_COMPAT_2_7 + HW_COMPAT_2_8 except -+ * disable-modern, disable-legacy, page-per-vq have already been -+ * backported to RHEL7.3 -+ */ -+#define HW_COMPAT_RHEL7_3 \ -+ { /* HW_COMPAT_RHEL7_3 */ \ -+ .driver = "virtio-mmio",\ -+ .property = "format_transport_address",\ -+ .value = "off",\ -+ },{ /* HW_COMPAT_RHEL7_3 */ \ -+ .driver = "virtio-serial-device",\ -+ .property = "emergency-write",\ -+ .value = "off",\ -+ },{ /* HW_COMPAT_RHEL7_3 */ \ -+ .driver = "ioapic",\ -+ .property = "version",\ -+ .value = "0x11",\ -+ },{ /* HW_COMPAT_RHEL7_3 */ \ -+ .driver = "intel-iommu",\ -+ .property = "x-buggy-eim",\ -+ .value = "true",\ -+ },{ /* HW_COMPAT_RHEL7_3 */ \ -+ .driver = "virtio-pci",\ -+ .property = "x-ignore-backend-features",\ -+ .value = "on",\ -+ },{ /* HW_COMPAT_RHEL7_3 */ \ -+ .driver = "fw_cfg_mem",\ -+ .property = "x-file-slots",\ -+ .value = stringify(0x10),\ -+ },{ /* HW_COMPAT_RHEL7_3 */ \ -+ .driver = "fw_cfg_io",\ -+ .property = "x-file-slots",\ -+ .value = stringify(0x10),\ -+ },{ /* HW_COMPAT_RHEL7_3 */ \ -+ .driver = "pflash_cfi01",\ -+ .property = "old-multiple-chip-handling",\ -+ .value = "on",\ -+ },{ /* HW_COMPAT_RHEL7_3 */ \ -+ .driver = TYPE_PCI_DEVICE,\ -+ .property = "x-pcie-extcap-init",\ -+ .value = "off",\ -+ },{ /* HW_COMPAT_RHEL7_3 */ \ -+ .driver = "virtio-pci",\ -+ .property = "x-pcie-deverr-init",\ -+ .value = "off",\ -+ },{ /* HW_COMPAT_RHEL7_3 */ \ -+ .driver = "virtio-pci",\ -+ .property = "x-pcie-lnkctl-init",\ -+ .value = "off",\ -+ },{ /* HW_COMPAT_RHEL7_3 */ \ -+ .driver = "virtio-pci",\ -+ .property = "x-pcie-pm-init",\ -+ .value = "off",\ - }, - - #endif /* HW_COMPAT_H */ -diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h -index d80859b..b808a9b 100644 ---- a/include/hw/i386/pc.h -+++ b/include/hw/i386/pc.h -@@ -987,4 +987,446 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *); - type_init(pc_machine_init_##suffix) - - extern void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id); -+ -+/* See include/hw/compat.h for shared compatibility lists */ -+ -+/* This macro is for changes to properties that are RHEL specific, -+ * different to the current upstream and to be applied to the latest -+ * machine type. -+ */ -+#define PC_RHEL_COMPAT \ -+ { /* PC_RHEL_COMPAT */ \ -+ .driver = TYPE_X86_CPU,\ -+ .property = "host-phys-bits",\ -+ .value = "on",\ -+ }, -+ -+#define PC_RHEL7_3_COMPAT \ -+ HW_COMPAT_RHEL7_3 \ -+ { /* PC_RHEL7_3_COMPAT from PC_COMPAT_2_8 */ \ -+ .driver = "kvmclock",\ -+ .property = "x-mach-use-reliable-get-clock",\ -+ .value = "off",\ -+ },\ -+ { /* PC_RHEL7_3_COMPAT from PC_COMPAT_2_7 */ \ -+ .driver = TYPE_X86_CPU,\ -+ .property = "l3-cache",\ -+ .value = "off",\ -+ },\ -+ { /* PC_RHEL7_3_COMPAT from PC_COMPAT_2_7 */ \ -+ .driver = TYPE_X86_CPU,\ -+ .property = "full-cpuid-auto-level",\ -+ .value = "off",\ -+ },\ -+ { /* PC_RHEL7_3_COMPAT from PC_COMPAT_2_7 */ \ -+ .driver = "Opteron_G3" "-" TYPE_X86_CPU,\ -+ .property = "family",\ -+ .value = "15",\ -+ },\ -+ { /* PC_RHEL7_3_COMPAT from PC_COMPAT_2_7 */ \ -+ .driver = "Opteron_G3" "-" TYPE_X86_CPU,\ -+ .property = "model",\ -+ .value = "6",\ -+ },\ -+ { /* PC_RHEL7_3_COMPAT from PC_COMPAT_2_7 */ \ -+ .driver = "Opteron_G3" "-" TYPE_X86_CPU,\ -+ .property = "stepping",\ -+ .value = "1",\ -+ },\ -+ { /* PC_RHEL7_3_COMPAT from PC_COMPAT_2_7 */ \ -+ .driver = "isa-pcspk",\ -+ .property = "migrate",\ -+ .value = "off",\ -+ },\ -+ { /* PC_RHEL7_3_COMPAT from PC_COMPAT_2_6 */ \ -+ .driver = TYPE_X86_CPU,\ -+ .property = "cpuid-0xb",\ -+ .value = "off",\ -+ },\ -+ { /* PC_RHEL7_3_COMPAT from PC_COMPAT_2_8 */ \ -+ .driver = "ICH9-LPC",\ -+ .property = "x-smi-broadcast",\ -+ .value = "off",\ -+ },\ -+ { /* PC_RHEL7_3_COMPAT from PC_COMPAT_2_8 */ \ -+ .driver = TYPE_X86_CPU,\ -+ .property = "vmware-cpuid-freq",\ -+ .value = "off",\ -+ },\ -+ { /* PC_RHEL7_3_COMPAT from PC_COMPAT_2_8 */ \ -+ .driver = "Haswell-" TYPE_X86_CPU,\ -+ .property = "stepping",\ -+ .value = "1",\ -+ },\ -+ { /* PC_RHEL7_3_COMPAT from PC_COMPAT_2_3 added in 2.9 */ \ -+ .driver = TYPE_X86_CPU,\ -+ .property = "kvm-no-smi-migration",\ -+ .value = "on",\ -+ }, -+ -+#define PC_RHEL7_2_COMPAT \ -+ HW_COMPAT_RHEL7_2 \ -+ {\ -+ .driver = "phenom" "-" TYPE_X86_CPU,\ -+ .property = "rdtscp",\ -+ .value = "off",\ -+ },\ -+ { /* PC_RHEL7_2_COMPAT */ \ -+ .driver = "qemu64" "-" TYPE_X86_CPU,\ -+ .property = "sse4a",\ -+ .value = "on",\ -+ },\ -+ { /* PC_RHEL7_2_COMPAT */ \ -+ .driver = "qemu64" "-" TYPE_X86_CPU,\ -+ .property = "abm",\ -+ .value = "on",\ -+ },\ -+ { /* PC_RHEL7_2_COMPAT */ \ -+ .driver = "Haswell-" TYPE_X86_CPU,\ -+ .property = "abm",\ -+ .value = "off",\ -+ },\ -+ { /* PC_RHEL7_2_COMPAT */ \ -+ .driver = "Haswell-noTSX-" TYPE_X86_CPU,\ -+ .property = "abm",\ -+ .value = "off",\ -+ },\ -+ { /* PC_RHEL7_2_COMPAT */ \ -+ .driver = "Broadwell-" TYPE_X86_CPU,\ -+ .property = "abm",\ -+ .value = "off",\ -+ },\ -+ { /* PC_RHEL7_2_COMPAT */ \ -+ .driver = "Broadwell-noTSX-" TYPE_X86_CPU,\ -+ .property = "abm",\ -+ .value = "off",\ -+ },\ -+ { /* PC_RHEL7_2_COMPAT */ \ -+ .driver = "host" "-" TYPE_X86_CPU,\ -+ .property = "host-cache-info",\ -+ .value = "on",\ -+ },\ -+ { /* PC_RHEL7_2_COMPAT */ \ -+ .driver = TYPE_X86_CPU,\ -+ .property = "check",\ -+ .value = "off",\ -+ },\ -+ { /* PC_RHEL7_2_COMPAT */ \ -+ .driver = "qemu32" "-" TYPE_X86_CPU,\ -+ .property = "popcnt",\ -+ .value = "on",\ -+ },\ -+ { /* PC_RHEL7_2_COMPAT */ \ -+ .driver = TYPE_X86_CPU,\ -+ .property = "arat",\ -+ .value = "off",\ -+ },\ -+ { /* PC_RHEL7_2_COMPAT */ \ -+ .driver = "usb-redir",\ -+ .property = "streams",\ -+ .value = "off",\ -+ },\ -+ { /* PC_RHEL7_2_COMPAT */ \ -+ .driver = TYPE_X86_CPU,\ -+ .property = "fill-mtrr-mask",\ -+ .value = "off",\ -+ },\ -+ { /* PC_RHEL7_2_COMPAT */ \ -+ .driver = "apic-common",\ -+ .property = "legacy-instance-id",\ -+ .value = "on",\ -+ }, -+ -+ -+ -+#define PC_RHEL7_1_COMPAT \ -+ HW_COMPAT_RHEL7_1 \ -+ {\ -+ .driver = "kvm64" "-" TYPE_X86_CPU,\ -+ .property = "vme",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = "kvm32" "-" TYPE_X86_CPU,\ -+ .property = "vme",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = "Conroe" "-" TYPE_X86_CPU,\ -+ .property = "vme",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = "Penryn" "-" TYPE_X86_CPU,\ -+ .property = "vme",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = "Nehalem" "-" TYPE_X86_CPU,\ -+ .property = "vme",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = "Westmere" "-" TYPE_X86_CPU,\ -+ .property = "vme",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = "SandyBridge" "-" TYPE_X86_CPU,\ -+ .property = "vme",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = "Haswell" "-" TYPE_X86_CPU,\ -+ .property = "vme",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = "Broadwell" "-" TYPE_X86_CPU,\ -+ .property = "vme",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = "Opteron_G1" "-" TYPE_X86_CPU,\ -+ .property = "vme",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = "Opteron_G2" "-" TYPE_X86_CPU,\ -+ .property = "vme",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = "Opteron_G3" "-" TYPE_X86_CPU,\ -+ .property = "vme",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = "Opteron_G4" "-" TYPE_X86_CPU,\ -+ .property = "vme",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = "Opteron_G5" "-" TYPE_X86_CPU,\ -+ .property = "vme",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = "Haswell" "-" TYPE_X86_CPU,\ -+ .property = "f16c",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = "Haswell" "-" TYPE_X86_CPU,\ -+ .property = "rdrand",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = "Broadwell" "-" TYPE_X86_CPU,\ -+ .property = "f16c",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = "Broadwell" "-" TYPE_X86_CPU,\ -+ .property = "rdrand",\ -+ .value = "off",\ -+ },\ -+ {\ -+ .driver = "coreduo" "-" TYPE_X86_CPU,\ -+ .property = "vmx",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "core2duo" "-" TYPE_X86_CPU,\ -+ .property = "vmx",\ -+ .value = "on",\ -+ },\ -+ { /* PC_RHEL7_1_COMPAT */ \ -+ .driver = "qemu64" "-" TYPE_X86_CPU,\ -+ .property = "min-level",\ -+ .value = stringify(4),\ -+ },{ /* PC_RHEL7_1_COMPAT */ \ -+ .driver = "kvm64" "-" TYPE_X86_CPU,\ -+ .property = "min-level",\ -+ .value = stringify(5),\ -+ },{ /* PC_RHEL7_1_COMPAT */ \ -+ .driver = "pentium3" "-" TYPE_X86_CPU,\ -+ .property = "min-level",\ -+ .value = stringify(2),\ -+ },{ /* PC_RHEL7_1_COMPAT */ \ -+ .driver = "n270" "-" TYPE_X86_CPU,\ -+ .property = "min-level",\ -+ .value = stringify(5),\ -+ },{ /* PC_RHEL7_1_COMPAT */ \ -+ .driver = "Conroe" "-" TYPE_X86_CPU,\ -+ .property = "min-level",\ -+ .value = stringify(4),\ -+ },{ /* PC_RHEL7_1_COMPAT */ \ -+ .driver = "Penryn" "-" TYPE_X86_CPU,\ -+ .property = "min-level",\ -+ .value = stringify(4),\ -+ },{ /* PC_RHEL7_1_COMPAT */ \ -+ .driver = "Nehalem" "-" TYPE_X86_CPU,\ -+ .property = "min-level",\ -+ .value = stringify(4),\ -+ },{ /* PC_RHEL7_1_COMPAT */ \ -+ .driver = "n270" "-" TYPE_X86_CPU,\ -+ .property = "min-xlevel",\ -+ .value = stringify(0x8000000a),\ -+ },{ /* PC_RHEL7_1_COMPAT */ \ -+ .driver = "Penryn" "-" TYPE_X86_CPU,\ -+ .property = "min-xlevel",\ -+ .value = stringify(0x8000000a),\ -+ },{ /* PC_RHEL7_1_COMPAT */ \ -+ .driver = "Conroe" "-" TYPE_X86_CPU,\ -+ .property = "min-xlevel",\ -+ .value = stringify(0x8000000a),\ -+ },{ /* PC_RHEL7_1_COMPAT */ \ -+ .driver = "Nehalem" "-" TYPE_X86_CPU,\ -+ .property = "min-xlevel",\ -+ .value = stringify(0x8000000a),\ -+ },{ /* PC_RHEL7_1_COMPAT */ \ -+ .driver = "Westmere" "-" TYPE_X86_CPU,\ -+ .property = "min-xlevel",\ -+ .value = stringify(0x8000000a),\ -+ },{ /* PC_RHEL7_1_COMPAT */ \ -+ .driver = "SandyBridge" "-" TYPE_X86_CPU,\ -+ .property = "min-xlevel",\ -+ .value = stringify(0x8000000a),\ -+ },{ /* PC_RHEL7_1_COMPAT */ \ -+ .driver = "IvyBridge" "-" TYPE_X86_CPU,\ -+ .property = "min-xlevel",\ -+ .value = stringify(0x8000000a),\ -+ },{ /* PC_RHEL7_1_COMPAT */ \ -+ .driver = "Haswell" "-" TYPE_X86_CPU,\ -+ .property = "min-xlevel",\ -+ .value = stringify(0x8000000a),\ -+ },{ /* PC_RHEL7_1_COMPAT */ \ -+ .driver = "Haswell-noTSX" "-" TYPE_X86_CPU,\ -+ .property = "min-xlevel",\ -+ .value = stringify(0x8000000a),\ -+ },{ /* PC_RHEL7_1_COMPAT */ \ -+ .driver = "Broadwell" "-" TYPE_X86_CPU,\ -+ .property = "min-xlevel",\ -+ .value = stringify(0x8000000a),\ -+ },{ /* PC_RHEL7_1_COMPAT */ \ -+ .driver = "Broadwell-noTSX" "-" TYPE_X86_CPU,\ -+ .property = "min-xlevel",\ -+ .value = stringify(0x8000000a),\ -+ }, -+ -+/* -+ * The PC_RHEL_*_COMPAT serve the same purpose for RHEL-7 machine -+ * types as the PC_COMPAT_* do for upstream types. -+ * PC_RHEL_7_*_COMPAT apply both to i440fx and q35 types. -+ * PC_RHEL6_*_COMPAT apply to i440fx types only, and therefore live -+ * in pc_piix.c. -+ */ -+ -+/* -+ * RHEL-7 is based on QEMU 1.5.3, so this needs the PC_COMPAT_* -+ * between our base and 1.5, less stuff backported to RHEL-7.0 -+ * (usb-device.msos-desc), less stuff for devices we changed -+ * (qemu64-x86_64-cpu) or don't support (hpet, pci-serial-2x, -+ * pci-serial-4x) in 7.0. -+ */ -+#define PC_RHEL7_0_COMPAT \ -+ {\ -+ .driver = "virtio-scsi-pci",\ -+ .property = "any_layout",\ -+ .value = "off",\ -+ },{\ -+ .driver = "PIIX4_PM",\ -+ .property = "memory-hotplug-support",\ -+ .value = "off",\ -+ },{\ -+ .driver = "apic",\ -+ .property = "version",\ -+ .value = stringify(0x11),\ -+ },{\ -+ .driver = "nec-usb-xhci",\ -+ .property = "superspeed-ports-first",\ -+ .value = "off",\ -+ },{\ -+ .driver = "nec-usb-xhci",\ -+ .property = "force-pcie-endcap",\ -+ .value = "on",\ -+ },{\ -+ .driver = "pci-serial",\ -+ .property = "prog_if",\ -+ .value = stringify(0),\ -+ },{\ -+ .driver = "virtio-net-pci",\ -+ .property = "guest_announce",\ -+ .value = "off",\ -+ },{\ -+ .driver = "ICH9-LPC",\ -+ .property = "memory-hotplug-support",\ -+ .value = "off",\ -+ },{\ -+ .driver = "xio3130-downstream",\ -+ .property = COMPAT_PROP_PCP,\ -+ .value = "off",\ -+ },{\ -+ .driver = "ioh3420",\ -+ .property = COMPAT_PROP_PCP,\ -+ .value = "off",\ -+ },{\ -+ .driver = "PIIX4_PM",\ -+ .property = "acpi-pci-hotplug-with-bridge-support",\ -+ .value = "off",\ -+ },{\ -+ .driver = "e1000",\ -+ .property = "mitigation",\ -+ .value = "off",\ -+ },{ \ -+ .driver = "virtio-net-pci", \ -+ .property = "ctrl_guest_offloads", \ -+ .value = "off", \ -+ },\ -+ {\ -+ .driver = "Conroe" "-" TYPE_X86_CPU,\ -+ .property = "x2apic",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "Penryn" "-" TYPE_X86_CPU,\ -+ .property = "x2apic",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "Nehalem" "-" TYPE_X86_CPU,\ -+ .property = "x2apic",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "Westmere" "-" TYPE_X86_CPU,\ -+ .property = "x2apic",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "Opteron_G1" "-" TYPE_X86_CPU,\ -+ .property = "x2apic",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "Opteron_G2" "-" TYPE_X86_CPU,\ -+ .property = "x2apic",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "Opteron_G3" "-" TYPE_X86_CPU,\ -+ .property = "x2apic",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "Opteron_G4" "-" TYPE_X86_CPU,\ -+ .property = "x2apic",\ -+ .value = "on",\ -+ },\ -+ {\ -+ .driver = "Opteron_G5" "-" TYPE_X86_CPU,\ -+ .property = "x2apic",\ -+ .value = "on",\ -+ }, - #endif -diff --git a/include/hw/usb.h b/include/hw/usb.h -index eb28655..e2d3d77 100644 ---- a/include/hw/usb.h -+++ b/include/hw/usb.h -@@ -608,4 +608,11 @@ int usb_get_quirks(uint16_t vendor_id, uint16_t product_id, - uint8_t interface_class, uint8_t interface_subclass, - uint8_t interface_protocol); - -+ -+/* hcd-uhci.c -- RHEL-6 machine type compatibility */ -+extern bool ich9_uhci123_irqpin_override; -+ -+/* hcd-xhci.c -- rhel7.0.0 machine type compatibility */ -+extern bool migrate_cve_2014_5263_xhci_fields; -+ - #endif -diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h -index 80c45c3..5faa359 100644 ---- a/include/hw/virtio/virtio.h -+++ b/include/hw/virtio/virtio.h -@@ -95,6 +95,7 @@ struct VirtIODevice - uint8_t device_endian; - bool use_guest_notifier_mask; - AddressSpace *dma_as; -+ bool rhel6_ctrl_guest_workaround; - QLIST_HEAD(, VirtQueue) *vector_queues; - }; - -diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h -index b213696..9caaacf 100644 ---- a/include/sysemu/sysemu.h -+++ b/include/sysemu/sysemu.h -@@ -92,6 +92,8 @@ void qemu_add_machine_init_done_notifier(Notifier *notify); - void qemu_remove_machine_init_done_notifier(Notifier *notify); - - void qemu_announce_self(void); -+extern bool shadow_bios_after_incoming; -+void shadow_bios(void); - - extern int autostart; - -diff --git a/migration/migration.c b/migration/migration.c -index c3fe0ed..c7b4d3d 100644 ---- a/migration/migration.c -+++ b/migration/migration.c -@@ -96,6 +96,8 @@ enum mig_rp_message_type { - MIG_RP_MSG_MAX - }; - -+bool migrate_pre_2_2; -+ - /* When we add fault tolerance, we could have several - migrations at once. For now we don't need to add - dynamic creation of migration */ -diff --git a/migration/migration.h b/migration/migration.h -index 148c9fa..8771ab0 100644 ---- a/migration/migration.h -+++ b/migration/migration.h -@@ -193,4 +193,10 @@ void migrate_send_rp_pong(MigrationIncomingState *mis, - void migrate_send_rp_req_pages(MigrationIncomingState *mis, const char* rbname, - ram_addr_t start, size_t len); - -+/* -+ * Disables a load of subsections that were added in 2.2/rh7.2 for backwards -+ * migration compatibility. -+ */ -+extern bool migrate_pre_2_2; -+ - #endif -diff --git a/migration/savevm.c b/migration/savevm.c -index fdd15fa..5eb3504 100644 ---- a/migration/savevm.c -+++ b/migration/savevm.c -@@ -42,6 +42,7 @@ - #include "postcopy-ram.h" - #include "qapi/qmp/qerror.h" - #include "qemu/error-report.h" -+#include "qemu/rcu_queue.h" - #include "sysemu/cpus.h" - #include "exec/memory.h" - #include "exec/target_page.h" -@@ -80,6 +81,7 @@ enum qemu_vm_cmd { - MIG_CMD_PACKAGED, /* Send a wrapped stream within this stream */ - MIG_CMD_MAX - }; -+bool shadow_bios_after_incoming; - - #define MAX_VM_CMD_PACKAGED_SIZE (1ul << 24) - static struct mig_cmd_args { -@@ -2079,6 +2081,13 @@ int qemu_loadvm_state(QEMUFile *f) - } - - qemu_loadvm_state_cleanup(); -+ /* Supplement SeaBIOS's shadowing now, because it was useless when the -+ * incoming VM started on the RHEL-6 emulator. -+ */ -+ if (shadow_bios_after_incoming) { -+ shadow_bios(); -+ } -+ - cpu_synchronize_all_post_init(); - - return ret; -diff --git a/numa.c b/numa.c -index e32af04..be78167 100644 ---- a/numa.c -+++ b/numa.c -@@ -566,6 +566,19 @@ void memory_region_allocate_system_memory(MemoryRegion *mr, Object *owner, - return; - } - -+ /* The shadow_bios_after_incoming hack at savevm.c:shadow_bios() is not -+ * able to handle the multiple memory blocks added when using NUMA -+ * memdevs. We can disallow -numa memdev= when using rhel6.* machine-types -+ * because RHEL-6 didn't support the NUMA memdev option. -+ */ -+ if (shadow_bios_after_incoming) { -+ MachineClass *mc; -+ mc = MACHINE_GET_CLASS(current_machine); -+ error_report("-numa memdev is not supported by machine %s", -+ mc->name); -+ exit(1); -+ } -+ - memory_region_init(mr, owner, name, ram_size); - for (i = 0; i < MAX_NODES; i++) { - uint64_t size = numa_info[i].node_mem; -diff --git a/qdev-monitor.c b/qdev-monitor.c -index 8fd6df9..b05ae6d 100644 ---- a/qdev-monitor.c -+++ b/qdev-monitor.c -@@ -44,7 +44,6 @@ typedef struct QDevAlias - - /* Please keep this table sorted by typename. */ - static const QDevAlias qdev_alias_table[] = { -- { "e1000", "e1000-82540em" }, - { "ich9-ahci", "ahci" }, - { "kvm-pci-assign", "pci-assign" }, - { "lsi53c895a", "lsi" }, -diff --git a/scripts/vmstate-static-checker.py b/scripts/vmstate-static-checker.py -index bcef7ee..ffb13d1 100755 ---- a/scripts/vmstate-static-checker.py -+++ b/scripts/vmstate-static-checker.py -@@ -104,7 +104,6 @@ def get_changed_sec_name(sec): - # Section names can change -- see commit 292b1634 for an example. - changes = { - "ICH9 LPC": "ICH9-LPC", -- "e1000-82540em": "e1000", - } - - for item in changes: -diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs -index e69c217..b24da3b 100644 ---- a/stubs/Makefile.objs -+++ b/stubs/Makefile.objs -@@ -40,3 +40,4 @@ stub-obj-y += pc_madt_cpu_entry.o - stub-obj-y += vmgenid.o - stub-obj-y += xen-common.o - stub-obj-y += xen-hvm.o -+stub-obj-y += shadow-bios.o -diff --git a/stubs/shadow-bios.c b/stubs/shadow-bios.c -new file mode 100644 -index 0000000..c77cd7a ---- /dev/null -+++ b/stubs/shadow-bios.c -@@ -0,0 +1,7 @@ -+#include "qemu/osdep.h" -+#include "sysemu/sysemu.h" -+ -+void shadow_bios(void) -+{ -+ abort(); -+} -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index ddc45ab..7f52680 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -754,20 +754,29 @@ struct X86CPUDefinition { - - static X86CPUDefinition builtin_x86_defs[] = { - { -+ /* qemu64 is the default CPU model for all *-rhel7.* machine-types. -+ * The default on RHEL-6 was cpu64-rhel6. -+ * libvirt assumes that qemu64 is the default for _all_ machine-types, -+ * so we should try to keep qemu64 and cpu64-rhel6 as similar as -+ * possible. -+ */ - .name = "qemu64", - .level = 0xd, - .vendor = CPUID_VENDOR_AMD, - .family = 6, -- .model = 6, -+ .model = 13, - .stepping = 3, -- .features[FEAT_1_EDX] = -- PPRO_FEATURES | -- CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | -- CPUID_PSE36, -- .features[FEAT_1_ECX] = -- CPUID_EXT_SSE3 | CPUID_EXT_CX16, -- .features[FEAT_8000_0001_EDX] = -- CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX, -+ .features[FEAT_1_EDX] = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | -+ CPUID_MMX | CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | -+ CPUID_MCA | CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | -+ CPUID_CX8 | CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | -+ CPUID_PSE | CPUID_DE | CPUID_FP87, -+ .features[FEAT_1_ECX] = CPUID_EXT_CX16 | CPUID_EXT_SSE3, -+ .features[FEAT_8000_0001_EDX] = CPUID_EXT2_LM | CPUID_EXT2_FXSR | -+ CPUID_EXT2_MMX | CPUID_EXT2_NX | CPUID_EXT2_PAT | CPUID_EXT2_CMOV | -+ CPUID_EXT2_PGE | CPUID_EXT2_SYSCALL | CPUID_EXT2_APIC | -+ CPUID_EXT2_CX8 | CPUID_EXT2_MCE | CPUID_EXT2_PAE | CPUID_EXT2_MSR | CPUID_EXT2_TSC | -+ CPUID_EXT2_PSE | CPUID_EXT2_DE | CPUID_EXT2_FPU, - .features[FEAT_8000_0001_ECX] = - CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM, - .xlevel = 0x8000000A, -@@ -993,6 +1002,29 @@ static X86CPUDefinition builtin_x86_defs[] = { - .model_id = "Intel(R) Atom(TM) CPU N270 @ 1.60GHz", - }, - { -+ .name = "cpu64-rhel6", -+ .level = 4, -+ .vendor = CPUID_VENDOR_AMD, -+ .family = 6, -+ .model = 13, -+ .stepping = 3, -+ .features[FEAT_1_EDX] = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | -+ CPUID_MMX | CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | -+ CPUID_MCA | CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | -+ CPUID_CX8 | CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | -+ CPUID_PSE | CPUID_DE | CPUID_FP87, -+ .features[FEAT_1_ECX] = CPUID_EXT_CX16 | CPUID_EXT_SSE3, -+ .features[FEAT_8000_0001_EDX] = CPUID_EXT2_LM | CPUID_EXT2_FXSR | -+ CPUID_EXT2_MMX | CPUID_EXT2_NX | CPUID_EXT2_PAT | CPUID_EXT2_CMOV | -+ CPUID_EXT2_PGE | CPUID_EXT2_SYSCALL | CPUID_EXT2_APIC | -+ CPUID_EXT2_CX8 | CPUID_EXT2_MCE | CPUID_EXT2_PAE | CPUID_EXT2_MSR | CPUID_EXT2_TSC | -+ CPUID_EXT2_PSE | CPUID_EXT2_DE | CPUID_EXT2_FPU, -+ .features[FEAT_8000_0001_ECX] = CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | -+ CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM, -+ .xlevel = 0x8000000A, -+ .model_id = "QEMU Virtual CPU version (cpu64-rhel6)", -+ }, -+ { - .name = "Conroe", - .level = 10, - .vendor = CPUID_VENDOR_INTEL, -@@ -1542,6 +1574,7 @@ static PropValue kvm_default_props[] = { - { "acpi", "off" }, - { "monitor", "off" }, - { "svm", "off" }, -+ { "kvm-pv-unhalt", "on" }, - { NULL, NULL }, - }; - -diff --git a/target/i386/machine.c b/target/i386/machine.c -index eab3372..6156626 100644 ---- a/target/i386/machine.c -+++ b/target/i386/machine.c -@@ -818,6 +818,26 @@ static const VMStateDescription vmstate_mcg_ext_ctl = { - } - }; - -+static bool vmstate_xsave_needed(void *opaque) -+{ -+ /* The xsave state is already on the main "cpu" section */ -+ return false; -+} -+ -+static const VMStateDescription vmstate_xsave ={ -+ .name = "cpu/xsave", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .minimum_version_id_old = 1, -+ .needed = vmstate_xsave_needed, -+ .fields = (VMStateField []) { -+ VMSTATE_UINT64_V(env.xcr0, X86CPU, 1), -+ VMSTATE_UINT64_V(env.xstate_bv, X86CPU, 1), -+ VMSTATE_YMMH_REGS_VARS(env.xmm_regs, X86CPU, CPU_NB_REGS, 1), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ - VMStateDescription vmstate_x86_cpu = { - .name = "cpu", - .version_id = 12, -@@ -937,6 +957,7 @@ VMStateDescription vmstate_x86_cpu = { - &vmstate_pkru, - #endif - &vmstate_mcg_ext_ctl, -+ &vmstate_xsave, - NULL - } - }; --- -1.8.3.1 - diff --git a/SOURCES/0003-Initial-redhat-build.patch b/SOURCES/0003-Initial-redhat-build.patch new file mode 100644 index 0000000..8da937f --- /dev/null +++ b/SOURCES/0003-Initial-redhat-build.patch @@ -0,0 +1,1015 @@ +From ec05305843e6fb1cf3a8bc1dfab7b7e3d9edce4e Mon Sep 17 00:00:00 2001 +From: Miroslav Rezanina +Date: Mon, 11 Sep 2017 07:11:00 +0200 +Subject: Initial redhat build + +This patch introduces redhat build structure in redhat subdirectory. In addition, +several issues are fixed in QEMU tree: + +- Change of app name for sasl_server_init in VNC code from qemu to qemu-kvm + - As we use qemu-kvm as name in all places, this is updated to be consistent +- Man page renamed from qemu to qemu-kvm + - man page is installed using make install so we have to fix it in qemu tree +- Added live-block-migration configuration option support + - Downstream differentiation support +- Use "/share/qemu-kvm" as SHARE_SUFFIX + - We reconfigured our share to qemu-kvm to be consistent with used name +- Added .gitpublish configuration file + - Support for git publish has to be stored in repository root + +-- +Rebase notes (2.12.0): +- Not packaging hppa-firmware.img +- Disable vxhs.o in block/Makefile.obj +- Disable ppc64 builds +- Removed acpi-dsdt.aml (upstream) + +Rebase notes (2.11.0): +- Removed --with-pixman configure option (upstream) +- Disabled multipath for qemu-pr-helper (unsupported API) +- null-co whitelisting moved to this patch +- make check enabled +- conditionaly disable query-block-jobs for qmp-test.c + +Rebase notes (2.10.0): +- live_block_migration option added upstream +- moved qmp-spec.txt file (upstream) +- added s390-netboot.img (added upstream) +- removed qemu_vga.ndrv (added upstream) +- switch to (rhevh-)rhel-7.5-candidate +- switched differentiation defaults +- moved binary files to separate commit + +Rebase notes (2.9.0): +- documentation files handling changes (upstrem) +- removed --enable-colo option and --disable-archipelago (upstream) +- bump BuildRequires versions +- new mandatory argument for tracetool.py (upstream) +- updated RHEL 6 roms +- switch from sha1sum to sha256sum +- Moved adding rhel6-e1000.rom from machine types commit +- Moved adding pxe-e1000e.rom from device disable commit +- Use rdma-core instead of librdmacm +- Add upstream tarballs tar.xz to .gitignore +- Updated git-backport-diff script + +Rebase notes (2.8.0): +- removed vhdx option (upstream) +- qemu-tech.html merged to qemu-doc.html (upstream) +- removed skiboot.lid firmware +- Changed tracetool.py parameters +- Added support for easy z-stream switch + +Rebase notes (2.7.0): +- removed kvm_stat +- added efi-e1000e.rom +- added efi-vmxnet.rom +- added linuxboot_dma.bin +- trace-events renamed to trace-events-all +- reverted dependency to seccomp on aarch64 +- Add ipxe-qemu-roms ad build dependency to pass tests + +Rebase notes (2.6.0): +- removed q35-acpi-dsdt.aml +- add enable-gcrypt option + +Rebase notes (2.5.0): +- New seccomp hadling in configure +- New condition format in migration/migration.c +- libcacard extracted +- vnc fixes +- libsecomp for aarch64 requirements changed downstream + +Rebase notes (2.4.0): +- remove --enable-ws-vnc +- use error_setg instead of error_set in migration/migration.c +- remove target-x86_64.conf +- create /etc/qemu-kvm on copying of bridge.conf +- disabled opengl +- rebased to version 2.3.0-30.el7 + +Merged patches (rebase 2.11.0) +- ce6e8e5b8a redhat/qemu-kvm.spec.template: Enable seccomp on s390x, too +- 8629f208c6 redhat: Remove qemu.binfmt from the downstream repository +- b889ce1c40 Disable build of qemu-kvm-ma for x86_64 +- 4506913c42 redhat: add CONFIG_RHV flag +- 21ecaec46f s390x: vm.allocate_pgste sysctl is no longer needed +- 78a1864d99 Update build_configure for 2.10.0 options +- decf881320 redhat: Provide s390x specific /etc/modprobe.d/kvm.conf +- e0cd3138cc redhat/qemu-kvm.spec: Use the freshly built s390-ccw.img firmware image +- 7af6b9a4fa redhat: install generic kvm.conf except for s390 and x86 architectures +- c4290f50bb redhat: fix rh-srpm target +- 8943f52e8b Package qemu-block-drivers manpage +- 88b41044d6 update spec to build and install qemu-pr-helper +- 34ca391 redhat: Fix permissions of /dev/kvm on a freshly booted s390x system + +Merged patches (rebase 2.10.0) +- feefd46 qemu-kvm.spec: Enable s390x build +- 985051e Removing texi2html from build requirements +- 7c64a2a Update ignore files for redhat usage +- 8f9a95a Disable replication feature +- 1b7bbc5 block/vxhs: modularize VXHS via g_module +- 7511527 Remove the dependencies to seavgabios-bin and ipxe-roms-qemu on s390x +- aa0891c Downstream: Don't disable SMT on POWER9 hosts +- a13a0e9 Update configuration for qemu 2.9 +- bbf46dd disable pulseaudio and alsa +- 9124839 redhat/Makefile: honor BREW_FLAGS like the kernel +- 53c03bd copy SLIT test reference blobs into tests directory +- c4c77e6 Differentiation support +- f1ec0e8 configure: allow to disable VT-d emulation +- b972023 Disable VT-d for rhel builds +- 29a0414 RHEL Diff.: Add option in configure to disable live block ops +- 1f33b29 RHEL Diff.: Unregister live block operations +- c590551 RHEL Diff.: Disable live block operations in HMP monitor +- c7e208f RHEL Diff.: Add rpm spec options for live block ops +- 733af5c pegas: add rpm spec options for vhost-user +- ff16138 Add support for local build +- fb426d4 qemu-kvm.spec: Configure vm.allocate_pgste for s390x + +Merged patches (rebase 2.9.0) +- 9c7ab94 Enable seccomp for ppc64/ppc64le architecture +- f6d7e9d Update qemu-kvm package Summary and Description +- a9e55b6 Disable usbredir and libcacard for unsupported architectures +- 0218220 Update configuration for 2.8.0 release + +Merged patches (rebase 2.7.0) +- 2be6077 Fix SLOF dependency +- dc58590 spec: Remove dependency to ipxe-roms-qemu for aarch64 +- 357ef43 spec: link sgabios.bin only for x86_64 +- 08d82cc spec: Update rules before triggering for kvm device +- 8980a76 spec: Do not package ivshmem-server and ivshmem-client +- 027067c spec: add a sample kvm.conf to enable Nested Virtualization +- ba2ba30 Adjust locked memory limits to allow unprivileged VMs on Power +- e9740b0 Increase locked memory limit for all users, not just kvm group +- 8c301be add vgabios-virtio.bin symlink +- 4d03723 usb: enable streams support +- 2a9363e Add install dependency required for usb streams +- 9a54442 Add dump-guest-memory.py to all archs +- 73fffc9 add e1000e ipxe rom symlink +- aaaa2a9 Add 'luks' to block driver whitelist +- c78c3a8 redhat: switch from gcrypt to nettle for crypto +- bb51a69 redhat: include username and date in RPM N-E-V-R for scratch builds +- 21ecaec s390x: vm.allocate_pgste sysctl is no longer needed +- 78a1864 Update build_configure for 2.10.0 options + +Merged patches (rebase 2.4.0) +- 9201274 spec: Remove obsolete differentiation code +- a938a8c spec: Use external configuration script +- 5ca8d0e spec: Use configure options to prevent default resolution +- 5dca391 spec: Ship complete QMP documentation files +- 7899edd aarch64: allow --enable-seccomp +- a56fb9c aarch64: redhat spec: enable seccomp +- a9571e6 rhel: Update package version for SLOF dependency +- 25c70c4 configure: Add support for tcmalloc +- db72485 Change fsreeze-hook default location +- 14b8a9e redhat: add kvm-unit-tests tarball to environment +- 5ee4238 spec: Build tscdeadline_latency.flat from kvm-unit-tests +- 6ba800b Downstream-only: Start kvm-setup service before libvirtd service +- 59b43d6 Do not stop qemu-guest-agent service on target switch +- 4d851fa provide vhost module config file with max_mem_regions set to 509 +- 0b18027 spec: Require proper version of SLOF +- 3c436c7 Fix rh-brew-aarch64, rh-brew-ppc rh-brew-ga-ppc target + +(cherry picked from commit ba7591ec4a0906121d15ffbf740580bd79ec5814) +(cherry picked from commit c984102495c0cee355158ecc382ad5e44b23b16c) + +Conflicts: + .gitpublish + configure + hw/i386/Makefile.objs + +(cherry picked from commit bea8f0ccd9fb65aefe7f19b3c4cc849c9e4c1bff) +(cherry picked from commit 7bb63d45c5ed63943718d60382c140fbbba270cb) +(cherry picked from commit a451d845da0e2f872b07ae57fd328adb8116f6cc) +(cherry picked from commit db5d48c968290ffc47ef8662d6ee1fece967acac) +--- + .gitignore | 1 + + .gitpublish | 65 +- + Makefile | 2 +- + block/Makefile.objs | 2 +- + block/vxhs.c | 122 +- + configure | 65 +- + hmp-commands-info.hx | 4 + + hmp-commands.hx | 12 + + hmp.c | 12 + + include/block/vxhs_shim.h | 143 + + monitor.c | 16 + + os-posix.c | 2 +- + redhat/.gitignore | 5 + + redhat/80-kvm.rules | 1 + + redhat/85-kvm.preset | 5 + + redhat/95-kvm-memlock.conf | 10 + + redhat/99-qemu-guest-agent.rules | 2 + + redhat/Makefile | 95 + + redhat/Makefile.common | 57 + + redhat/Makefile.local | 76 + + redhat/README.rhel6-gpxe-source | 9 + + redhat/bridge.conf | 1 + + redhat/build_configure.sh | 167 + + redhat/ksm.service | 13 + + redhat/ksm.sysconfig | 4 + + redhat/ksmctl.c | 77 + + redhat/ksmtuned | 138 + + redhat/ksmtuned.conf | 21 + + redhat/ksmtuned.service | 12 + + redhat/kvm-s390x.conf | 7 + + redhat/kvm-setup | 40 + + redhat/kvm-setup.service | 14 + + redhat/kvm-x86.conf | 12 + + redhat/kvm.conf | 3 + + redhat/kvm.modules | 21 + + redhat/qemu-ga.sysconfig | 19 + + redhat/qemu-guest-agent.service | 20 + + redhat/qemu-kvm.spec.template | 6903 ++++++++++++++++++++++++++++++++++++ + redhat/qemu-pr-helper.service | 15 + + redhat/qemu-pr-helper.socket | 9 + + redhat/rpmbuild/BUILD/.gitignore | 2 + + redhat/rpmbuild/RPMS/.gitignore | 2 + + redhat/rpmbuild/SOURCES/.gitignore | 2 + + redhat/rpmbuild/SPECS/.gitignore | 2 + + redhat/rpmbuild/SRPMS/.gitignore | 2 + + redhat/scripts/frh.py | 26 + + redhat/scripts/git-backport-diff | 327 ++ + redhat/scripts/git-compile-check | 215 ++ + redhat/scripts/process-patches.sh | 81 + + redhat/scripts/tarball_checksum.sh | 3 + + redhat/vhost.conf | 3 + + tests/qmp-test.c | 3 + + ui/vnc.c | 2 +- + 53 files changed, 8776 insertions(+), 96 deletions(-) + create mode 100644 include/block/vxhs_shim.h + create mode 100644 redhat/.gitignore + create mode 100644 redhat/80-kvm.rules + create mode 100644 redhat/85-kvm.preset + create mode 100644 redhat/95-kvm-memlock.conf + create mode 100644 redhat/99-qemu-guest-agent.rules + create mode 100644 redhat/Makefile + create mode 100644 redhat/Makefile.common + create mode 100644 redhat/Makefile.local + create mode 100644 redhat/README.rhel6-gpxe-source + create mode 100644 redhat/bridge.conf + create mode 100755 redhat/build_configure.sh + create mode 100644 redhat/ksm.service + create mode 100644 redhat/ksm.sysconfig + create mode 100644 redhat/ksmctl.c + create mode 100644 redhat/ksmtuned + create mode 100644 redhat/ksmtuned.conf + create mode 100644 redhat/ksmtuned.service + create mode 100644 redhat/kvm-s390x.conf + create mode 100644 redhat/kvm-setup + create mode 100644 redhat/kvm-setup.service + create mode 100644 redhat/kvm-x86.conf + create mode 100644 redhat/kvm.conf + create mode 100644 redhat/kvm.modules + create mode 100644 redhat/qemu-ga.sysconfig + create mode 100644 redhat/qemu-guest-agent.service + create mode 100644 redhat/qemu-kvm.spec.template + create mode 100644 redhat/qemu-pr-helper.service + create mode 100644 redhat/qemu-pr-helper.socket + create mode 100644 redhat/rpmbuild/BUILD/.gitignore + create mode 100644 redhat/rpmbuild/RPMS/.gitignore + create mode 100644 redhat/rpmbuild/SOURCES/.gitignore + create mode 100644 redhat/rpmbuild/SPECS/.gitignore + create mode 100644 redhat/rpmbuild/SRPMS/.gitignore + create mode 100755 redhat/scripts/frh.py + create mode 100755 redhat/scripts/git-backport-diff + create mode 100755 redhat/scripts/git-compile-check + create mode 100755 redhat/scripts/process-patches.sh + create mode 100755 redhat/scripts/tarball_checksum.sh + create mode 100644 redhat/vhost.conf + +diff --git a/Makefile b/Makefile +index d71dd5b..89ba4c5 100644 +--- a/Makefile ++++ b/Makefile +@@ -804,7 +804,7 @@ install-doc: $(DOCS) + $(INSTALL_DATA) docs/interop/qemu-qmp-ref.txt "$(DESTDIR)$(qemu_docdir)" + ifdef CONFIG_POSIX + $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1" +- $(INSTALL_DATA) qemu.1 "$(DESTDIR)$(mandir)/man1" ++ $(INSTALL_DATA) qemu.1 "$(DESTDIR)$(mandir)/man1/qemu-kvm.1" + $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man7" + $(INSTALL_DATA) docs/interop/qemu-qmp-ref.7 "$(DESTDIR)$(mandir)/man7" + $(INSTALL_DATA) docs/qemu-block-drivers.7 "$(DESTDIR)$(mandir)/man7" +diff --git a/block/Makefile.objs b/block/Makefile.objs +index d644bac..c0693fc 100644 +--- a/block/Makefile.objs ++++ b/block/Makefile.objs +@@ -20,7 +20,7 @@ block-obj-$(CONFIG_LIBNFS) += nfs.o + block-obj-$(CONFIG_CURL) += curl.o + block-obj-$(CONFIG_RBD) += rbd.o + block-obj-$(CONFIG_GLUSTERFS) += gluster.o +-block-obj-$(CONFIG_VXHS) += vxhs.o ++#block-obj-$(CONFIG_VXHS) += vxhs.o + block-obj-$(CONFIG_LIBSSH2) += ssh.o + block-obj-y += accounting.o dirty-bitmap.o + block-obj-y += write-threshold.o +diff --git a/block/vxhs.c b/block/vxhs.c +index 75cc6c8..a18154c 100644 +--- a/block/vxhs.c ++++ b/block/vxhs.c +@@ -9,7 +9,8 @@ + */ + + #include "qemu/osdep.h" +-#include ++#include "block/vxhs_shim.h" ++#include + #include + #include "block/block_int.h" + #include "qapi/qmp/qerror.h" +@@ -58,6 +59,96 @@ typedef struct BDRVVXHSState { + char *tlscredsid; /* tlscredsid */ + } BDRVVXHSState; + ++#define LIBVXHS_FULL_PATHNAME "/usr/lib64/qemu/libvxhs.so.1" ++static bool libvxhs_loaded; ++static GModule *libvxhs_handle; ++ ++static LibVXHSFuncs libvxhs; ++ ++typedef struct LibVXHSSymbols { ++ const char *name; ++ gpointer *addr; ++} LibVXHSSymbols; ++ ++static LibVXHSSymbols libvxhs_symbols[] = { ++ {"iio_init", (gpointer *) &libvxhs.iio_init}, ++ {"iio_fini", (gpointer *) &libvxhs.iio_fini}, ++ {"iio_min_version", (gpointer *) &libvxhs.iio_min_version}, ++ {"iio_max_version", (gpointer *) &libvxhs.iio_max_version}, ++ {"iio_open", (gpointer *) &libvxhs.iio_open}, ++ {"iio_close", (gpointer *) &libvxhs.iio_close}, ++ {"iio_writev", (gpointer *) &libvxhs.iio_writev}, ++ {"iio_readv", (gpointer *) &libvxhs.iio_readv}, ++ {"iio_ioctl", (gpointer *) &libvxhs.iio_ioctl}, ++ {NULL} ++}; ++ ++static void bdrv_vxhs_set_funcs(GModule *handle, Error **errp) ++{ ++ int i = 0; ++ while (libvxhs_symbols[i].name) { ++ const char *name = libvxhs_symbols[i].name; ++ if (!g_module_symbol(handle, name, libvxhs_symbols[i].addr)) { ++ error_setg(errp, "%s could not be loaded from libvxhs: %s", ++ name, g_module_error()); ++ return; ++ } ++ ++i; ++ } ++} ++ ++static void bdrv_vxhs_load_libs(Error **errp) ++{ ++ Error *local_err = NULL; ++ int32_t ver; ++ ++ if (libvxhs_loaded) { ++ return; ++ } ++ ++ if (!g_module_supported()) { ++ error_setg(errp, "modules are not supported on this platform: %s", ++ g_module_error()); ++ return; ++ } ++ ++ libvxhs_handle = g_module_open(LIBVXHS_FULL_PATHNAME, ++ G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); ++ if (!libvxhs_handle) { ++ error_setg(errp, "error loading libvxhs: %s", g_module_error()); ++ return; ++ } ++ ++ g_module_make_resident(libvxhs_handle); ++ ++ bdrv_vxhs_set_funcs(libvxhs_handle, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; ++ } ++ ++ /* Now check to see if the libvxhs we are using here is supported ++ * by the loaded version */ ++ ++ ver = (*libvxhs.iio_min_version)(); ++ if (ver > QNIO_VERSION) { ++ error_setg(errp, "Trying to use libvxhs version %"PRId32" API, but " ++ "only %"PRId32" or newer is supported by %s", ++ QNIO_VERSION, ver, LIBVXHS_FULL_PATHNAME); ++ return; ++ } ++ ++ ver = (*libvxhs.iio_max_version)(); ++ if (ver < QNIO_VERSION) { ++ error_setg(errp, "Trying to use libvxhs version %"PRId32" API, but " ++ "only %"PRId32" or earlier is supported by %s", ++ QNIO_VERSION, ver, LIBVXHS_FULL_PATHNAME); ++ return; ++ } ++ ++ libvxhs_loaded = true; ++} ++ + static void vxhs_complete_aio_bh(void *opaque) + { + VXHSAIOCB *acb = opaque; +@@ -219,7 +310,7 @@ static void vxhs_parse_filename(const char *filename, QDict *options, + static int vxhs_init_and_ref(void) + { + if (vxhs_ref++ == 0) { +- if (iio_init(QNIO_VERSION, vxhs_iio_callback)) { ++ if ((*libvxhs.iio_init)(QNIO_VERSION, vxhs_iio_callback)) { + return -ENODEV; + } + } +@@ -229,7 +320,7 @@ static int vxhs_init_and_ref(void) + static void vxhs_unref(void) + { + if (--vxhs_ref == 0) { +- iio_fini(); ++ (*libvxhs.iio_fini)(); + } + } + +@@ -299,8 +390,17 @@ static int vxhs_open(BlockDriverState *bs, QDict *options, + char *client_key = NULL; + char *client_cert = NULL; + ++ bdrv_vxhs_load_libs(&local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ /* on error, cannot cleanup because the iio_fini() function ++ * is not loaded */ ++ return -EINVAL; ++ } ++ + ret = vxhs_init_and_ref(); + if (ret < 0) { ++ error_setg(&local_err, "libvxhs iio_init() failed"); + ret = -EINVAL; + goto out; + } +@@ -385,8 +485,8 @@ static int vxhs_open(BlockDriverState *bs, QDict *options, + /* + * Open qnio channel to storage agent if not opened before + */ +- dev_handlep = iio_open(of_vsa_addr, s->vdisk_guid, 0, +- cacert, client_key, client_cert); ++ dev_handlep = (*libvxhs.iio_open)(of_vsa_addr, s->vdisk_guid, 0, ++ cacert, client_key, client_cert); + if (dev_handlep == NULL) { + trace_vxhs_open_iio_open(of_vsa_addr); + ret = -ENODEV; +@@ -450,12 +550,12 @@ static BlockAIOCB *vxhs_aio_rw(BlockDriverState *bs, int64_t sector_num, + + switch (iodir) { + case VDISK_AIO_WRITE: +- ret = iio_writev(dev_handle, acb, qiov->iov, qiov->niov, +- offset, (uint64_t)size, iio_flags); ++ ret = (*libvxhs.iio_writev)(dev_handle, acb, qiov->iov, qiov->niov, ++ offset, (uint64_t)size, iio_flags); + break; + case VDISK_AIO_READ: +- ret = iio_readv(dev_handle, acb, qiov->iov, qiov->niov, +- offset, (uint64_t)size, iio_flags); ++ ret = (*libvxhs.iio_readv)(dev_handle, acb, qiov->iov, qiov->niov, ++ offset, (uint64_t)size, iio_flags); + break; + default: + trace_vxhs_aio_rw_invalid(iodir); +@@ -505,7 +605,7 @@ static void vxhs_close(BlockDriverState *bs) + * Close vDisk device + */ + if (s->vdisk_hostinfo.dev_handle) { +- iio_close(s->vdisk_hostinfo.dev_handle); ++ (*libvxhs.iio_close)(s->vdisk_hostinfo.dev_handle); + s->vdisk_hostinfo.dev_handle = NULL; + } + +@@ -527,7 +627,7 @@ static int64_t vxhs_get_vdisk_stat(BDRVVXHSState *s) + int ret = 0; + void *dev_handle = s->vdisk_hostinfo.dev_handle; + +- ret = iio_ioctl(dev_handle, IOR_VDISK_STAT, &vdisk_size, 0); ++ ret = (*libvxhs.iio_ioctl)(dev_handle, IOR_VDISK_STAT, &vdisk_size, 0); + if (ret < 0) { + trace_vxhs_get_vdisk_stat_err(s->vdisk_guid, ret, errno); + return -EIO; +diff --git a/configure b/configure +index e9243f5..d2367f1 100755 +--- a/configure ++++ b/configure +@@ -445,12 +445,15 @@ virglrenderer="" + tpm="yes" + libssh2="" + live_block_migration="yes" ++live_block_ops="yes" + numa="" + tcmalloc="no" + jemalloc="no" + replication="yes" + vxhs="" + libxml2="" ++vtd="yes" ++rhel_target="rhv" + + supported_cpu="no" + supported_os="no" +@@ -1348,6 +1351,10 @@ for opt do + ;; + --enable-replication) replication="yes" + ;; ++ --disable-live-block-ops) live_block_ops="no" ++ ;; ++ --enable-live-block-ops) live_block_ops="yes" ++ ;; + --disable-vxhs) vxhs="no" + ;; + --enable-vxhs) vxhs="yes" +@@ -1374,6 +1381,12 @@ for opt do + ;; + --disable-git-update) git_update=no + ;; ++ --disable-vtd) vtd="no" ++ ;; ++ --enable-vtd) vtd="yes" ++ ;; ++ --rhel-target=*) rhel_target="$optarg" ++ ;; + *) + echo "ERROR: unknown option $opt" + echo "Try '$0 --help' for more information" +@@ -1547,6 +1560,7 @@ Advanced options (experts only): + xen pv domain builder + --enable-debug-stack-usage + track the maximum stack usage of stacks created by qemu_alloc_stack ++ --rhel-target set RHEL target (rhv or rhel) + + Optional features, enabled with --enable-FEATURE and + disabled with --disable-FEATURE, default is enabled if available: +@@ -1616,6 +1630,8 @@ disabled with --disable-FEATURE, default is enabled if available: + glusterfs GlusterFS backend + tpm TPM support + libssh2 ssh block device support ++ live-block-migration live block migration support ++ live-block-ops live block operations support + numa libnuma support + libxml2 for Parallels image format + tcmalloc tcmalloc support +@@ -1628,6 +1644,7 @@ disabled with --disable-FEATURE, default is enabled if available: + qom-cast-debug cast debugging support + tools build qemu-io, qemu-nbd and qemu-image tools + vxhs Veritas HyperScale vDisk backend support ++ vtd Emulated VT-d support (only affects x86 targets) + crypto-afalg Linux AF_ALG crypto backend driver + vhost-user vhost-user support + capstone capstone disassembler support +@@ -3369,7 +3386,7 @@ else + glib_req_ver=2.22 + fi + glib_modules=gthread-2.0 +-if test "$modules" = yes; then ++if test "$modules" = yes -o "$vxhs" = yes; then + glib_modules="$glib_modules gmodule-export-2.0" + fi + +@@ -5306,33 +5323,6 @@ if compile_prog "" "" ; then + fi + + ########################################## +-# Veritas HyperScale block driver VxHS +-# Check if libvxhs is installed +- +-if test "$vxhs" != "no" ; then +- cat > $TMPC < +-#include +- +-void *vxhs_callback; +- +-int main(void) { +- iio_init(QNIO_VERSION, vxhs_callback); +- return 0; +-} +-EOF +- vxhs_libs="-lvxhs -lssl" +- if compile_prog "" "$vxhs_libs" ; then +- vxhs=yes +- else +- if test "$vxhs" = "yes" ; then +- feature_not_found "vxhs block device" "Install libvxhs See github" +- fi +- vxhs=no +- fi +-fi +- +-########################################## + # check for _Static_assert() + + have_static_assert=no +@@ -5855,6 +5845,7 @@ echo "TPM passthrough $tpm_passthrough" + echo "TPM emulator $tpm_emulator" + echo "QOM debugging $qom_cast_debug" + echo "Live block migration $live_block_migration" ++echo "Live block ops $live_block_ops" + echo "lzo support $lzo" + echo "snappy support $snappy" + echo "bzip2 support $bzip2" +@@ -5866,6 +5857,8 @@ echo "avx2 optimization $avx2_opt" + echo "replication support $replication" + echo "VxHS block device $vxhs" + echo "capstone $capstone" ++echo "VT-d emulation $vtd" ++echo "RHEL target $rhel_target" + + if test "$sdl_too_old" = "yes"; then + echo "-> Your SDL version is too old - please upgrade to have SDL support" +@@ -6504,6 +6497,10 @@ if test "$live_block_migration" = "yes" ; then + echo "CONFIG_LIVE_BLOCK_MIGRATION=y" >> $config_host_mak + fi + ++if test "$live_block_ops" = "yes" ; then ++ echo "CONFIG_LIVE_BLOCK_OPS=y" >> $config_host_mak ++fi ++ + if test "$tpm" = "yes"; then + echo 'CONFIG_TPM=$(CONFIG_SOFTMMU)' >> $config_host_mak + # TPM passthrough support? +@@ -6606,8 +6603,16 @@ if test "$pthread_setname_np" = "yes" ; then + fi + + if test "$vxhs" = "yes" ; then +- echo "CONFIG_VXHS=y" >> $config_host_mak +- echo "VXHS_LIBS=$vxhs_libs" >> $config_host_mak ++ echo "CONFIG_VXHS=m" >> $config_host_mak ++ echo "VXHS_LIBS= -lssl" >> $config_host_mak ++fi ++ ++if test "$vtd" = "yes" ; then ++ echo "CONFIG_VTD=y" >> $config_host_mak ++fi ++ ++if test "$rhel_target" = "rhv" ; then ++ echo "CONFIG_RHV=y" >> $config_host_mak + fi + + if test "$tcg_interpreter" = "yes"; then +diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx +index ddfcd5a..601fcb6 100644 +--- a/hmp-commands-info.hx ++++ b/hmp-commands-info.hx +@@ -84,6 +84,8 @@ STEXI + Show block device statistics. + ETEXI + ++#ifdef CONFIG_LIVE_BLOCK_OPS ++ + { + .name = "block-jobs", + .args_type = "", +@@ -98,6 +100,8 @@ STEXI + Show progress of ongoing block device operations. + ETEXI + ++#endif /* CONFIG_LIVE_BLOCK_OPS */ ++ + { + .name = "registers", + .args_type = "cpustate_all:-a", +diff --git a/hmp-commands.hx b/hmp-commands.hx +index 35d862a..3918831 100644 +--- a/hmp-commands.hx ++++ b/hmp-commands.hx +@@ -73,6 +73,8 @@ but should be used with extreme caution. Note that this command only + resizes image files, it can not resize block devices like LVM volumes. + ETEXI + ++#ifdef CONFIG_LIVE_BLOCK_OPS ++ + { + .name = "block_stream", + .args_type = "device:B,speed:o?,base:s?", +@@ -160,6 +162,8 @@ STEXI + Resume a paused block streaming operation. + ETEXI + ++#endif /* CONFIG_LIVE_BLOCK_OPS */ ++ + { + .name = "eject", + .args_type = "force:-f,device:B", +@@ -1151,6 +1155,8 @@ STEXI + Enables or disables migration mode. + ETEXI + ++#ifdef CONFIG_LIVE_BLOCK_OPS ++ + { + .name = "snapshot_blkdev", + .args_type = "reuse:-n,device:B,snapshot-file:s?,format:s?", +@@ -1172,6 +1178,8 @@ STEXI + Snapshot device, using snapshot file as target if provided + ETEXI + ++#endif /* CONFIG_LIVE_BLOCK_OPS */ ++ + { + .name = "snapshot_blkdev_internal", + .args_type = "device:B,name:s", +@@ -1206,6 +1214,8 @@ STEXI + Delete an internal snapshot on device if it support + ETEXI + ++#ifdef CONFIG_LIVE_BLOCK_OPS ++ + { + .name = "drive_mirror", + .args_type = "reuse:-n,full:-f,device:B,target:s,format:s?", +@@ -1249,6 +1259,8 @@ STEXI + Start a point-in-time copy of a block device to a specificed target. + ETEXI + ++#endif /* CONFIG_LIVE_BLOCK_OPS */ ++ + { + .name = "drive_add", + .args_type = "node:-n,pci_addr:s,opts:s", +diff --git a/hmp.c b/hmp.c +index a25c7bd..6c92198 100644 +--- a/hmp.c ++++ b/hmp.c +@@ -942,6 +942,8 @@ void hmp_info_pci(Monitor *mon, const QDict *qdict) + qapi_free_PciInfoList(info_list); + } + ++#ifdef CONFIG_LIVE_BLOCK_OPS ++ + void hmp_info_block_jobs(Monitor *mon, const QDict *qdict) + { + BlockJobInfoList *list; +@@ -980,6 +982,8 @@ void hmp_info_block_jobs(Monitor *mon, const QDict *qdict) + qapi_free_BlockJobInfoList(list); + } + ++#endif /* CONFIG_LIVE_BLOCK_OPS */ ++ + void hmp_info_tpm(Monitor *mon, const QDict *qdict) + { + TPMInfoList *info_list, *info; +@@ -1191,6 +1195,8 @@ void hmp_block_resize(Monitor *mon, const QDict *qdict) + hmp_handle_error(mon, &err); + } + ++#ifdef CONFIG_LIVE_BLOCK_OPS ++ + void hmp_drive_mirror(Monitor *mon, const QDict *qdict) + { + const char *filename = qdict_get_str(qdict, "target"); +@@ -1274,6 +1280,8 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict) + hmp_handle_error(mon, &err); + } + ++#endif /* CONFIG_LIVE_BLOCK_OPS */ ++ + void hmp_snapshot_blkdev_internal(Monitor *mon, const QDict *qdict) + { + const char *device = qdict_get_str(qdict, "device"); +@@ -1789,6 +1797,8 @@ void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict) + hmp_handle_error(mon, &err); + } + ++#ifdef CONFIG_LIVE_BLOCK_OPS ++ + void hmp_block_stream(Monitor *mon, const QDict *qdict) + { + Error *error = NULL; +@@ -1855,6 +1865,8 @@ void hmp_block_job_complete(Monitor *mon, const QDict *qdict) + hmp_handle_error(mon, &error); + } + ++#endif /* CONFIG_LIVE_BLOCK_OPS */ ++ + typedef struct HMPMigrationStatus + { + QEMUTimer *timer; +diff --git a/include/block/vxhs_shim.h b/include/block/vxhs_shim.h +new file mode 100644 +index 0000000..42519ae +--- /dev/null ++++ b/include/block/vxhs_shim.h +@@ -0,0 +1,143 @@ ++/* ++ * Network IO library for VxHS QEMU block driver (Veritas Technologies) ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2. See ++ * the COPYING file in the top-level directory. ++ * ++ * Contributions after 2014-08-15 are licensed under the terms of the ++ * GNU GPL, version 2 or (at your option) any later version. ++ */ ++ ++#ifndef QNIO_API_H ++#define QNIO_API_H ++ ++#include ++ ++/* ++ * Bump up the version everytime this file is modified ++ */ ++#define QNIO_VERSION 34 ++ ++/* ++ * These are the opcodes referenced by callback routine. ++ */ ++#define IRP_READ_REQUEST 0x1FFF ++#define IRP_WRITE_REQUEST 0x2FFF ++#define IRP_VDISK_CHECK_IO_FAILOVER_READY 2020 ++ ++/* ++ * opcodes for iio_ioctl. ++ */ ++#define IOR_VDISK_STAT 1005 ++ ++/* ++ * Error values for iio_cb_t callback function. ++ */ ++#define QNIOERROR_HUP 901 /* Retriable error */ ++#define QNIOERROR_NOCONN 902 /* Non-retriable error */ ++ ++ ++/* Operation Flags */ ++#define IIO_FLAG_ASYNC 0x0001 /* Do an async send */ ++ ++/* ++ * INPUT: ++ * ctx - opaque context ++ * opcode - Operation ++ * error - 0 for sucess, non-zero for failure. ++ * RETURNS: ++ * void ++ * DESCRIPTION: ++ * This callback is called, after Async request completes. ++ * ++ * CONTEXT: ++ * The callback should be wait-free. ++ */ ++typedef void (*iio_cb_t) (void *ctx, uint32_t opcode, uint32_t error); ++ ++typedef struct LibVXHSFuncs { ++/* ++ * RETURNS: ++ * 0 for sucess, non-zero for failure. ++ * DESCRIPTION: ++ * Intilize the library state. This should be called at the ++ * begining before issuing any library call. ++ */ ++ int (*iio_init)(int32_t version, iio_cb_t cb); ++/* ++ * RETURNS: ++ * void ++ * DESCRIPTION: ++ * Relinquish library resources. This should be called on the ++ * close of last open device. ++ */ ++ void (*iio_fini)(void); ++/* ++ * DESCRIPTION: ++ * Returns minimum QNIO API version supported by library. ++ */ ++ int32_t (*iio_min_version)(void); ++/* ++ * DESCRIPTION: ++ * Returns maximum QNIO API version supported by library. ++ */ ++ int32_t (*iio_max_version)(void); ++/* ++ * INPUT: ++ * uri - const string of the format of://:port ++ * devid - Device ID. ++ * flags - currently unused, this must be set to 0 ++ * cacert - CA certificates file in PEM format ++ * client_key - Client private key file in PEM format ++ * client_cert - Client certificate file in PEM format ++ * RETURNS: ++ * opeque device handle on success, NULL on failure. ++ * DESCRIPTION: ++ * This call returns device handle on success. Returns NULL on ++ * failure with errno set ++ * errno can be one of: ++ * ENODEV - remote device not found ++ * EBADF - Unable to open communication channel. ++ * EBUSY - The call cannot be completed right now ++ */ ++ void *(*iio_open)(const char *uri, const char *devid, uint32_t flags, ++ const char *cacert, const char *client_key, ++ const char *client_cert); ++/* ++ * Close the device. ++ * For every matching iio_open() there should be a matching iio_close() ++ * The last close free all data structures associated with the device. ++ */ ++ int32_t (*iio_close)(void *dev_handle); ++/* ++ * INPUT: ++ * dev_handle - device descriptor on which read/write needs to be performed ++ * ctx - an opaque context that is not interpreted This is set for ++ * async calls only. It can be NULL. ++ * iov - an array of iovecs (This is a scatter gather operation) ++ * iovcnt - the number of iovecs ++ * offset - an offset to perform the write ++ * size - I/O size ++ * flags - can be one of ++ * IIO_FLAG_ASYNC - indicating this is a aio call. ++ * RETURNS: ++ * -1 on error, sets errno ++ * EBADF - the remote fd is bad ++ * EBUSY - The call cannot be completed right now ++ * EPIPE - the channel got disconnected, call back would be called in ++ * addition to this. ++ */ ++ int32_t (*iio_writev)(void *dev_handle, void *ctx, struct iovec *iov, ++ int iovcnt, uint64_t offset, uint64_t size, ++ uint32_t flags); ++ ++ int32_t (*iio_readv)(void *dev_handle, void *ctx, struct iovec *iov, ++ int iovcnt, uint64_t offset, uint64_t size, ++ uint32_t flags); ++ ++ int32_t (*iio_ioctl)(void *dev_handle, uint32_t opcode, void *opaque, ++ uint32_t flags); ++ ++} LibVXHSFuncs; ++ ++#endif +diff --git a/monitor.c b/monitor.c +index 39f8ee1..1813d34 100644 +--- a/monitor.c ++++ b/monitor.c +@@ -1168,6 +1168,22 @@ static void qmp_unregister_commands_hack(void) + && !defined(TARGET_S390X) + qmp_unregister_command(&qmp_commands, "query-cpu-definitions"); + #endif ++#ifndef CONFIG_LIVE_BLOCK_OPS ++ qmp_unregister_command(&qmp_commands, "block-stream"); ++ qmp_unregister_command(&qmp_commands, "block-commit"); ++ qmp_unregister_command(&qmp_commands, "drive-mirror"); ++ qmp_unregister_command(&qmp_commands, "blockdev-mirror"); ++ qmp_unregister_command(&qmp_commands, "drive-backup"); ++ qmp_unregister_command(&qmp_commands, "blockdev-backup"); ++ qmp_unregister_command(&qmp_commands, "blockdev-snapshot"); ++ qmp_unregister_command(&qmp_commands, "blockdev-snapshot-sync"); ++ qmp_unregister_command(&qmp_commands, "block-job-set-speed"); ++ qmp_unregister_command(&qmp_commands, "block-job-cancel"); ++ qmp_unregister_command(&qmp_commands, "block-job-pause"); ++ qmp_unregister_command(&qmp_commands, "block-job-resume"); ++ qmp_unregister_command(&qmp_commands, "block-job-complete"); ++ qmp_unregister_command(&qmp_commands, "query-block-jobs"); ++#endif + } + + static void monitor_init_qmp_commands(void) +diff --git a/os-posix.c b/os-posix.c +index b9c2343..05de8ee 100644 +--- a/os-posix.c ++++ b/os-posix.c +@@ -75,7 +75,7 @@ void os_setup_signal_handling(void) + /* Find a likely location for support files using the location of the binary. + For installed binaries this will be "$bindir/../share/qemu". When + running from the build tree this will be "$bindir/../pc-bios". */ +-#define SHARE_SUFFIX "/share/qemu" ++#define SHARE_SUFFIX "/share/qemu-kvm" + #define BUILD_SUFFIX "/pc-bios" + char *os_find_datadir(void) + { +diff --git a/tests/qmp-test.c b/tests/qmp-test.c +index 772058f..f34428e 100644 +--- a/tests/qmp-test.c ++++ b/tests/qmp-test.c +@@ -238,6 +238,9 @@ static int query_error_class(const char *cmd) + { "query-balloon", ERROR_CLASS_DEVICE_NOT_ACTIVE }, + { "query-hotpluggable-cpus", ERROR_CLASS_GENERIC_ERROR }, + { "query-vm-generation-id", ERROR_CLASS_GENERIC_ERROR }, ++#ifndef CONFIG_RHV ++ { "query-block-jobs", ERROR_CLASS_COMMAND_NOT_FOUND }, ++#endif + { NULL, -1 } + }; + int i; +diff --git a/ui/vnc.c b/ui/vnc.c +index e164eb7..0c3011b 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -4045,7 +4045,7 @@ void vnc_display_open(const char *id, Error **errp) + trace_vnc_auth_init(vd, 1, vd->ws_auth, vd->ws_subauth); + + #ifdef CONFIG_VNC_SASL +- if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) { ++ if ((saslErr = sasl_server_init(NULL, "qemu-kvm")) != SASL_OK) { + error_setg(errp, "Failed to initialize SASL auth: %s", + sasl_errstring(saslErr, NULL, NULL)); + goto fail; +-- +1.8.3.1 + diff --git a/SOURCES/0004-Enable-disable-devices-for-RHEL-7.patch b/SOURCES/0004-Enable-disable-devices-for-RHEL-7.patch index 94953da..77ef5fe 100644 --- a/SOURCES/0004-Enable-disable-devices-for-RHEL-7.patch +++ b/SOURCES/0004-Enable-disable-devices-for-RHEL-7.patch @@ -1,4 +1,4 @@ -From 0e72e616b2d80e47c0eb6c5976276e9f8d920e92 Mon Sep 17 00:00:00 2001 +From 9746c4059558e94c983df315f61203f766ceb500 Mon Sep 17 00:00:00 2001 From: Miroslav Rezanina Date: Mon, 11 Jan 2016 11:53:33 +0100 Subject: Enable/disable devices for RHEL 7 @@ -8,6 +8,18 @@ up to qemu-kvm-rhev-2.1.2-16.el7. Signed-off-by: Miroslav Rezanina +Rebase notes (2.12.0): +- Disable AMD_IOMMU +- New handling of VHOST_USER_* device disabling +- Use cpu_type instead of cpu_model +- Disabled CONFIG_P4XXX for power64 +- Disabled sam460ex board tests + +Rebase notes (2.11.0): +- Switched order with machine type commit +- Removed CONFIG_STELLARIS from aarch64 +- Blacklist isapc for qom and hmp tests + Rebase notes (2.10.0): - replace cannot_instantiate_with_device_add_yet with user_creatable (upstream e90f2a) - Comment out default configs instead of removing the options @@ -54,6 +66,15 @@ Rebase notes (2.4.0): Rebase notes (2.3.0): - Added USB=y in 2.3-rc2 (used instead of downstream version fora aarch64) +Merged patches (2.11.): +- e6c4563d68 hw: Remove the redundant user_creatable = false from SYS_BUS_DEVICEs +- 35474b23b1 hw/pci-host/q35: Remove redundant downstream user_creatable = false +- 374294de46 hw/dma/i8257: Remove redundant downstream user_creatable = false +- 17abc4f5bd RHEL: Disable vfio-ccw and x-terminal270 devices +- b303e792c3 Disable vhost-user-scsi and vhost-user-scsi-pci +- 28f294c023 Disable sm501 and sysbus-sm501 devices +- d5959fcefc s390x/cpumodel: Disable unsupported CPU models + Merged patches (2.10.0): - e9b413e Add PCIe bridge devices for AArch64 - a522114 s390x/virtio-ccw: Disable crypto device in downstream RHEL builds @@ -123,76 +144,93 @@ Merged patches (2.4.0): - 91c76c5 Remove intel-iommu device - ec1615d Disable additional e1000 models -(cherry picked from commit a36a3ad800b282cef9d72e6d8026470035f8f21c) +(cherry picked from commit 0e72e616b2d80e47c0eb6c5976276e9f8d920e92) + +Conflicts: + redhat/qemu-kvm.spec.template + +Conflicts: + default-configs/aarch64-softmmu.mak + default-configs/pci.mak + default-configs/ppc64-softmmu.mak + default-configs/s390x-softmmu.mak + hw/arm/Makefile.objs + hw/core/Makefile.objs + hw/i386/Makefile.objs + hw/i386/pc.c + hw/ppc/Makefile.objs + stubs/Makefile.objs + tests/Makefile.include + tests/boot-serial-test.c + tests/qemu-iotests/051 + +Conflicts: + target/i386/cpu.c + tests/boot-serial-test.c + +(cherry picked from commit d62675886ef77b23a774523cb33cc3037b7f7a8b) --- - default-configs/aarch64-softmmu.mak | 33 ++++++++--- - default-configs/pci.mak | 36 ++++++------ - default-configs/ppc64-softmmu.mak | 108 ++++++++++++++++++++---------------- - default-configs/ppcemb-softmmu.mak | 13 +++++ - default-configs/s390x-softmmu.mak | 2 +- - default-configs/sound.mak | 8 +-- - default-configs/usb.mak | 14 ++--- - default-configs/x86_64-softmmu.mak | 26 +++++---- - hw/acpi/ich9.c | 4 +- - hw/block/fdc.c | 1 + - hw/block/pflash_cfi01.c | 1 + - hw/char/serial-pci.c | 4 ++ - hw/core/Makefile.objs | 7 ++- - hw/display/cirrus_vga.c | 2 + - hw/display/sm501.c | 2 +- - hw/dma/i8257.c | 2 + - hw/i386/Makefile.objs | 3 +- - hw/i386/kvm/clock.c | 1 + - hw/i386/pc.c | 3 +- - hw/ide/ahci.c | 5 ++ - hw/ide/piix.c | 5 +- - hw/ide/via.c | 2 + - hw/input/pckbd.c | 2 + - hw/isa/isa-bus.c | 1 + - hw/misc/Makefile.objs | 2 +- - hw/misc/ivshmem.c | 11 ++++ - hw/net/e1000.c | 2 + - hw/net/e1000e.c | 2 +- - hw/pci-host/piix.c | 4 ++ - hw/pci-host/q35.c | 1 + - hw/ppc/Makefile.objs | 3 +- - hw/ppc/spapr.c | 3 +- - hw/ppc/spapr_cpu_core.c | 4 +- - hw/s390x/virtio-ccw.c | 10 ++++ - hw/usb/ccid-card-emulated.c | 2 + - hw/vfio/Makefile.objs | 3 - - hw/vfio/pci-quirks.c | 5 ++ - hw/virtio/Makefile.objs | 5 +- - hw/virtio/virtio-mmio.c | 1 + - qemu-options.hx | 5 -- - redhat/build_configure.sh | 2 +- - redhat/qemu-kvm.spec.template | 5 +- - stubs/Makefile.objs | 1 + - stubs/ide-isa.c | 13 +++++ - target/arm/cpu.c | 4 +- - target/i386/cpu.c | 15 ++--- - target/ppc/cpu-models.c | 17 +++++- - tests/Makefile.include | 72 +++++++----------------- - tests/bios-tables-test.c | 4 ++ - tests/boot-order-test.c | 7 +++ - tests/boot-serial-test.c | 8 +-- - tests/e1000-test.c | 2 + - tests/endianness-test.c | 2 + - tests/ivshmem-test.c | 10 +++- - tests/qemu-iotests/051 | 20 +++---- - tests/qemu-iotests/group | 4 +- - tests/qom-test.c | 4 +- - tests/test-x86-cpuid-compat.c | 2 + - tests/usb-hcd-xhci-test.c | 5 +- - vl.c | 2 +- - 60 files changed, 338 insertions(+), 209 deletions(-) + default-configs/aarch64-softmmu.mak | 35 ++++++++++++++---- + default-configs/pci.mak | 38 +++++++++---------- + default-configs/ppc64-softmmu.mak | 30 ++++++++++++--- + default-configs/s390x-softmmu.mak | 12 +++--- + default-configs/sound.mak | 8 ++-- + default-configs/usb.mak | 14 +++---- + default-configs/x86_64-softmmu.mak | 30 ++++++++------- + hw/acpi/ich9.c | 4 +- + hw/block/fdc.c | 1 + + hw/char/serial-pci.c | 4 ++ + hw/core/Makefile.objs | 7 ++-- + hw/display/cirrus_vga.c | 2 + + hw/i386/pc.c | 3 +- + hw/ide/piix.c | 5 ++- + hw/ide/via.c | 2 + + hw/input/pckbd.c | 2 + + hw/misc/Makefile.objs | 2 +- + hw/misc/ivshmem.c | 11 ++++++ + hw/net/e1000.c | 2 + + hw/net/e1000e.c | 2 +- + hw/pci-host/piix.c | 4 ++ + hw/ppc/Makefile.objs | 2 +- + hw/ppc/spapr.c | 3 +- + hw/ppc/spapr_cpu_core.c | 2 + + hw/s390x/virtio-ccw.c | 8 ++++ + hw/usb/ccid-card-emulated.c | 2 + + hw/vfio/Makefile.objs | 3 -- + hw/vfio/pci-quirks.c | 5 +++ + hw/virtio/Makefile.objs | 5 ++- + hw/virtio/virtio-pci.c | 8 ++-- + qemu-options.hx | 5 --- + redhat/qemu-kvm.spec.template | 4 +- + stubs/Makefile.objs | 1 + + stubs/ide-isa.c | 13 +++++++ + target/arm/cpu.c | 4 +- + target/i386/cpu.c | 37 +++++++++++++++---- + target/ppc/cpu-models.c | 17 ++++++++- + target/s390x/cpu_models.c | 3 ++ + target/s390x/kvm.c | 8 ++++ + tests/Makefile.include | 73 +++++++++++-------------------------- + tests/bios-tables-test.c | 4 ++ + tests/boot-order-test.c | 7 ++++ + tests/boot-serial-test.c | 10 ++--- + tests/e1000-test.c | 2 + + tests/endianness-test.c | 2 + + tests/ivshmem-test.c | 10 ++++- + tests/qemu-iotests/051 | 12 +++--- + tests/qemu-iotests/group | 4 +- + tests/qom-test.c | 4 +- + tests/test-hmp.c | 2 +- + tests/test-x86-cpuid-compat.c | 2 + + tests/usb-hcd-xhci-test.c | 5 ++- + vl.c | 2 +- + 53 files changed, 318 insertions(+), 169 deletions(-) create mode 100644 stubs/ide-isa.c diff --git a/default-configs/aarch64-softmmu.mak b/default-configs/aarch64-softmmu.mak -index abd18c2..5d57303 100644 +index 9ddccf8..001eb8e 100644 --- a/default-configs/aarch64-softmmu.mak +++ b/default-configs/aarch64-softmmu.mak -@@ -1,11 +1,30 @@ +@@ -1,10 +1,29 @@ # Default configuration for aarch64-softmmu -# We support all the 32 bit boards so need all their config @@ -202,16 +240,16 @@ index abd18c2..5d57303 100644 -CONFIG_DDC=y -CONFIG_DPCD=y -CONFIG_XLNX_ZYNQMP=y -+# Disabled in Red Hat Enterprise Linux +-CONFIG_XLNX_ZYNQMP_ARM=y +# CONFIG_AUX=y +# CONFIG_DDC=y +# CONFIG_DPCD=y +# CONFIG_XLNX_ZYNQMP=y ++# CONFIG_XLNX_ZYNQMP_ARM=y +CONFIG_PCI=y +CONFIG_PCI_TESTDEV=y +CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO=y -+CONFIG_STELLARIS=y +CONFIG_ARM_GIC=y +CONFIG_ARM_GIC_KVM=$(CONFIG_KVM) +CONFIG_PL011=y @@ -221,20 +259,20 @@ index abd18c2..5d57303 100644 +CONFIG_ACPI=y +CONFIG_PLATFORM_BUS=y +CONFIG_SMBIOS=y - CONFIG_PL061=y - CONFIG_GPIO_KEY=y ++CONFIG_PL061=y ++CONFIG_GPIO_KEY=y +CONFIG_ARM_V7M=y -+CONFIG_VHOST_USER_SCSI=$(and $(CONFIG_VHOST_USER),$(CONFIG_LINUX)) +CONFIG_PCIE_PORT=y +CONFIG_XIO3130=y +CONFIG_IOH3420=y +CONFIG_USB_XHCI=y +CONFIG_USB=y ++CONFIG_I2C=y diff --git a/default-configs/pci.mak b/default-configs/pci.mak -index a758630..9bd8452 100644 +index 35e7596..4c8c296 100644 --- a/default-configs/pci.mak +++ b/default-configs/pci.mak -@@ -4,43 +4,43 @@ CONFIG_ISA_BUS=y +@@ -4,21 +4,21 @@ CONFIG_ISA_BUS=y CONFIG_VIRTIO_PCI=y CONFIG_VIRTIO=y CONFIG_USB_UHCI=y @@ -266,9 +304,7 @@ index a758630..9bd8452 100644 CONFIG_RTL8139_PCI=y CONFIG_E1000_PCI=y CONFIG_E1000E_PCI=y --CONFIG_VMXNET3_PCI=y -+#CONFIG_VMXNET3_PCI=y - CONFIG_IDE_CORE=y +@@ -26,24 +26,24 @@ CONFIG_IDE_CORE=y CONFIG_IDE_QDEV=y CONFIG_IDE_PCI=y CONFIG_AHCI=y @@ -279,6 +315,9 @@ index a758630..9bd8452 100644 CONFIG_SERIAL=y CONFIG_SERIAL_ISA=y CONFIG_SERIAL_PCI=y + CONFIG_CAN_BUS=y + CONFIG_CAN_SJA1000=y + CONFIG_CAN_PCI=y -CONFIG_IPACK=y +#CONFIG_IPACK=y CONFIG_WDT_IB6300ESB=y @@ -294,17 +333,24 @@ index a758630..9bd8452 100644 CONFIG_VGA_PCI=y CONFIG_IVSHMEM_DEVICE=$(CONFIG_IVSHMEM) -CONFIG_ROCKER=y +-CONFIG_VHOST_USER_SCSI=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) +-CONFIG_VHOST_USER_BLK=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) +#CONFIG_ROCKER=y - CONFIG_VHOST_USER_SCSI=$(and $(CONFIG_VHOST_USER),$(CONFIG_LINUX)) ++#CONFIG_VHOST_USER_SCSI=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) ++#CONFIG_VHOST_USER_BLK=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak -index 46c9599..31ef40c 100644 +index b94af6c..936ac17 100644 --- a/default-configs/ppc64-softmmu.mak +++ b/default-configs/ppc64-softmmu.mak -@@ -1,64 +1,76 @@ +@@ -1,14 +1,31 @@ # Default configuration for ppc64-softmmu --include pci.mak -+# PCI configuration - cut down from the defaults in pci.mak +-# Include all 32-bit boards +-include ppc-softmmu.mak ++include sound.mak ++include usb.mak ++ ++## PCI configuration - cut down from the defaults in pci.mak +CONFIG_PCI=y +CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO=y @@ -312,15 +358,18 @@ index 46c9599..31ef40c 100644 +CONFIG_USB_XHCI_NEC=y +CONFIG_WDT_IB6300ESB=y +CONFIG_PCI_TESTDEV=y -+CONFIG_VHOST_USER_SCSI=$(and $(CONFIG_VHOST_USER),$(CONFIG_LINUX)) ++CONFIG_USB_OHCI=y ++CONFIG_VGA=y ++CONFIG_VGA_PCI=y ++CONFIG_SERIAL=y ++CONFIG_I2C=y + - include sound.mak - include usb.mak - CONFIG_VIRTIO_VGA=y --CONFIG_ESCC=y --CONFIG_M48T59=y -+#CONFIG_ESCC=y -+#CONFIG_M48T59=y ++# For embedded PPCs ++#CONFIG_PPC4XX=y + + # For PowerNV +-CONFIG_POWERNV=y ++#CONFIG_POWERNV=y CONFIG_IPMI=y -CONFIG_IPMI_LOCAL=y -CONFIG_IPMI_EXTERN=y @@ -328,138 +377,37 @@ index 46c9599..31ef40c 100644 +#CONFIG_IPMI_LOCAL=y +#CONFIG_IPMI_EXTERN=y +#CONFIG_ISA_IPMI_BT=y -+CONFIG_VGA=y -+CONFIG_VGA_PCI=y - CONFIG_SERIAL=y --CONFIG_PARALLEL=y --CONFIG_I8254=y --CONFIG_PCKBD=y --CONFIG_FDC=y --CONFIG_I8257=y --CONFIG_I82374=y --CONFIG_OPENPIC=y --CONFIG_PREP_PCI=y --CONFIG_I82378=y --CONFIG_PC87312=y --CONFIG_MACIO=y --CONFIG_PCSPK=y --CONFIG_CUDA=y --CONFIG_ADB=y --CONFIG_MAC_NVRAM=y --CONFIG_MAC_DBDMA=y --CONFIG_HEATHROW_PIC=y --CONFIG_GRACKLE_PCI=y --CONFIG_UNIN_PCI=y --CONFIG_DEC_PCI=y --CONFIG_PPCE500_PCI=y --CONFIG_IDE_ISA=y --CONFIG_IDE_CMD646=y --CONFIG_IDE_MACIO=y --CONFIG_NE2000_ISA=y --CONFIG_PFLASH_CFI01=y --CONFIG_PFLASH_CFI02=y --CONFIG_PTIMER=y --CONFIG_I8259=y --CONFIG_XILINX=y --CONFIG_XILINX_ETHLITE=y -+#CONFIG_PARALLEL=y -+#CONFIG_I8254=y -+#CONFIG_PCKBD=y -+#CONFIG_FDC=y -+#CONFIG_I8257=y -+#CONFIG_I82374=y -+#CONFIG_OPENPIC=y -+#CONFIG_PREP_PCI=y -+#CONFIG_I82378=y -+#CONFIG_PC87312=y -+#CONFIG_MACIO=y -+#CONFIG_PCSPK=y -+#CONFIG_CUDA=y -+#CONFIG_ADB=y -+#CONFIG_MAC_NVRAM=y -+#CONFIG_MAC_DBDMA=y -+#CONFIG_HEATHROW_PIC=y -+#CONFIG_GRACKLE_PCI=y -+#CONFIG_UNIN_PCI=y -+#CONFIG_DEC_PCI=y -+#CONFIG_PPCE500_PCI=y -+#CONFIG_IDE_ISA=y -+#CONFIG_IDE_CMD646=y -+#CONFIG_IDE_MACIO=y -+#CONFIG_NE2000_ISA=y -+#CONFIG_PFLASH_CFI01=y -+#CONFIG_PFLASH_CFI02=y -+#CONFIG_PTIMER=y -+#CONFIG_I8259=y -+#CONFIG_XILINX=y -+#CONFIG_XILINX_ETHLITE=y - CONFIG_PSERIES=y --CONFIG_POWERNV=y --CONFIG_PREP=y --CONFIG_MAC=y --CONFIG_E500=y --CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM)) --CONFIG_PLATFORM_BUS=y --CONFIG_ETSEC=y -+#CONFIG_POWERNV=y -+#CONFIG_PREP=y -+#CONFIG_MAC=y -+#CONFIG_E500=y -+#CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM)) -+#CONFIG_PLATFORM_BUS=y -+#CONFIG_ETSEC=y - CONFIG_LIBDECNUMBER=y - CONFIG_SM501=y -+CONFIG_USB_OHCI=y + # For pSeries - CONFIG_XICS=$(CONFIG_PSERIES) + CONFIG_PSERIES=y +@@ -17,3 +34,4 @@ CONFIG_XICS=$(CONFIG_PSERIES) CONFIG_XICS_SPAPR=$(CONFIG_PSERIES) - CONFIG_XICS_KVM=$(and $(CONFIG_PSERIES),$(CONFIG_KVM)) - # For PReP --CONFIG_SERIAL_ISA=y --CONFIG_MC146818RTC=y --CONFIG_ISA_TESTDEV=y -+#CONFIG_SERIAL_ISA=y -+#CONFIG_MC146818RTC=y -+#CONFIG_ISA_TESTDEV=y + CONFIG_XICS_KVM=$(call land,$(CONFIG_PSERIES),$(CONFIG_KVM)) CONFIG_MEM_HOTPLUG=y --CONFIG_RS6000_MC=y -+#CONFIG_RS6000_MC=y -diff --git a/default-configs/ppcemb-softmmu.mak b/default-configs/ppcemb-softmmu.mak -index 94340de..cd9d51a 100644 ---- a/default-configs/ppcemb-softmmu.mak -+++ b/default-configs/ppcemb-softmmu.mak -@@ -8,6 +8,19 @@ CONFIG_SERIAL=y - CONFIG_SERIAL_ISA=y - CONFIG_I8257=y - CONFIG_OPENPIC=y -+CONFIG_MACIO=y -+CONFIG_CUDA=y -+CONFIG_ADB=y -+CONFIG_MAC_NVRAM=y -+CONFIG_MAC_DBDMA=y -+CONFIG_HEATHROW_PIC=y -+CONFIG_GRACKLE_PCI=y -+CONFIG_UNIN_PCI=y -+CONFIG_DEC_PCI=y -+CONFIG_PPCE500_PCI=y -+CONFIG_IDE_ISA=y -+CONFIG_IDE_CMD646=y -+CONFIG_IDE_MACIO=y - CONFIG_PFLASH_CFI01=y - CONFIG_PFLASH_CFI02=y - CONFIG_PTIMER=y ++CONFIG_I2C=y diff --git a/default-configs/s390x-softmmu.mak b/default-configs/s390x-softmmu.mak -index 51191b7..43dbf34 100644 +index 2f4bfe7..649bf2c 100644 --- a/default-configs/s390x-softmmu.mak +++ b/default-configs/s390x-softmmu.mak -@@ -1,5 +1,5 @@ +@@ -1,11 +1,13 @@ CONFIG_PCI=y --CONFIG_VIRTIO_PCI=y -+#CONFIG_VIRTIO_PCI=y - CONFIG_VHOST_USER_SCSI=$(and $(CONFIG_VHOST_USER),$(CONFIG_LINUX)) +-CONFIG_VIRTIO_PCI=$(CONFIG_PCI) +-CONFIG_VHOST_USER_SCSI=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) +-CONFIG_VHOST_USER_BLK=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) ++#CONFIG_VIRTIO_PCI=$(CONFIG_PCI) ++#CONFIG_VHOST_USER_SCSI=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) ++#CONFIG_VHOST_USER_BLK=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) CONFIG_VIRTIO=y CONFIG_SCLPCONSOLE=y +-CONFIG_TERMINAL3270=y ++# Disabled for Red Hat Enterprise Linux: ++# CONFIG_TERMINAL3270=y + CONFIG_S390_FLIC=y + CONFIG_S390_FLIC_KVM=$(CONFIG_KVM) +-CONFIG_VFIO_CCW=$(CONFIG_LINUX) ++# Disabled for Red Hat Enterprise Linux: ++# CONFIG_VFIO_CCW=$(CONFIG_LINUX) + CONFIG_WDT_DIAG288=y diff --git a/default-configs/sound.mak b/default-configs/sound.mak index 4f22c34..1bead9b 100644 --- a/default-configs/sound.mak @@ -496,10 +444,10 @@ index f4b8568..a256f84 100644 +#CONFIG_USB_NETWORK=y +#CONFIG_USB_BLUETOOTH=y diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak -index 9bde2f1..d6d10aa 100644 +index 0390b43..2675606 100644 --- a/default-configs/x86_64-softmmu.mak +++ b/default-configs/x86_64-softmmu.mak -@@ -4,19 +4,20 @@ include pci.mak +@@ -4,20 +4,21 @@ include pci.mak include sound.mak include usb.mak CONFIG_QXL=$(CONFIG_SPICE) @@ -508,7 +456,9 @@ index 9bde2f1..d6d10aa 100644 +CONFIG_VGA_PCI=y CONFIG_VGA_CIRRUS=y -CONFIG_VMWARE_VGA=y +-CONFIG_VMXNET3_PCI=y +#CONFIG_VMWARE_VGA=y ++#CONFIG_VMXNET3_PCI=y CONFIG_VIRTIO_VGA=y CONFIG_VMMOUSE=y CONFIG_IPMI=y @@ -527,7 +477,7 @@ index 9bde2f1..d6d10aa 100644 CONFIG_I8254=y CONFIG_PCSPK=y CONFIG_PCKBD=y -@@ -28,17 +29,18 @@ CONFIG_ACPI_MEMORY_HOTPLUG=y +@@ -29,11 +30,11 @@ CONFIG_ACPI_MEMORY_HOTPLUG=y CONFIG_ACPI_CPU_HOTPLUG=y CONFIG_APM=y CONFIG_I8257=y @@ -543,6 +493,7 @@ index 9bde2f1..d6d10aa 100644 CONFIG_I8259=y CONFIG_PFLASH_CFI01=y CONFIG_TPM_TIS=$(CONFIG_TPM) +@@ -41,6 +42,7 @@ CONFIG_TPM_CRB=$(CONFIG_TPM) CONFIG_MC146818RTC=y CONFIG_PCI_PIIX=y CONFIG_WDT_IB700=y @@ -550,7 +501,7 @@ index 9bde2f1..d6d10aa 100644 CONFIG_ISA_DEBUG=y CONFIG_ISA_TESTDEV=y CONFIG_VMPORT=y -@@ -56,6 +58,6 @@ CONFIG_XIO3130=y +@@ -58,11 +60,11 @@ CONFIG_XIO3130=y CONFIG_IOH3420=y CONFIG_I82801B11=y CONFIG_SMBIOS=y @@ -558,6 +509,12 @@ index 9bde2f1..d6d10aa 100644 +#CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM) CONFIG_PXB=y CONFIG_ACPI_VMGENID=y + CONFIG_FW_CFG_DMA=y + CONFIG_I2C=y + CONFIG_SEV=$(CONFIG_KVM) + CONFIG_VTD=y +-CONFIG_AMD_IOMMU=y ++#CONFIG_AMD_IOMMU=y diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c index c5d8646..a4e87b8 100644 --- a/hw/acpi/ich9.c @@ -574,10 +531,10 @@ index c5d8646..a4e87b8 100644 object_property_add_uint32_ptr(obj, ACPI_PM_PROP_PM_IO_BASE, diff --git a/hw/block/fdc.c b/hw/block/fdc.c -index 4011290..90cd9a0 100644 +index cd29e27..3964096 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c -@@ -611,6 +611,7 @@ static void floppy_drive_class_init(ObjectClass *klass, void *data) +@@ -605,6 +605,7 @@ static void floppy_drive_class_init(ObjectClass *klass, void *data) k->bus_type = TYPE_FLOPPY_BUS; k->props = floppy_drive_properties; k->desc = "virtual floppy drive"; @@ -585,20 +542,8 @@ index 4011290..90cd9a0 100644 } static const TypeInfo floppy_drive_info = { -diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c -index 1113ab1..afe6230 100644 ---- a/hw/block/pflash_cfi01.c -+++ b/hw/block/pflash_cfi01.c -@@ -925,6 +925,7 @@ static void pflash_cfi01_class_init(ObjectClass *klass, void *data) - dc->realize = pflash_cfi01_realize; - dc->props = pflash_cfi01_properties; - dc->vmsd = &vmstate_pflash; -+ dc->user_creatable = false; /* RH state preserve */ - set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); - } - diff --git a/hw/char/serial-pci.c b/hw/char/serial-pci.c -index 303104d..24ce17b 100644 +index cb0d04c..d426982 100644 --- a/hw/char/serial-pci.c +++ b/hw/char/serial-pci.c @@ -228,6 +228,8 @@ static void multi_2x_serial_pci_class_initfn(ObjectClass *klass, void *data) @@ -620,28 +565,29 @@ index 303104d..24ce17b 100644 static const TypeInfo serial_pci_info = { diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs -index f8d7a4a..060d594 100644 +index eb88ca9..2b4491f 100644 --- a/hw/core/Makefile.objs +++ b/hw/core/Makefile.objs -@@ -15,9 +15,10 @@ common-obj-$(CONFIG_SOFTMMU) += machine.o +@@ -16,10 +16,11 @@ common-obj-$(CONFIG_SOFTMMU) += machine.o common-obj-$(CONFIG_SOFTMMU) += loader.o common-obj-$(CONFIG_FITLOADER) += loader-fit.o common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o -common-obj-$(CONFIG_SOFTMMU) += register.o -common-obj-$(CONFIG_SOFTMMU) += or-irq.o - common-obj-$(CONFIG_PLATFORM_BUS) += platform-bus.o +# Disabled in Red Hat Enterprise Linux +# common-obj-$(CONFIG_SOFTMMU) += register.o +# obj-$(CONFIG_SOFTMMU) += generic-loader.o +# common-obj-$(CONFIG_SOFTMMU) += or-irq.o + common-obj-$(CONFIG_SOFTMMU) += split-irq.o + common-obj-$(CONFIG_PLATFORM_BUS) += platform-bus.o -obj-$(CONFIG_SOFTMMU) += generic-loader.o obj-$(CONFIG_SOFTMMU) += null-machine.o diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c -index 14008aa..15322b5 100644 +index 138ae96..d116651 100644 --- a/hw/display/cirrus_vga.c +++ b/hw/display/cirrus_vga.c -@@ -3077,6 +3077,8 @@ static void isa_cirrus_vga_class_init(ObjectClass *klass, void *data) +@@ -3074,6 +3074,8 @@ static void isa_cirrus_vga_class_init(ObjectClass *klass, void *data) dc->realize = isa_cirrus_vga_realizefn; dc->props = isa_cirrus_vga_properties; set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); @@ -650,113 +596,26 @@ index 14008aa..15322b5 100644 } static const TypeInfo isa_cirrus_vga_info = { -diff --git a/hw/display/sm501.c b/hw/display/sm501.c -index 9aa515b..6f3dfe0 100644 ---- a/hw/display/sm501.c -+++ b/hw/display/sm501.c -@@ -1758,7 +1758,7 @@ static void sm501_sysbus_class_init(ObjectClass *klass, void *data) - dc->reset = sm501_reset_sysbus; - dc->vmsd = &vmstate_sm501_sysbus; - /* Note: pointer property "chr-state" may remain null, thus -- * no need for dc->cannot_instantiate_with_device_add_yet = true; -+ * no need for dc->user_creatable = false; - */ - } - -diff --git a/hw/dma/i8257.c b/hw/dma/i8257.c -index bd23e89..e52a679 100644 ---- a/hw/dma/i8257.c -+++ b/hw/dma/i8257.c -@@ -591,6 +591,8 @@ static void i8257_class_init(ObjectClass *klass, void *data) - dc->reset = i8257_reset; - dc->vmsd = &vmstate_i8257; - dc->props = i8257_properties; -+ /* Disabled for Red Hat Enterprise Linux: */ -+ dc->user_creatable = false; - - idc->get_transfer_mode = i8257_dma_get_transfer_mode; - idc->has_autoinitialization = i8257_dma_has_autoinitialization; -diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs -index 9b5686b..1874b03 100644 ---- a/hw/i386/Makefile.objs -+++ b/hw/i386/Makefile.objs -@@ -4,7 +4,8 @@ obj-y += pc.o pc_piix.o pc_q35.o - obj-y += pc_sysfw.o - obj-y += x86-iommu.o - obj-$(CONFIG_VTD) += intel_iommu.o --obj-y += amd_iommu.o -+# Disabled in Red Hat Enterprise Linux -+# obj-y += amd_iommu.o - obj-$(CONFIG_XEN) += ../xenpv/ xen/ - - obj-y += kvmvapic.o -diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c -index 363d1b5..fc7212f 100644 ---- a/hw/i386/kvm/clock.c -+++ b/hw/i386/kvm/clock.c -@@ -289,6 +289,7 @@ static void kvmclock_class_init(ObjectClass *klass, void *data) - dc->realize = kvmclock_realize; - dc->vmsd = &kvmclock_vmsd; - dc->props = kvmclock_properties; -+ dc->user_creatable = false; /* RH state preserve */ - } - - static const TypeInfo kvmclock_info = { diff --git a/hw/i386/pc.c b/hw/i386/pc.c -index 64929ea..c568777 100644 +index d36bac8..ab4323d 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c -@@ -1593,8 +1593,9 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, - } +@@ -1525,8 +1525,9 @@ static void pc_superio_init(ISABus *isa_bus, bool create_fdctrl, bool no_vmport) + ISADevice *i8042, *port92, *vmmouse; serial_hds_isa_init(isa_bus, 0, MAX_SERIAL_PORTS); -+#if 0 /* Disabled for Red Hat Enterprise Linux 7 */ ++#if 0 /* Disabled for Red Hat Enterprise Linux */ parallel_hds_isa_init(isa_bus, MAX_PARALLEL_PORTS); - +#endif - a20_line = qemu_allocate_irqs(handle_a20_line_change, first_cpu, 2); - i8042 = isa_create_simple(isa_bus, "i8042"); - i8042_setup_a20_line(i8042, a20_line[0]); -diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c -index 406a1b5..2cb41fc 100644 ---- a/hw/ide/ahci.c -+++ b/hw/ide/ahci.c -@@ -1720,6 +1720,7 @@ static void sysbus_ahci_class_init(ObjectClass *klass, void *data) - dc->vmsd = &vmstate_sysbus_ahci; - dc->props = sysbus_ahci_properties; - dc->reset = sysbus_ahci_reset; -+ dc->user_creatable = false; /* RH state preserve */ - set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); - } - -@@ -1731,6 +1732,7 @@ static const TypeInfo sysbus_ahci_info = { - .class_init = sysbus_ahci_class_init, - }; - -+#if 0 /* Disabled in Red Hat Enterprise Linux */ - #define ALLWINNER_AHCI_BISTAFR ((0xa0 - ALLWINNER_AHCI_MMIO_OFF) / 4) - #define ALLWINNER_AHCI_BISTCR ((0xa4 - ALLWINNER_AHCI_MMIO_OFF) / 4) - #define ALLWINNER_AHCI_BISTFCTR ((0xa8 - ALLWINNER_AHCI_MMIO_OFF) / 4) -@@ -1824,11 +1826,14 @@ static const TypeInfo allwinner_ahci_info = { - .instance_init = allwinner_ahci_init, - .class_init = allwinner_ahci_class_init, - }; -+#endif - - static void sysbus_ahci_register_types(void) - { - type_register_static(&sysbus_ahci_info); -+#if 0 /* Disabled in Red Hat Enterprise Linux */ - type_register_static(&allwinner_ahci_info); -+#endif - } - - type_init(sysbus_ahci_register_types) + for (i = 0; i < MAX_FD; i++) { + fd[i] = drive_get(IF_FLOPPY, 0, i); + create_fdctrl |= !!fd[i]; diff --git a/hw/ide/piix.c b/hw/ide/piix.c -index 7e2d767..3184377 100644 +index a3afe1f..6de12ca 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c -@@ -254,7 +254,8 @@ static void piix3_ide_class_init(ObjectClass *klass, void *data) +@@ -253,7 +253,8 @@ static void piix3_ide_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_INTEL_82371SB_1; k->class_id = PCI_CLASS_STORAGE_IDE; set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); @@ -766,7 +625,7 @@ index 7e2d767..3184377 100644 } static const TypeInfo piix3_ide_info = { -@@ -281,6 +282,8 @@ static void piix4_ide_class_init(ObjectClass *klass, void *data) +@@ -280,6 +281,8 @@ static void piix4_ide_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_STORAGE_IDE; set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->hotpluggable = false; @@ -776,10 +635,10 @@ index 7e2d767..3184377 100644 static const TypeInfo piix4_ide_info = { diff --git a/hw/ide/via.c b/hw/ide/via.c -index 5b32ecb..c0ab568 100644 +index 117ac4d..b1bafe6 100644 --- a/hw/ide/via.c +++ b/hw/ide/via.c -@@ -220,6 +220,8 @@ static void via_ide_class_init(ObjectClass *klass, void *data) +@@ -217,6 +217,8 @@ static void via_ide_class_init(ObjectClass *klass, void *data) k->revision = 0x06; k->class_id = PCI_CLASS_STORAGE_IDE; set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); @@ -789,7 +648,7 @@ index 5b32ecb..c0ab568 100644 static const TypeInfo via_ide_info = { diff --git a/hw/input/pckbd.c b/hw/input/pckbd.c -index c479f82..62678f3 100644 +index f17f18e..66adb83 100644 --- a/hw/input/pckbd.c +++ b/hw/input/pckbd.c @@ -570,6 +570,8 @@ static void i8042_class_initfn(ObjectClass *klass, void *data) @@ -801,20 +660,8 @@ index c479f82..62678f3 100644 } static const TypeInfo i8042_info = { -diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c -index 348e0ea..467042f 100644 ---- a/hw/isa/isa-bus.c -+++ b/hw/isa/isa-bus.c -@@ -221,6 +221,7 @@ static void isabus_bridge_class_init(ObjectClass *klass, void *data) - - set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); - dc->fw_name = "isa"; -+ dc->user_creatable = false; /* RH state preserve */ - } - - static const TypeInfo isabus_bridge_info = { diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs -index 29fb922..a1007ae 100644 +index 00e834d..d7430cf 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -8,7 +8,7 @@ common-obj-$(CONFIG_ISA_TESTDEV) += pc-testdev.o @@ -823,14 +670,14 @@ index 29fb922..a1007ae 100644 -common-obj-y += unimp.o +#common-obj-y += unimp.o + common-obj-$(CONFIG_FW_CFG_DMA) += vmcoreinfo.o - obj-$(CONFIG_VMPORT) += vmport.o - + # ARM devices diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c -index 47a015f..33ef10b 100644 +index 16f0370..bfbfc0e 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c -@@ -850,6 +850,13 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp) +@@ -892,6 +892,13 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp) return; } @@ -844,7 +691,7 @@ index 47a015f..33ef10b 100644 pci_conf = dev->config; pci_conf[PCI_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEMORY; -@@ -1137,6 +1144,8 @@ static void ivshmem_doorbell_class_init(ObjectClass *klass, void *data) +@@ -1183,6 +1190,8 @@ static void ivshmem_doorbell_class_init(ObjectClass *klass, void *data) k->realize = ivshmem_doorbell_realize; dc->props = ivshmem_doorbell_properties; dc->vmsd = &ivshmem_doorbell_vmsd; @@ -853,7 +700,7 @@ index 47a015f..33ef10b 100644 } static const TypeInfo ivshmem_doorbell_info = { -@@ -1306,6 +1315,8 @@ static void ivshmem_class_init(ObjectClass *klass, void *data) +@@ -1352,6 +1361,8 @@ static void ivshmem_class_init(ObjectClass *klass, void *data) dc->desc = "Inter-VM shared memory (legacy)"; dc->props = ivshmem_properties; dc->vmsd = &ivshmem_vmsd; @@ -863,10 +710,10 @@ index 47a015f..33ef10b 100644 static const TypeInfo ivshmem_info = { diff --git a/hw/net/e1000.c b/hw/net/e1000.c -index 3d86146..d29e9ee 100644 +index 13a9494..742cd0a 100644 --- a/hw/net/e1000.c +++ b/hw/net/e1000.c -@@ -1704,6 +1704,7 @@ static const E1000Info e1000_devices[] = { +@@ -1768,6 +1768,7 @@ static const E1000Info e1000_devices[] = { .revision = 0x03, .phy_id2 = E1000_PHY_ID2_8254xx_DEFAULT, }, @@ -874,40 +721,40 @@ index 3d86146..d29e9ee 100644 { .name = "e1000-82544gc", .device_id = E1000_DEV_ID_82544GC_COPPER, -@@ -1716,6 +1717,7 @@ static const E1000Info e1000_devices[] = { +@@ -1780,6 +1781,7 @@ static const E1000Info e1000_devices[] = { .revision = 0x03, .phy_id2 = E1000_PHY_ID2_8254xx_DEFAULT, }, +#endif }; - static const TypeInfo e1000_default_info = { + static void e1000_register_types(void) diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c -index 6c42b44..2c91d07 100644 +index 16a9417..c934c22 100644 --- a/hw/net/e1000e.c +++ b/hw/net/e1000e.c -@@ -671,7 +671,7 @@ static void e1000e_class_init(ObjectClass *class, void *data) +@@ -673,7 +673,7 @@ static void e1000e_class_init(ObjectClass *class, void *data) c->vendor_id = PCI_VENDOR_ID_INTEL; c->device_id = E1000_DEV_ID_82574L; c->revision = 0; - c->romfile = "efi-e1000e.rom"; + c->romfile = "pxe-e1000e.rom"; c->class_id = PCI_CLASS_NETWORK_ETHERNET; - c->is_express = 1; + dc->desc = "Intel 82574L GbE Controller"; diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c -index 072a04e..90c50b0 100644 +index 0e60834..3ce4b14 100644 --- a/hw/pci-host/piix.c +++ b/hw/pci-host/piix.c -@@ -750,6 +750,7 @@ static const TypeInfo i440fx_info = { - .class_init = i440fx_class_init, +@@ -787,6 +787,7 @@ static const TypeInfo i440fx_info = { + }, }; +#if 0 /* Disabled in Red Hat Enterprise Linux */ /* IGD Passthrough Host Bridge. */ typedef struct { uint8_t offset; -@@ -838,6 +839,7 @@ static const TypeInfo igd_passthrough_i440fx_info = { +@@ -870,6 +871,7 @@ static const TypeInfo igd_passthrough_i440fx_info = { .instance_size = sizeof(PCII440FXState), .class_init = igd_passthrough_i440fx_class_init, }; @@ -915,7 +762,7 @@ index 072a04e..90c50b0 100644 static const char *i440fx_pcihost_root_bus_path(PCIHostState *host_bridge, PCIBus *rootbus) -@@ -882,7 +884,9 @@ static const TypeInfo i440fx_pcihost_info = { +@@ -915,7 +917,9 @@ static const TypeInfo i440fx_pcihost_info = { static void i440fx_register_types(void) { type_register_static(&i440fx_info); @@ -925,44 +772,24 @@ index 072a04e..90c50b0 100644 type_register_static(&piix3_pci_type_info); type_register_static(&piix3_info); type_register_static(&piix3_xen_info); -diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c -index 0e472f2..a91418c 100644 ---- a/hw/pci-host/q35.c -+++ b/hw/pci-host/q35.c -@@ -158,6 +158,7 @@ static void q35_host_class_init(ObjectClass *klass, void *data) - dc->user_creatable = false; - set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); - dc->fw_name = "pci"; -+ dc->user_creatable = false; /* RH state preserve */ - } - - static void q35_host_initfn(Object *obj) diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs -index 645ffdf..856cef5 100644 +index 86d82a6..a46a989 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -3,7 +3,7 @@ obj-y += ppc.o ppc_booke.o fdt.o # IBM pSeries (sPAPR) - obj-$(CONFIG_PSERIES) += spapr.o spapr_vio.o spapr_events.o + obj-$(CONFIG_PSERIES) += spapr.o spapr_caps.o spapr_vio.o spapr_events.o obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o -obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_rtc.o spapr_drc.o spapr_rng.o +obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_rtc.o spapr_drc.o obj-$(CONFIG_PSERIES) += spapr_cpu_core.o spapr_ovec.o # IBM PowerNV obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o pnv_core.o pnv_lpc.o pnv_psi.o pnv_occ.o pnv_bmc.o -@@ -13,7 +13,6 @@ endif - obj-$(CONFIG_PSERIES) += spapr_rtas_ddw.o - # PowerPC 4xx boards - obj-y += ppc4xx_devs.o ppc405_uc.o --obj-y += ppc4xx_pci.o - # PReP - obj-$(CONFIG_PREP) += prep.o - obj-$(CONFIG_PREP) += prep_systemio.o diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 268fd44..8d1cfcf 100644 +index a81570e..6a92b20 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c -@@ -1084,6 +1084,7 @@ static void *spapr_build_fdt(sPAPRMachineState *spapr, +@@ -1153,6 +1153,7 @@ static void *spapr_build_fdt(sPAPRMachineState *spapr, /* /vdevice */ spapr_dt_vdevice(spapr->vio_bus, fdt); @@ -970,7 +797,7 @@ index 268fd44..8d1cfcf 100644 if (object_resolve_path_type("", TYPE_SPAPR_RNG, NULL)) { ret = spapr_rng_populate_dt(fdt); if (ret < 0) { -@@ -1091,7 +1092,7 @@ static void *spapr_build_fdt(sPAPRMachineState *spapr, +@@ -1160,7 +1161,7 @@ static void *spapr_build_fdt(sPAPRMachineState *spapr, exit(1); } } @@ -980,39 +807,27 @@ index 268fd44..8d1cfcf 100644 ret = spapr_populate_pci_dt(phb, PHANDLE_XICP, fdt); if (ret < 0) { diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c -index ea278ce..3e731e4 100644 +index 94afeb3..1eda854 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c -@@ -264,6 +264,7 @@ err: - } - - static const char *spapr_core_models[] = { +@@ -240,10 +240,12 @@ static const TypeInfo spapr_cpu_core_type_infos[] = { + .instance_size = sizeof(sPAPRCPUCore), + .class_size = sizeof(sPAPRCPUCoreClass), + }, +#if 0 /* Disabled for Red Hat Enterprise Linux */ - /* 970 */ - "970_v2.2", - -@@ -276,6 +277,8 @@ static const char *spapr_core_models[] = { - /* POWER5+ */ - "POWER5+_v2.1", - -+ { .name = "POWER5+_v2.1", .initfn = spapr_cpu_core_POWER5plus_initfn }, + DEFINE_SPAPR_CPU_CORE_TYPE("970_v2.2"), + DEFINE_SPAPR_CPU_CORE_TYPE("970mp_v1.0"), + DEFINE_SPAPR_CPU_CORE_TYPE("970mp_v1.1"), + DEFINE_SPAPR_CPU_CORE_TYPE("power5+_v2.1"), +#endif - /* POWER7 */ - "POWER7_v2.3", - -@@ -290,7 +293,6 @@ static const char *spapr_core_models[] = { - - /* POWER8NVL */ - "POWER8NVL_v1.0", -- - /* POWER9 */ - "POWER9_v1.0", - }; + DEFINE_SPAPR_CPU_CORE_TYPE("power7_v2.3"), + DEFINE_SPAPR_CPU_CORE_TYPE("power7+_v2.1"), + DEFINE_SPAPR_CPU_CORE_TYPE("power8_v2.0"), diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c -index b1976fd..d85ff1d 100644 +index e51fbef..8720e46 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c -@@ -989,6 +989,8 @@ static void virtio_ccw_rng_realize(VirtioCcwDevice *ccw_dev, Error **errp) +@@ -927,6 +927,8 @@ static void virtio_ccw_rng_realize(VirtioCcwDevice *ccw_dev, Error **errp) NULL); } @@ -1021,16 +836,15 @@ index b1976fd..d85ff1d 100644 static void virtio_ccw_crypto_realize(VirtioCcwDevice *ccw_dev, Error **errp) { VirtIOCryptoCcw *dev = VIRTIO_CRYPTO_CCW(ccw_dev); -@@ -1007,6 +1009,8 @@ static void virtio_ccw_crypto_realize(VirtioCcwDevice *ccw_dev, Error **errp) +@@ -944,6 +946,7 @@ static void virtio_ccw_crypto_realize(VirtioCcwDevice *ccw_dev, Error **errp) + OBJECT(dev->vdev.conf.cryptodev), "cryptodev", NULL); } - +#endif -+ - /* DeviceState to VirtioCcwDevice. Note: used on datapath, - * be careful and test performance if you change this. - */ -@@ -1578,6 +1582,8 @@ static const TypeInfo virtio_ccw_rng = { + + static void virtio_ccw_gpu_realize(VirtioCcwDevice *ccw_dev, Error **errp) + { +@@ -1534,6 +1537,8 @@ static const TypeInfo virtio_ccw_rng = { .class_init = virtio_ccw_rng_class_init, }; @@ -1039,27 +853,26 @@ index b1976fd..d85ff1d 100644 static Property virtio_ccw_crypto_properties[] = { DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), -@@ -1616,6 +1622,8 @@ static const TypeInfo virtio_ccw_crypto = { +@@ -1571,6 +1576,7 @@ static const TypeInfo virtio_ccw_crypto = { + .instance_init = virtio_ccw_crypto_instance_init, .class_init = virtio_ccw_crypto_class_init, }; - +#endif -+ - static void virtio_ccw_busdev_realize(DeviceState *dev, Error **errp) - { - VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev; -@@ -1814,7 +1822,9 @@ static void virtio_ccw_register(void) + + static Property virtio_ccw_gpu_properties[] = { + DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, +@@ -1895,7 +1901,9 @@ static void virtio_ccw_register(void) #ifdef CONFIG_VHOST_VSOCK type_register_static(&vhost_vsock_ccw_info); #endif +#if 0 /* Disabled in Red Hat Enterprise Linux */ type_register_static(&virtio_ccw_crypto); +#endif - } - - type_init(virtio_ccw_register) + type_register_static(&virtio_ccw_gpu); + type_register_static(&virtio_ccw_input); + type_register_static(&virtio_ccw_input_hid); diff --git a/hw/usb/ccid-card-emulated.c b/hw/usb/ccid-card-emulated.c -index e646eb2..8d7205c 100644 +index ea42e46..f2d8b0d 100644 --- a/hw/usb/ccid-card-emulated.c +++ b/hw/usb/ccid-card-emulated.c @@ -588,6 +588,8 @@ static void emulated_class_initfn(ObjectClass *klass, void *data) @@ -1072,12 +885,12 @@ index e646eb2..8d7205c 100644 static const TypeInfo emulated_card_info = { diff --git a/hw/vfio/Makefile.objs b/hw/vfio/Makefile.objs -index c3ab909..4029072 100644 +index a2e7a0a..b25ca64 100644 --- a/hw/vfio/Makefile.objs +++ b/hw/vfio/Makefile.objs @@ -2,8 +2,5 @@ ifeq ($(CONFIG_LINUX), y) obj-$(CONFIG_SOFTMMU) += common.o - obj-$(CONFIG_PCI) += pci.o pci-quirks.o + obj-$(CONFIG_PCI) += pci.o pci-quirks.o display.o obj-$(CONFIG_VFIO_CCW) += ccw.o -obj-$(CONFIG_SOFTMMU) += platform.o -obj-$(CONFIG_VFIO_XGMAC) += calxeda-xgmac.o @@ -1085,10 +898,10 @@ index c3ab909..4029072 100644 obj-$(CONFIG_SOFTMMU) += spapr.o endif diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c -index 349085e..58046e6 100644 +index e5779a7..cb2f79c 100644 --- a/hw/vfio/pci-quirks.c +++ b/hw/vfio/pci-quirks.c -@@ -1189,6 +1189,8 @@ static void vfio_pci_igd_lpc_bridge_class_init(ObjectClass *klass, void *data) +@@ -1193,6 +1193,8 @@ static void vfio_pci_igd_lpc_bridge_class_init(ObjectClass *klass, void *data) set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->desc = "VFIO dummy ISA/LPC bridge for IGD assignment"; dc->hotpluggable = false; @@ -1097,7 +910,7 @@ index 349085e..58046e6 100644 k->realize = vfio_pci_igd_lpc_bridge_realize; k->class_id = PCI_CLASS_BRIDGE_ISA; } -@@ -1378,6 +1380,9 @@ static void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr) +@@ -1386,6 +1388,9 @@ static void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr) 0, PCI_DEVFN(0x2, 0))) { return; } @@ -1123,23 +936,51 @@ index 765d363..a5a0936 100644 endif common-obj-$(call lnot,$(CONFIG_LINUX)) += vhost-stub.o -diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c -index 5807aa8..62df6c2 100644 ---- a/hw/virtio/virtio-mmio.c -+++ b/hw/virtio/virtio-mmio.c -@@ -448,6 +448,7 @@ static void virtio_mmio_class_init(ObjectClass *klass, void *data) - - dc->realize = virtio_mmio_realizefn; - dc->reset = virtio_mmio_reset; -+ dc->user_creatable = false; /* RH state preserve */ - set_bit(DEVICE_CATEGORY_MISC, dc->categories); - dc->props = virtio_mmio_properties; - } +diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c +index 1e8ab7b..e3e49d6 100644 +--- a/hw/virtio/virtio-pci.c ++++ b/hw/virtio/virtio-pci.c +@@ -1983,7 +1983,7 @@ static const TypeInfo virtio_blk_pci_info = { + .class_init = virtio_blk_pci_class_init, + }; + +-#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX) ++#if defined(CONFIG_VHOST_USER_BLK) + /* vhost-user-blk */ + + static Property vhost_user_blk_pci_properties[] = { +@@ -2163,7 +2163,7 @@ static const TypeInfo vhost_scsi_pci_info = { + }; + #endif + +-#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX) ++#if defined(CONFIG_VHOST_USER_SCSI) + /* vhost-user-scsi-pci */ + static Property vhost_user_scsi_pci_properties[] = { + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, +@@ -2686,7 +2686,7 @@ static void virtio_pci_register_types(void) + type_register_static(&virtio_9p_pci_info); + #endif + type_register_static(&virtio_blk_pci_info); +-#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX) ++#if defined(CONFIG_VHOST_USER_BLK) + type_register_static(&vhost_user_blk_pci_info); + #endif + type_register_static(&virtio_scsi_pci_info); +@@ -2696,7 +2696,7 @@ static void virtio_pci_register_types(void) + #ifdef CONFIG_VHOST_SCSI + type_register_static(&vhost_scsi_pci_info); + #endif +-#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX) ++#if defined(CONFIG_VHOST_USER_SCSI) + type_register_static(&vhost_user_scsi_pci_info); + #endif + #ifdef CONFIG_VHOST_VSOCK diff --git a/qemu-options.hx b/qemu-options.hx -index 9f6e2ad..568fc7c 100644 +index ca4e412..2042dba 100644 --- a/qemu-options.hx +++ b/qemu-options.hx -@@ -1820,11 +1820,6 @@ ETEXI +@@ -1811,11 +1811,6 @@ ETEXI DEF("no-hpet", 0, QEMU_OPTION_no_hpet, "-no-hpet disable HPET\n", QEMU_ARCH_I386) @@ -1152,22 +993,22 @@ index 9f6e2ad..568fc7c 100644 DEF("acpitable", HAS_ARG, QEMU_OPTION_acpitable, "-acpitable [sig=str][,rev=n][,oem_id=str][,oem_table_id=str][,oem_rev=n][,asl_compiler_id=str][,asl_compiler_rev=n][,{data|file}=file1[:file2]...]\n" diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs -index b24da3b..7e9f94d 100644 +index 2d59d84..dfdfca7 100644 --- a/stubs/Makefile.objs +++ b/stubs/Makefile.objs -@@ -41,3 +41,4 @@ stub-obj-y += vmgenid.o - stub-obj-y += xen-common.o +@@ -43,3 +43,4 @@ stub-obj-y += xen-common.o stub-obj-y += xen-hvm.o - stub-obj-y += shadow-bios.o + stub-obj-y += pci-host-piix.o + stub-obj-y += ram-block.o +stub-obj-y += ide-isa.o diff --git a/stubs/ide-isa.c b/stubs/ide-isa.c new file mode 100644 -index 0000000..5dacaa5 +index 0000000..9fd50ef --- /dev/null +++ b/stubs/ide-isa.c @@ -0,0 +1,13 @@ -+#include -+#include ++#include "qemu/osdep.h" ++#include "hw/ide.h" +#include + +ISADevice *isa_ide_init(ISABus *bus, int iobase, int iobase2, int isairq, @@ -1180,11 +1021,11 @@ index 0000000..5dacaa5 + abort(); +} diff --git a/target/arm/cpu.c b/target/arm/cpu.c -index 05c038b..3f90b7e 100644 +index 022d8c5..4255e9c 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c -@@ -1724,7 +1724,9 @@ static void arm_cpu_register_types(void) - type_register_static(&arm_cpu_type_info); +@@ -1953,7 +1953,9 @@ static void arm_cpu_register_types(void) + type_register_static(&idau_interface_type_info); while (info->name) { - cpu_register(info); @@ -1193,39 +1034,61 @@ index 05c038b..3f90b7e 100644 + cpu_register(info); info++; } - } + diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 7f52680..670d121 100644 +index a20fe26..f483a71 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c -@@ -772,11 +772,8 @@ static X86CPUDefinition builtin_x86_defs[] = { - CPUID_CX8 | CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | - CPUID_PSE | CPUID_DE | CPUID_FP87, - .features[FEAT_1_ECX] = CPUID_EXT_CX16 | CPUID_EXT_SSE3, -- .features[FEAT_8000_0001_EDX] = CPUID_EXT2_LM | CPUID_EXT2_FXSR | -- CPUID_EXT2_MMX | CPUID_EXT2_NX | CPUID_EXT2_PAT | CPUID_EXT2_CMOV | -- CPUID_EXT2_PGE | CPUID_EXT2_SYSCALL | CPUID_EXT2_APIC | -- CPUID_EXT2_CX8 | CPUID_EXT2_MCE | CPUID_EXT2_PAE | CPUID_EXT2_MSR | CPUID_EXT2_TSC | -- CPUID_EXT2_PSE | CPUID_EXT2_DE | CPUID_EXT2_FPU, +@@ -825,14 +825,14 @@ static X86CPUDefinition builtin_x86_defs[] = { + .family = 6, + .model = 6, + .stepping = 3, +- .features[FEAT_1_EDX] = +- PPRO_FEATURES | +- CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | +- CPUID_PSE36, +- .features[FEAT_1_ECX] = +- CPUID_EXT_SSE3 | CPUID_EXT_CX16, +- .features[FEAT_8000_0001_EDX] = +- CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX, ++ .features[FEAT_1_EDX] = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | ++ CPUID_MMX | CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | ++ CPUID_MCA | CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | ++ CPUID_CX8 | CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | ++ CPUID_PSE | CPUID_DE | CPUID_FP87, ++ .features[FEAT_1_ECX] = CPUID_EXT_CX16 | CPUID_EXT_SSE3, + .features[FEAT_8000_0001_EDX] = CPUID_EXT2_LM | CPUID_EXT2_NX | + CPUID_EXT2_SYSCALL, .features[FEAT_8000_0001_ECX] = CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM, .xlevel = 0x8000000A, -@@ -1014,11 +1011,7 @@ static X86CPUDefinition builtin_x86_defs[] = { - CPUID_CX8 | CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | - CPUID_PSE | CPUID_DE | CPUID_FP87, - .features[FEAT_1_ECX] = CPUID_EXT_CX16 | CPUID_EXT_SSE3, -- .features[FEAT_8000_0001_EDX] = CPUID_EXT2_LM | CPUID_EXT2_FXSR | -- CPUID_EXT2_MMX | CPUID_EXT2_NX | CPUID_EXT2_PAT | CPUID_EXT2_CMOV | -- CPUID_EXT2_PGE | CPUID_EXT2_SYSCALL | CPUID_EXT2_APIC | -- CPUID_EXT2_CX8 | CPUID_EXT2_MCE | CPUID_EXT2_PAE | CPUID_EXT2_MSR | CPUID_EXT2_TSC | -- CPUID_EXT2_PSE | CPUID_EXT2_DE | CPUID_EXT2_FPU, +@@ -1062,6 +1062,25 @@ static X86CPUDefinition builtin_x86_defs[] = { + .model_id = "Intel(R) Atom(TM) CPU N270 @ 1.60GHz", + }, + { ++ .name = "cpu64-rhel6", ++ .level = 4, ++ .vendor = CPUID_VENDOR_AMD, ++ .family = 6, ++ .model = 13, ++ .stepping = 3, ++ .features[FEAT_1_EDX] = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | ++ CPUID_MMX | CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | ++ CPUID_MCA | CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | ++ CPUID_CX8 | CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | ++ CPUID_PSE | CPUID_DE | CPUID_FP87, ++ .features[FEAT_1_ECX] = CPUID_EXT_CX16 | CPUID_EXT_SSE3, + .features[FEAT_8000_0001_EDX] = CPUID_EXT2_LM | CPUID_EXT2_NX | CPUID_EXT2_SYSCALL, - .features[FEAT_8000_0001_ECX] = CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | - CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM, - .xlevel = 0x8000000A, -@@ -4113,11 +4106,13 @@ static Property x86_cpu_properties[] = { ++ .features[FEAT_8000_0001_ECX] = CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | ++ CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM, ++ .xlevel = 0x8000000A, ++ .model_id = "QEMU Virtual CPU version (cpu64-rhel6)", ++ }, ++ { + .name = "Conroe", + .level = 10, + .vendor = CPUID_VENDOR_INTEL, +@@ -4764,11 +4783,13 @@ static Property x86_cpu_properties[] = { DEFINE_PROP_BOOL("hv-vapic", X86CPU, hyperv_vapic, false), DEFINE_PROP_BOOL("hv-time", X86CPU, hyperv_time, false), DEFINE_PROP_BOOL("hv-crash", X86CPU, hyperv_crash, false), @@ -1236,14 +1099,14 @@ index 7f52680..670d121 100644 DEFINE_PROP_BOOL("hv-synic", X86CPU, hyperv_synic, false), DEFINE_PROP_BOOL("hv-stimer", X86CPU, hyperv_stimer, false), +#endif + DEFINE_PROP_BOOL("hv-frequencies", X86CPU, hyperv_frequencies, false), DEFINE_PROP_BOOL("check", X86CPU, check_cpuid, true), DEFINE_PROP_BOOL("enforce", X86CPU, enforce_cpuid, false), - DEFINE_PROP_BOOL("kvm", X86CPU, expose_kvm, true), diff --git a/target/ppc/cpu-models.c b/target/ppc/cpu-models.c -index 4d3e635..08a1f59 100644 +index 6c9bfde..77cb298 100644 --- a/target/ppc/cpu-models.c +++ b/target/ppc/cpu-models.c -@@ -70,6 +70,7 @@ +@@ -65,6 +65,7 @@ #define POWERPC_DEF(_name, _pvr, _type, _desc) \ POWERPC_DEF_SVR(_name, _desc, _pvr, POWERPC_SVR_NONE, _type) @@ -1251,75 +1114,69 @@ index 4d3e635..08a1f59 100644 /* Embedded PowerPC */ /* PowerPC 401 family */ POWERPC_DEF("401", CPU_POWERPC_401, 401, -@@ -1101,8 +1102,10 @@ +@@ -739,10 +740,13 @@ "PowerPC 7447A v1.2 (G4)") - POWERPC_DEF("7457A_v1.2", CPU_POWERPC_74x7A_v12, 7455, + POWERPC_DEF("7457a_v1.2", CPU_POWERPC_74x7A_v12, 7455, "PowerPC 7457A v1.2 (G4)") +#endif /* 64 bits PowerPC */ #if defined (TARGET_PPC64) +#if 0 /* Disabled for Red Hat Enterprise Linux */ - #if defined(TODO) - POWERPC_DEF("620", CPU_POWERPC_620, 620, - "PowerPC 620") -@@ -1131,6 +1134,7 @@ - POWERPC_DEF("POWER6", CPU_POWERPC_POWER6, POWER6, - "POWER6") - #endif + POWERPC_DEF("power5+_v2.1", CPU_POWERPC_POWER5P_v21, POWER5P, + "POWER5+ v2.1") +#endif - POWERPC_DEF("POWER7_v2.3", CPU_POWERPC_POWER7_v23, POWER7, + POWERPC_DEF("power7_v2.3", CPU_POWERPC_POWER7_v23, POWER7, "POWER7 v2.3") - POWERPC_DEF("POWER7+_v2.1", CPU_POWERPC_POWER7P_v21, POWER7, -@@ -1141,12 +1145,15 @@ + POWERPC_DEF("power7+_v2.1", CPU_POWERPC_POWER7P_v21, POWER7, +@@ -753,14 +757,17 @@ "POWER8 v2.0") - POWERPC_DEF("POWER8NVL_v1.0",CPU_POWERPC_POWER8NVL_v10, POWER8, + POWERPC_DEF("power8nvl_v1.0", CPU_POWERPC_POWER8NVL_v10, POWER8, "POWER8NVL v1.0") +#if 0 /* Disabled for Red Hat Enterprise Linux */ POWERPC_DEF("970_v2.2", CPU_POWERPC_970_v22, 970, "PowerPC 970 v2.2") +#endif - POWERPC_DEF("POWER9_v1.0", CPU_POWERPC_POWER9_BASE, POWER9, + POWERPC_DEF("power9_v1.0", CPU_POWERPC_POWER9_DD1, POWER9, "POWER9 v1.0") + POWERPC_DEF("power9_v2.0", CPU_POWERPC_POWER9_DD20, POWER9, + "POWER9 v2.0") +#if 0 /* Disabled for Red Hat Enterprise Linux */ POWERPC_DEF("970fx_v1.0", CPU_POWERPC_970FX_v10, 970, "PowerPC 970FX v1.0 (G5)") POWERPC_DEF("970fx_v2.0", CPU_POWERPC_970FX_v20, 970, -@@ -1161,6 +1168,7 @@ +@@ -775,12 +782,14 @@ "PowerPC 970MP v1.0") POWERPC_DEF("970mp_v1.1", CPU_POWERPC_970MP_v11, 970, "PowerPC 970MP v1.1") +#endif - #if defined(TODO) - POWERPC_DEF("Cell", CPU_POWERPC_CELL, 970, - "PowerPC Cell") -@@ -1226,6 +1234,7 @@ + #endif /* defined (TARGET_PPC64) */ + + /***************************************************************************/ /* PowerPC CPU aliases */ PowerPCCPUAlias ppc_cpu_aliases[] = { +#if 0 /* Embedded and 32-bit CPUs disabled for Red Hat Enterprise Linux */ - { "403", "403GC" }, - { "405", "405D4" }, - { "405CR", "405CRc" }, -@@ -1381,22 +1390,27 @@ PowerPCCPUAlias ppc_cpu_aliases[] = { - { "7447A", "7447A_v1.2" }, - { "7457A", "7457A_v1.2" }, - { "Apollo7PM", "7457A_v1.0" }, + { "403", "403gc" }, + { "405", "405d4" }, + { "405cr", "405crc" }, +@@ -939,20 +948,25 @@ PowerPCCPUAlias ppc_cpu_aliases[] = { + { "7447a", "7447a_v1.2" }, + { "7457a", "7457a_v1.2" }, + { "apollo7pm", "7457a_v1.0" }, +#endif #if defined(TARGET_PPC64) +#if 0 /* Disabled for Red Hat Enterprise Linux */ - { "POWER3", "630" }, - { "POWER3+", "631" }, - { "POWER5+", "POWER5+_v2.1" }, - { "POWER5gs", "POWER5+_v2.1" }, + { "power5+", "power5+_v2.1" }, + { "power5gs", "power5+_v2.1" }, +#endif - { "POWER7", "POWER7_v2.3" }, - { "POWER7+", "POWER7+_v2.1" }, - { "POWER8E", "POWER8E_v2.1" }, - { "POWER8", "POWER8_v2.0" }, - { "POWER8NVL", "POWER8NVL_v1.0" }, - { "POWER9", "POWER9_v1.0" }, + { "power7", "power7_v2.3" }, + { "power7+", "power7+_v2.1" }, + { "power8e", "power8e_v2.1" }, + { "power8", "power8_v2.0" }, + { "power8nvl", "power8nvl_v1.0" }, + { "power9", "power9_v2.0" }, +#if 0 /* Disabled for Red Hat Enterprise Linux */ { "970", "970_v2.2" }, { "970fx", "970fx_v3.1" }, @@ -1330,19 +1187,52 @@ index 4d3e635..08a1f59 100644 +#if 0 /* Disabled for Red Hat Enterprise Linux */ /* Generic PowerPCs */ #if defined(TARGET_PPC64) - { "ppc64", "970fx" }, -@@ -1404,5 +1418,6 @@ PowerPCCPUAlias ppc_cpu_aliases[] = { + { "ppc64", "970fx_v3.1" }, +@@ -960,5 +974,6 @@ PowerPCCPUAlias ppc_cpu_aliases[] = { { "ppc32", "604" }, - { "ppc", "ppc32" }, - { "default", "ppc" }, + { "ppc", "604" }, + { "default", "604" }, +#endif { NULL, NULL } }; +diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c +index 2741b68..c4016e0 100644 +--- a/target/s390x/cpu_models.c ++++ b/target/s390x/cpu_models.c +@@ -372,6 +372,9 @@ static void check_unavailable_features(const S390CPUModel *max_model, + (max_model->def->gen == model->def->gen && + max_model->def->ec_ga < model->def->ec_ga)) { + list_add_feat("type", unavailable); ++ } else if (model->def->gen < 11 && kvm_enabled()) { ++ /* Older CPU models are not supported on Red Hat Enterprise Linux */ ++ list_add_feat("type", unavailable); + } + + /* detect missing features if any to properly report them */ +diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c +index fb59d92..fbccceb 100644 +--- a/target/s390x/kvm.c ++++ b/target/s390x/kvm.c +@@ -2285,6 +2285,14 @@ void kvm_s390_apply_cpu_model(const S390CPUModel *model, Error **errp) + error_setg(errp, "KVM doesn't support CPU models"); + return; + } ++ ++ /* Older CPU models are not supported on Red Hat Enterprise Linux */ ++ if (model->def->gen < 11) { ++ error_setg(errp, "KVM: Unsupported CPU type specified: %s", ++ MACHINE(qdev_get_machine())->cpu_type); ++ return; ++ } ++ + prop.cpuid = s390_cpuid_from_cpu_model(model); + prop.ibc = s390_ibc_from_cpu_model(model); + /* configure cpu features indicated via STFL(e) */ diff --git a/tests/Makefile.include b/tests/Makefile.include -index 37c1bed..327ffd9 100644 +index 3b9a5e3..e4125a6 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include -@@ -166,8 +166,6 @@ check-qtest-generic-y += tests/device-introspect-test$(EXESUF) +@@ -181,8 +181,6 @@ check-qtest-generic-y += tests/device-introspect-test$(EXESUF) gcov-files-generic-y = qdev-monitor.c qmp.c gcov-files-ipack-y += hw/ipack/ipack.c @@ -1351,7 +1241,7 @@ index 37c1bed..327ffd9 100644 check-qtest-virtioserial-y += tests/virtio-console-test$(EXESUF) gcov-files-virtioserial-y += hw/char/virtio-console.c -@@ -199,23 +197,10 @@ check-qtest-pci-y += tests/e1000e-test$(EXESUF) +@@ -214,23 +212,10 @@ check-qtest-pci-y += tests/e1000e-test$(EXESUF) gcov-files-pci-y += hw/net/e1000e.c hw/net/e1000e_core.c check-qtest-pci-y += tests/rtl8139-test$(EXESUF) gcov-files-pci-y += hw/net/rtl8139.c @@ -1375,7 +1265,7 @@ index 37c1bed..327ffd9 100644 check-qtest-pci-y += $(check-qtest-ipack-y) gcov-files-pci-y += $(gcov-files-ipack-y) check-qtest-pci-y += tests/display-vga-test$(EXESUF) -@@ -229,23 +214,21 @@ check-qtest-pci-y += tests/intel-hda-test$(EXESUF) +@@ -244,23 +229,21 @@ check-qtest-pci-y += tests/intel-hda-test$(EXESUF) gcov-files-pci-y += hw/audio/intel-hda.c hw/audio/hda-codec.c check-qtest-pci-$(CONFIG_IVSHMEM) += tests/ivshmem-test$(EXESUF) gcov-files-pci-y += hw/misc/ivshmem.c @@ -1404,7 +1294,7 @@ index 37c1bed..327ffd9 100644 check-qtest-i386-y += tests/i440fx-test$(EXESUF) check-qtest-i386-y += tests/fw_cfg-test$(EXESUF) check-qtest-i386-y += tests/drive_del-test$(EXESUF) -@@ -254,8 +237,6 @@ check-qtest-i386-y += tests/tco-test$(EXESUF) +@@ -269,8 +252,6 @@ check-qtest-i386-y += tests/tco-test$(EXESUF) gcov-files-i386-y += hw/watchdog/watchdog.c hw/watchdog/wdt_ib700.c check-qtest-i386-y += $(check-qtest-pci-y) gcov-files-i386-y += $(gcov-files-pci-y) @@ -1413,7 +1303,7 @@ index 37c1bed..327ffd9 100644 gcov-files-i386-y += hw/net/net_rx_pkt.c gcov-files-i386-y += hw/net/net_tx_pkt.c check-qtest-i386-y += tests/pvpanic-test$(EXESUF) -@@ -264,8 +245,6 @@ check-qtest-i386-y += tests/i82801b11-test$(EXESUF) +@@ -279,8 +260,6 @@ check-qtest-i386-y += tests/i82801b11-test$(EXESUF) gcov-files-i386-y += hw/pci-bridge/i82801b11.c check-qtest-i386-y += tests/ioh3420-test$(EXESUF) gcov-files-i386-y += hw/pci-bridge/ioh3420.c @@ -1422,7 +1312,16 @@ index 37c1bed..327ffd9 100644 check-qtest-i386-y += tests/usb-hcd-uhci-test$(EXESUF) gcov-files-i386-y += hw/usb/hcd-uhci.c check-qtest-i386-y += tests/usb-hcd-ehci-test$(EXESUF) -@@ -302,7 +281,7 @@ check-qtest-mips64el-y = tests/endianness-test$(EXESUF) +@@ -306,7 +285,7 @@ check-qtest-i386-y += tests/migration-test$(EXESUF) + check-qtest-i386-y += tests/test-x86-cpuid-compat$(EXESUF) + check-qtest-i386-y += tests/numa-test$(EXESUF) + check-qtest-x86_64-y += $(check-qtest-i386-y) +-check-qtest-x86_64-y += tests/sdhci-test$(EXESUF) ++#check-qtest-x86_64-y += tests/sdhci-test$(EXESUF) + gcov-files-i386-y += i386-softmmu/hw/timer/mc146818rtc.c + gcov-files-x86_64-y = $(subst i386-softmmu/,x86_64-softmmu/,$(gcov-files-i386-y)) + +@@ -328,7 +307,7 @@ check-qtest-moxie-y = tests/boot-serial-test$(EXESUF) check-qtest-ppc-y = tests/endianness-test$(EXESUF) check-qtest-ppc-y += tests/boot-order-test$(EXESUF) @@ -1430,18 +1329,9 @@ index 37c1bed..327ffd9 100644 +#check-qtest-ppc-y += tests/prom-env-test$(EXESUF) check-qtest-ppc-y += tests/drive_del-test$(EXESUF) check-qtest-ppc-y += tests/boot-serial-test$(EXESUF) - -@@ -310,32 +289,32 @@ check-qtest-ppc64-y = tests/spapr-phb-test$(EXESUF) - gcov-files-ppc64-y = ppc64-softmmu/hw/ppc/spapr_pci.c - check-qtest-ppc64-y += tests/endianness-test$(EXESUF) - check-qtest-ppc64-y += tests/boot-order-test$(EXESUF) --check-qtest-ppc64-y += tests/prom-env-test$(EXESUF) --check-qtest-ppc64-y += tests/pnv-xscom-test$(EXESUF) -+#check-qtest-ppc64-y += tests/prom-env-test$(EXESUF) -+#check-qtest-ppc64-y += tests/pnv-xscom-test$(EXESUF) - check-qtest-ppc64-y += tests/drive_del-test$(EXESUF) - check-qtest-ppc64-y += tests/postcopy-test$(EXESUF) - check-qtest-ppc64-y += tests/boot-serial-test$(EXESUF) + check-qtest-ppc-y += tests/m48t59-test$(EXESUF) +@@ -342,19 +321,19 @@ check-qtest-ppc64-y += tests/pnv-xscom-test$(EXESUF) + check-qtest-ppc64-y += tests/migration-test$(EXESUF) check-qtest-ppc64-y += tests/rtas-test$(EXESUF) check-qtest-ppc64-$(CONFIG_SLIRP) += tests/pxe-test$(EXESUF) -check-qtest-ppc64-y += tests/usb-hcd-ohci-test$(EXESUF) @@ -1454,35 +1344,33 @@ index 37c1bed..327ffd9 100644 gcov-files-ppc64-y += hw/usb/hcd-xhci.c check-qtest-ppc64-y += $(check-qtest-virtio-y) -check-qtest-ppc64-$(CONFIG_SLIRP) += tests/test-netfilter$(EXESUF) --check-qtest-ppc64-y += tests/test-filter-mirror$(EXESUF) --check-qtest-ppc64-y += tests/test-filter-redirector$(EXESUF) +-check-qtest-ppc64-$(CONFIG_POSIX) += tests/test-filter-mirror$(EXESUF) +-check-qtest-ppc64-$(CONFIG_POSIX) += tests/test-filter-redirector$(EXESUF) +#check-qtest-ppc64-$(CONFIG_SLIRP) += tests/test-netfilter$(EXESUF) -+#check-qtest-ppc64-y += tests/test-filter-mirror$(EXESUF) -+#check-qtest-ppc64-y += tests/test-filter-redirector$(EXESUF) ++#check-qtest-ppc64-$(CONFIG_POSIX) += tests/test-filter-mirror$(EXESUF) ++#check-qtest-ppc64-$(CONFIG_POSIX) += tests/test-filter-redirector$(EXESUF) check-qtest-ppc64-y += tests/display-vga-test$(EXESUF) check-qtest-ppc64-y += tests/numa-test$(EXESUF) -check-qtest-ppc64-$(CONFIG_IVSHMEM) += tests/ivshmem-test$(EXESUF) +#check-qtest-ppc64-$(CONFIG_IVSHMEM) += tests/ivshmem-test$(EXESUF) + check-qtest-ppc64-y += tests/cpu-plug-test$(EXESUF) check-qtest-sh4-y = tests/endianness-test$(EXESUF) - - check-qtest-sh4eb-y = tests/endianness-test$(EXESUF) - --check-qtest-sparc-y = tests/prom-env-test$(EXESUF) -+#check-qtest-sparc-y = tests/prom-env-test$(EXESUF) - #check-qtest-sparc-y += tests/m48t59-test$(EXESUF) - #gcov-files-sparc-y = hw/timer/m48t59.c - -@@ -353,7 +332,7 @@ gcov-files-arm-y += arm-softmmu/hw/block/virtio-blk.c +@@ -379,10 +358,10 @@ gcov-files-arm-y += arm-softmmu/hw/block/virtio-blk.c check-qtest-arm-y += tests/test-arm-mptimer$(EXESUF) gcov-files-arm-y += hw/timer/arm_mptimer.c + check-qtest-arm-y += tests/boot-serial-test$(EXESUF) +-check-qtest-arm-y += tests/sdhci-test$(EXESUF) ++#check-qtest-arm-y += tests/sdhci-test$(EXESUF) -check-qtest-aarch64-y = tests/numa-test$(EXESUF) +-check-qtest-aarch64-y += tests/sdhci-test$(EXESUF) +#check-qtest-aarch64-y = tests/numa-test$(EXESUF) ++#check-qtest-aarch64-y += tests/sdhci-test$(EXESUF) + check-qtest-aarch64-y += tests/boot-serial-test$(EXESUF) check-qtest-microblazeel-y = $(check-qtest-microblaze-y) - -@@ -716,17 +695,15 @@ tests/rtc-test$(EXESUF): tests/rtc-test.o +@@ -757,17 +736,15 @@ tests/rtc-test$(EXESUF): tests/rtc-test.o tests/m48t59-test$(EXESUF): tests/m48t59-test.o tests/endianness-test$(EXESUF): tests/endianness-test.o tests/spapr-phb-test$(EXESUF): tests/spapr-phb-test.o $(libqos-obj-y) @@ -1503,7 +1391,7 @@ index 37c1bed..327ffd9 100644 tests/boot-sector.o tests/acpi-utils.o $(libqos-obj-y) tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y) tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y) -@@ -738,11 +715,8 @@ tests/fw_cfg-test$(EXESUF): tests/fw_cfg-test.o $(libqos-pc-obj-y) +@@ -779,11 +756,8 @@ tests/fw_cfg-test$(EXESUF): tests/fw_cfg-test.o $(libqos-pc-obj-y) tests/e1000-test$(EXESUF): tests/e1000-test.o tests/e1000e-test$(EXESUF): tests/e1000e-test.o $(libqos-pc-obj-y) tests/rtl8139-test$(EXESUF): tests/rtl8139-test.o $(libqos-pc-obj-y) @@ -1515,17 +1403,10 @@ index 37c1bed..327ffd9 100644 -tests/ne2000-test$(EXESUF): tests/ne2000-test.o tests/wdt_ib700-test$(EXESUF): tests/wdt_ib700-test.o tests/tco-test$(EXESUF): tests/tco-test.o $(libqos-pc-obj-y) - tests/virtio-balloon-test$(EXESUF): tests/virtio-balloon-test.o -@@ -753,21 +727,17 @@ tests/virtio-scsi-test$(EXESUF): tests/virtio-scsi-test.o $(libqos-virtio-obj-y) - tests/virtio-9p-test$(EXESUF): tests/virtio-9p-test.o $(libqos-virtio-obj-y) - tests/virtio-serial-test$(EXESUF): tests/virtio-serial-test.o - tests/virtio-console-test$(EXESUF): tests/virtio-console-test.o --tests/tpci200-test$(EXESUF): tests/tpci200-test.o - tests/display-vga-test$(EXESUF): tests/display-vga-test.o - tests/ipoctal232-test$(EXESUF): tests/ipoctal232-test.o - tests/qom-test$(EXESUF): tests/qom-test.o - tests/test-hmp$(EXESUF): tests/test-hmp.o - tests/drive_del-test$(EXESUF): tests/drive_del-test.o $(libqos-pc-obj-y) + tests/virtio-balloon-test$(EXESUF): tests/virtio-balloon-test.o $(libqos-virtio-obj-y) +@@ -802,14 +776,11 @@ tests/test-hmp$(EXESUF): tests/test-hmp.o + tests/machine-none-test$(EXESUF): tests/machine-none-test.o + tests/drive_del-test$(EXESUF): tests/drive_del-test.o $(libqos-virtio-obj-y) tests/qdev-monitor-test$(EXESUF): tests/qdev-monitor-test.o $(libqos-pc-obj-y) -tests/nvme-test$(EXESUF): tests/nvme-test.o tests/pvpanic-test$(EXESUF): tests/pvpanic-test.o @@ -1538,20 +1419,28 @@ index 37c1bed..327ffd9 100644 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) -@@ -785,7 +755,7 @@ tests/test-filter-mirror$(EXESUF): tests/test-filter-mirror.o $(qtest-obj-y) +@@ -827,14 +798,14 @@ 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/megasas-test$(EXESUF): tests/megasas-test.o $(libqos-spapr-obj-y) $(libqos-pc-obj-y) +#tests/megasas-test$(EXESUF): tests/megasas-test.o $(libqos-spapr-obj-y) $(libqos-pc-obj-y) - tests/vhost-user-bridge$(EXESUF): tests/vhost-user-bridge.o contrib/libvhost-user/libvhost-user.o $(test-util-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 + tests/test-qapi-util$(EXESUF): tests/test-qapi-util.o $(test-util-obj-y) + tests/numa-test$(EXESUF): tests/numa-test.o + tests/vmgenid-test$(EXESUF): tests/vmgenid-test.o tests/boot-sector.o tests/acpi-utils.o +-tests/sdhci-test$(EXESUF): tests/sdhci-test.o $(libqos-pc-obj-y) ++#tests/sdhci-test$(EXESUF): tests/sdhci-test.o $(libqos-pc-obj-y) + + tests/migration/stress$(EXESUF): tests/migration/stress.o + $(call quiet-command, $(LINKPROG) -static -O3 $(PTHREAD_LIB) -o $@ $< ,"LINK","$(TARGET_DIR)$@") diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c -index 564da45..ede777a 100644 +index bf3e193..715f90c 100644 --- a/tests/bios-tables-test.c +++ b/tests/bios-tables-test.c -@@ -743,6 +743,7 @@ static void test_acpi_q35_tcg_cphp(void) +@@ -736,6 +736,7 @@ static void test_acpi_q35_tcg_cphp(void) free_test_data(&data); } @@ -1559,7 +1448,7 @@ index 564da45..ede777a 100644 static uint8_t ipmi_required_struct_types[] = { 0, 1, 3, 4, 16, 17, 19, 32, 38, 127 }; -@@ -779,6 +780,7 @@ static void test_acpi_piix4_tcg_ipmi(void) +@@ -772,6 +773,7 @@ static void test_acpi_piix4_tcg_ipmi(void) &data); free_test_data(&data); } @@ -1567,7 +1456,7 @@ index 564da45..ede777a 100644 static void test_acpi_q35_tcg_memhp(void) { -@@ -824,8 +826,10 @@ int main(int argc, char *argv[]) +@@ -875,8 +877,10 @@ int main(int argc, char *argv[]) qtest_add_func("acpi/piix4/bridge", test_acpi_piix4_tcg_bridge); qtest_add_func("acpi/q35", test_acpi_q35_tcg); qtest_add_func("acpi/q35/bridge", test_acpi_q35_tcg_bridge); @@ -1579,10 +1468,10 @@ index 564da45..ede777a 100644 qtest_add_func("acpi/q35/cpuhp", test_acpi_q35_tcg_cphp); qtest_add_func("acpi/piix4/memhp", test_acpi_piix4_tcg_memhp); diff --git a/tests/boot-order-test.c b/tests/boot-order-test.c -index fc1e794..e29c528 100644 +index e70f5de..1be0731 100644 --- a/tests/boot-order-test.c +++ b/tests/boot-order-test.c -@@ -109,6 +109,7 @@ static void test_pc_boot_order(void) +@@ -106,6 +106,7 @@ static void test_pc_boot_order(void) test_boot_orders(NULL, read_boot_order_pc, test_cases_pc); } @@ -1590,7 +1479,7 @@ index fc1e794..e29c528 100644 static uint8_t read_m48t59(uint64_t addr, uint16_t reg) { writeb(addr, reg & 0xff); -@@ -139,6 +140,7 @@ static uint64_t read_boot_order_pmac(void) +@@ -136,6 +137,7 @@ static uint64_t read_boot_order_pmac(void) return qfw_cfg_get_u16(fw_cfg, FW_CFG_BOOT_DEVICE); } @@ -1598,7 +1487,7 @@ index fc1e794..e29c528 100644 static const boot_order_test test_cases_fw_cfg[] = { { "", 'c', 'c' }, -@@ -148,6 +150,7 @@ static const boot_order_test test_cases_fw_cfg[] = { +@@ -145,6 +147,7 @@ static const boot_order_test test_cases_fw_cfg[] = { {} }; @@ -1606,7 +1495,7 @@ index fc1e794..e29c528 100644 static void test_pmac_oldworld_boot_order(void) { test_boot_orders("g3beige", read_boot_order_pmac, test_cases_fw_cfg); -@@ -156,7 +159,9 @@ static void test_pmac_oldworld_boot_order(void) +@@ -153,7 +156,9 @@ static void test_pmac_oldworld_boot_order(void) static void test_pmac_newworld_boot_order(void) { test_boot_orders("mac99", read_boot_order_pmac, test_cases_fw_cfg); @@ -1616,7 +1505,7 @@ index fc1e794..e29c528 100644 static uint64_t read_boot_order_sun4m(void) { -@@ -191,11 +196,13 @@ int main(int argc, char *argv[]) +@@ -188,11 +193,13 @@ int main(int argc, char *argv[]) if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { qtest_add_func("boot-order/pc", test_pc_boot_order); } else if (strcmp(arch, "ppc") == 0 || strcmp(arch, "ppc64") == 0) { @@ -1631,28 +1520,37 @@ index fc1e794..e29c528 100644 qtest_add_func("boot-order/sun4m", test_sun4m_boot_order); } else if (strcmp(arch, "sparc64") == 0) { diff --git a/tests/boot-serial-test.c b/tests/boot-serial-test.c -index b95c5e7..e58c518 100644 +index 011525d..dc682c1 100644 --- a/tests/boot-serial-test.c +++ b/tests/boot-serial-test.c -@@ -26,14 +26,14 @@ static testdef_t tests[] = { - { "alpha", "clipper", "", "PCI:" }, +@@ -73,7 +73,7 @@ typedef struct testdef { + } testdef_t; + + static testdef_t tests[] = { +- { "alpha", "clipper", "", "PCI:" }, ++/* { "alpha", "clipper", "", "PCI:" }, { "ppc", "ppce500", "", "U-Boot" }, - { "ppc", "prep", "", "Open Hack'Ware BIOS" }, -- { "ppc64", "ppce500", "", "U-Boot" }, -- { "ppc64", "prep", "", "Open Hack'Ware BIOS" }, -+/* { "ppc64", "ppce500", "", "U-Boot" }, -+ { "ppc64", "prep", "", "Open Hack'Ware BIOS" }, */ + { "ppc", "prep", "-m 96", "Memory size: 96 MB" }, + { "ppc", "40p", "-boot d", "Booting from device d" }, +@@ -83,14 +83,14 @@ static testdef_t tests[] = { + { "ppc64", "ppce500", "", "U-Boot" }, + { "ppc64", "prep", "-boot e", "Booting from device e" }, + { "ppc64", "40p", "-m 192", "Memory size: 192 MB" }, +- { "ppc64", "mac99", "", "PowerPC,970FX" }, ++ { "ppc64", "mac99", "", "PowerPC,970FX" },*/ { "ppc64", "pseries", "", "Open Firmware" }, -- { "ppc64", "powernv", "-cpu POWER8", "SkiBoot" }, -+/* { "ppc64", "powernv", "-cpu POWER8", "SkiBoot" }, */ +- { "ppc64", "powernv", "-cpu POWER8", "OPAL" }, +- { "ppc64", "sam460ex", "-device e1000", "8086 100e" }, ++/* { "ppc64", "powernv", "-cpu POWER8", "OPAL" }, ++ { "ppc64", "sam460ex", "-device e1000", "8086 100e" },*/ { "i386", "isapc", "-cpu qemu32 -device sga", "SGABIOS" }, { "i386", "pc", "-device sga", "SGABIOS" }, { "i386", "q35", "-device sga", "SGABIOS" }, - { "x86_64", "isapc", "-cpu qemu32 -device sga", "SGABIOS" }, + { "x86_64", "pc", "-cpu qemu32 -device sga", "SGABIOS" }, { "x86_64", "q35", "-device sga", "SGABIOS" }, - { "s390x", "s390-ccw-virtio", - "-nodefaults -device sclpconsole,chardev=serial0", "virtio device" }, + { "sparc", "LX", "", "TMS390S10" }, + { "sparc", "SS-4", "", "MB86904" }, diff --git a/tests/e1000-test.c b/tests/e1000-test.c index 0c5fcdc..0504d33 100644 --- a/tests/e1000-test.c @@ -1669,7 +1567,7 @@ index 0c5fcdc..0504d33 100644 int main(int argc, char **argv) diff --git a/tests/endianness-test.c b/tests/endianness-test.c -index ed0bf52..58af690 100644 +index 546e096..1bd87db 100644 --- a/tests/endianness-test.c +++ b/tests/endianness-test.c @@ -34,6 +34,7 @@ static const TestCase test_cases[] = { @@ -1689,10 +1587,10 @@ index ed0bf52..58af690 100644 { "sh4eb", "r2d", 0xfe240000, .bswap = true, .superio = "i82378" }, { "sparc64", "sun4u", 0x1fe02000000LL, .bswap = true }, diff --git a/tests/ivshmem-test.c b/tests/ivshmem-test.c -index 3776342..6aae100 100644 +index 8af16ee..df2eb50 100644 --- a/tests/ivshmem-test.c +++ b/tests/ivshmem-test.c -@@ -256,6 +256,7 @@ static void test_ivshmem_pair(void) +@@ -257,6 +257,7 @@ static void test_ivshmem_pair(void) g_free(data); } @@ -1700,7 +1598,7 @@ index 3776342..6aae100 100644 typedef struct ServerThread { GThread *thread; IvshmemServer *server; -@@ -413,9 +414,11 @@ static void test_ivshmem_server_irq(void) +@@ -414,9 +415,11 @@ static void test_ivshmem_server_irq(void) { test_ivshmem_server(false); } @@ -1712,7 +1610,7 @@ index 3776342..6aae100 100644 static void test_ivshmem_hotplug(void) { const char *arch = qtest_get_arch(); -@@ -433,6 +436,7 @@ static void test_ivshmem_hotplug(void) +@@ -434,6 +437,7 @@ static void test_ivshmem_hotplug(void) qtest_end(); g_free(opts); } @@ -1720,7 +1618,7 @@ index 3776342..6aae100 100644 static void test_ivshmem_memdev(void) { -@@ -500,7 +504,7 @@ static gchar *mktempshm(int size, int *fd) +@@ -501,7 +505,7 @@ static gchar *mktempshm(int size, int *fd) int main(int argc, char **argv) { int ret, fd; @@ -1729,7 +1627,7 @@ index 3776342..6aae100 100644 gchar dir[] = "/tmp/ivshmem-test.XXXXXX"; #if !GLIB_CHECK_VERSION(2, 31, 0) -@@ -527,14 +531,18 @@ int main(int argc, char **argv) +@@ -528,14 +532,18 @@ int main(int argc, char **argv) tmpserver = g_strconcat(tmpdir, "/server", NULL); qtest_add_func("/ivshmem/single", test_ivshmem_single); @@ -1749,22 +1647,10 @@ index 3776342..6aae100 100644 ret = g_test_run(); diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051 -index c8cfc76..e6275f6 100755 +index f617e25..69d34eb 100755 --- a/tests/qemu-iotests/051 +++ b/tests/qemu-iotests/051 -@@ -145,9 +145,9 @@ case "$QEMU_DEFAULT_MACHINE" in - pc) - run_qemu -drive if=floppy - run_qemu -drive if=ide,media=cdrom -- run_qemu -drive if=scsi,media=cdrom -+# run_qemu -drive if=scsi,media=cdrom - run_qemu -drive if=ide -- run_qemu -drive if=scsi -+# run_qemu -drive if=scsi - ;; - *) - ;; -@@ -158,11 +158,11 @@ run_qemu -drive if=virtio +@@ -168,11 +168,11 @@ run_qemu -drive if=virtio case "$QEMU_DEFAULT_MACHINE" in pc) run_qemu -drive if=none,id=disk -device ide-cd,drive=disk @@ -1779,19 +1665,7 @@ index c8cfc76..e6275f6 100755 ;; *) ;; -@@ -176,9 +176,9 @@ case "$QEMU_DEFAULT_MACHINE" in - pc) - run_qemu -drive file="$TEST_IMG",if=floppy,readonly=on - run_qemu -drive file="$TEST_IMG",if=ide,media=cdrom,readonly=on -- run_qemu -drive file="$TEST_IMG",if=scsi,media=cdrom,readonly=on -+# run_qemu -drive file="$TEST_IMG",if=scsi,media=cdrom,readonly=on - run_qemu -drive file="$TEST_IMG",if=ide,readonly=on -- run_qemu -drive file="$TEST_IMG",if=scsi,readonly=on -+# run_qemu -drive file="$TEST_IMG",if=scsi,readonly=on - ;; - *) - ;; -@@ -189,11 +189,11 @@ run_qemu -drive file="$TEST_IMG",if=virtio,readonly=on +@@ -197,11 +197,11 @@ run_qemu -drive file="$TEST_IMG",if=virtio,readonly=on case "$QEMU_DEFAULT_MACHINE" in pc) run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device ide-cd,drive=disk @@ -1807,7 +1681,7 @@ index c8cfc76..e6275f6 100755 *) ;; diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group -index 4bd5017..0c2bda3 100644 +index 52a80f3..99777ec 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -77,7 +77,7 @@ @@ -1829,25 +1703,38 @@ index 4bd5017..0c2bda3 100644 101 rw auto quick 102 rw auto quick diff --git a/tests/qom-test.c b/tests/qom-test.c -index ab0595d..44347d2 100644 +index a34ff6b..db0d3ab 100644 --- a/tests/qom-test.c +++ b/tests/qom-test.c -@@ -15,7 +15,9 @@ - #include "qapi/qmp/types.h" +@@ -16,7 +16,9 @@ + #include "libqtest.h" static const char *blacklist_x86[] = { - "xenfv", "xenpv", NULL -+ "xenfv", "xenpv", ++ "xenfv", "xenpv", "isapc", + "rhel6.6.0", "rhel6.5.0", "rhel6.4.0", "rhel6.3.0", + "rhel6.2.0", "rhel6.1.0", "rhel6.0.0", NULL }; static const struct { +diff --git a/tests/test-hmp.c b/tests/test-hmp.c +index 5352c9c..674dd64 100644 +--- a/tests/test-hmp.c ++++ b/tests/test-hmp.c +@@ -139,7 +139,7 @@ static void add_machine_test_case(const char *mname) + char *path; + + /* Ignore blacklisted machines that have known problems */ +- if (!strcmp("xenfv", mname) || !strcmp("xenpv", mname)) { ++ if (!strcmp("xenfv", mname) || !strcmp("xenpv", mname) || !strcmp("isapc", mname)) { + return; + } + diff --git a/tests/test-x86-cpuid-compat.c b/tests/test-x86-cpuid-compat.c -index 58a2dd9..47c21f7 100644 +index 02e4184..9e4a508 100644 --- a/tests/test-x86-cpuid-compat.c +++ b/tests/test-x86-cpuid-compat.c -@@ -305,6 +305,7 @@ int main(int argc, char **argv) +@@ -306,6 +306,7 @@ int main(int argc, char **argv) "-cpu 486,xlevel2=0xC0000002,+xstore", "xlevel2", 0xC0000002); @@ -1855,7 +1742,7 @@ index 58a2dd9..47c21f7 100644 /* Check compatibility of old machine-types that didn't * auto-increase level/xlevel/xlevel2: */ -@@ -355,6 +356,7 @@ int main(int argc, char **argv) +@@ -356,6 +357,7 @@ int main(int argc, char **argv) add_cpuid_test("x86/cpuid/xlevel-compat/pc-i440fx-2.4/npt-on", "-machine pc-i440fx-2.4 -cpu SandyBridge,+npt", "xlevel", 0x80000008); @@ -1864,7 +1751,7 @@ index 58a2dd9..47c21f7 100644 /* Test feature parsing */ add_feature_test("x86/cpuid/features/plus", diff --git a/tests/usb-hcd-xhci-test.c b/tests/usb-hcd-xhci-test.c -index 031764d..80666d4 100644 +index 9c14e30..192b7f7 100644 --- a/tests/usb-hcd-xhci-test.c +++ b/tests/usb-hcd-xhci-test.c @@ -21,6 +21,7 @@ static void test_xhci_hotplug(void) @@ -1874,16 +1761,16 @@ index 031764d..80666d4 100644 +#if 0 /* Disabled for Red Hat Enterprise Linux 7 */ static void test_usb_uas_hotplug(void) { - QDict *response; -@@ -77,6 +78,7 @@ static void test_usb_uas_hotplug(void) - g_assert(!strcmp(qdict_get_str(response, "event"), "DEVICE_DELETED")); - QDECREF(response); + qtest_qmp_device_add("usb-uas", "uas", NULL); +@@ -34,6 +35,7 @@ static void test_usb_uas_hotplug(void) + qtest_qmp_device_del("scsihd"); + qtest_qmp_device_del("uas"); } +#endif int main(int argc, char **argv) { -@@ -86,8 +88,9 @@ int main(int argc, char **argv) +@@ -43,8 +45,9 @@ int main(int argc, char **argv) qtest_add_func("/xhci/pci/init", test_xhci_init); qtest_add_func("/xhci/pci/hotplug", test_xhci_hotplug); @@ -1895,10 +1782,10 @@ index 031764d..80666d4 100644 " -drive id=drive0,if=none,file=null-co://,format=raw"); ret = g_test_run(); diff --git a/vl.c b/vl.c -index 8e247cc..a64b349 100644 +index fce1fd1..03950fc 100644 --- a/vl.c +++ b/vl.c -@@ -168,7 +168,7 @@ int max_cpus = 1; +@@ -165,7 +165,7 @@ unsigned int max_cpus; int smp_cores = 1; int smp_threads = 1; int acpi_enabled = 1; diff --git a/SOURCES/0005-Add-RHEL-7-machine-types.patch b/SOURCES/0005-Add-RHEL-7-machine-types.patch new file mode 100644 index 0000000..f2edcb0 --- /dev/null +++ b/SOURCES/0005-Add-RHEL-7-machine-types.patch @@ -0,0 +1,3695 @@ +From 84733200df4772cf20a4e9f7e5669b87ef5ab4c0 Mon Sep 17 00:00:00 2001 +From: Miroslav Rezanina +Date: Sun, 14 Dec 2014 18:32:18 +0100 +Subject: Add RHEL 7 machine types + +This commit adds all changes related to machine types applied in +qemu-kvm-rhev-2.1.2-16.el7. + +Signed-off-by: Miroslav Rezanina + +Conflicts (on 2.3 rebase): + default-configs/ppc64-softmmu.mak + hw/arm/Makefile.objs + hw/i386/pc_piix.c + hw/i386/pc_q35.c + hw/ppc/spapr.c + savevm.c - has to change shadow_bios tail to rcu list handling + target-i386/machine.c - use xmm instead of ymmh register + +-- + +Rebase notes (2.12.0): +- replace has_dynamic_sysbus with list of dynamic devices (upstream) +- Changed force_rev1_fadt handling +- Added default nic to machine options for pc_piix and pc_q35 +- Disabled m48t59-test for ppc64 +- Disabled unsupported machine types in boot-serial-test +- Disabled pseries-rhel7.2.0 machine type for cpu-plug-test + +Rebase notes (2.11.0): +- Return type for VMStateDescription.pre_save changed (upstream) +- Use default_cpu_type instead of tcg_default_cpu for sPAPRMachineClass +- Use virt_get_default_cpu_node_id in arm rhel machine type +- Set default_cpu_type to cortex-a57 +- Disable options for arm boards instead of object file remove +- Changed order with device disable commit - removed unnecessary changes + +Rebase notes (2.10.0): +- Commented out new unused functions in hw/arm/virt.c +- savevm_skip_section_footers changed to COMPAT variable (upstream) +- global_state_set_optional changed to COMPAT variable (upstream) +- savevm_skip_configuration changed to COMPAT variable (upstream) +- move shadow_bios() to separate module with stub version available +- set possible_cpu_arch_ids and cpu_index_to_instance_props fields for arm machine type +- Re-enable older machine types for ppc64 +- Commented 7.2 rebase error for compat qemu-extended-regs + +Rebase notes (2.9.0): +- new header file for arm (upstream) +- query_hotpluggable_cpus renamed to has_hotpluggable_cpus (upstream) +- replace MAX_CPUMASK_BITS with max_cpus +- Adding rhel6-e1000.rom moved to Initial redhat commit +- Fixed conflict on cirrus_vga.c + +Rebase notes (2.8.0): +- new "m->max_cpus = 288" in pc_q35_machine_options hw/i386/pc_q35.c + +Rebase notes (2.7.0): +- Additional fsl-imx6.o sabrelito.o files in arm hw dir + +Rebase notes (2.6.0): +- Changes in handling of some compat properties +- Fixes in x86_64 copmat models +- Added required devices for aarch64 +- Fixes for ppc machine types + +Rebase notes (2.5.0): +- changed cpu defaults structure +- chnaged cpu compat properties handling +- added fix for arm machine type + +Rebase notes (2.4.0) +- Moved needed attribute (due to 5cd8cadae8db905afcbf877cae568c27d1d55a8a) +- Fixes to machine types changes + +Merged patches (2.12.0): +- 402de2c redhat: Define the pseries-rhel7.5-sxxm machine type +- a232ba5 redhat: Define the pseries-rhel7.4-sxxm machine type +- 54f90c2 redhat: Define the pseries-rhel7.3-sxxm machine type +- 3fe3c44 Disable GeForce quirks in vfio-pci for RHEL machines +- 4780659 target-i386: cpu: add new CPU models for indirect branch predictor restrictions +- d486f00 hw/ppc/spapr_caps: Rework spapr_caps to use uint8 internal representation +- cc06449 spapr: Handle Decimal Floating Point (DFP) as an optional capability +- 64ef8ed spapr: Handle VMX/VSX presence as an spapr capability flag +- acad5a1 spapr: Treat Hardware Transactional Memory (HTM) as an optional capability + +Merged patches (2.11.0): +- 58702e8dbb redhat: fix HW_COMPAT_RHEL7_3 +- ea157600da redhat: define HW_COMPAT_RHEL7_4 +- 86ef5cd189 redhat: define pseries-rhel7.5.0 machine type +- d8bf28e9ec qemu-kvm-ma: define only pseries-rhel7.5.0 machine type for -ma +- 9b07271835 Create x86 7.5.0 machine types +- e63d707db9 acpi: Force rev1 FADT on old q35 machine types +- c091cd7a1b pc: make pc_rom RO only on new machine types +- 082bd3ba3d arm/virt: Add RHEL 7.5 machine typei +- 8663586f2b qemu-kvm-rhev: only allows pseries-rhel7.5.0 machine type with POWER9 guest +- 229441f111 machine compat: pci_bridge/shpc always enable +- 917c9e7df7 pcie_root_port: Fix x-migrate-msix compat +- b0c0614041 q35: Fix mismerge +- 888e98c6d6 hw/pci-host: Fix x86 Host Bridges 64bit PCI hole (partial) +- b2f9f4fcaa i386/cpu/hyperv: support over 64 vcpus for windows guests (partial) +- cc306393d7 migcompat/e1000e: Work around 7.3 msi/intr_state field +- c4753f76a3 migcompat/rtl8139: Work around version bump +- 1ece5bfd00 RHEL: Add RHEL7 machine type for qemu on s390x + +Merged patches (2.10.0) +- 5090ba1 Fix qemu-kvm does not quit when booting guest w/ 241 vcpus and "-no-kvm" +- 3c52050 x86: bump maximum vcpu count of pc-q35-rhel7.4.0 to 288 +- 0ed92ca x86: Work around SMI breakages +- f7b5a7f spapr: update SPAPR_COMPAT_RHEL7_3 +- 04faf4d migration: update HW_COMPAT_RHEL7_3 +- 9982768 x86: bump maximum vcpu count of pc-q35-rhel7.4.0 to 384 +- f5095ba re-enable DMA for 7.3 machine type +- d6ec65d x86 machine compat: 2.9 stragglers +- eda659a disable linuxboot_dma.bin option rom for 7.3 machine types +- 8c122a5 Revert "hw/pci: disable pci-bridge's shpc by default" (partial) +- 627adfa virtio_net: Bypass backends for MTU feature negotiation (partial) +- b430787 pc: Use "min[x]level" on compat_props on RHEL machine-types +- 8c3f45a AArch64: remove mach-virt-7.3 machine type +- d5df1ef Downstream: Update pseries machine types for RHEL-ALT-7.4 + +Merged patches (2.9.0) +- 8475d69 hw/arm/virt: Disable virtio-net-pci option ROM file loading +- 73fe1f6 Workaround rhel6 ctrl_guest_offloads machine type mismatch +- 21d32ca pc_piix: fix compat props typo for RHEL6 machine types +- 55a5002 compat: define HW_COMPAT_RHEL7_3 +- 1b8e927 spapr: define pseries-rhel7.4.0 machine type +- cdb76ec hw/arm/virt: remove aarch64 rhel machine type +- 7dfa88b hw/arm/virt: create virt-rhel7.3.0 machine type +- 6894f91 hw/arm/virt: create virt-rhel7.4.0 machine type +- a9d2d39 x86: Split out options for the head rhel7 machine types +- fdafbdc x86: Create PC_RHEL7_3_COMPAT definition +- 3427c72 x86: Define pc-i440fx-rhel7.4.0 +- aea20ab x86: Define pc-q35-rhel7.4.0 +- 0185c0f x86: Remove downstream opteron rdtscp override +- 6b51073 fix abort in acpi_setup() since 2.8 with rhel6 machine types +- 954fc0d intel-hda: fix rhel6 compat property +- 1b57274 kvmclock: reduce kvmclock difference on migration (rhel only part) + +Merged patches (2.8.0) +- a1da2f0 virtio-pci: reduce modern_mem_bar size (rhel only part) + +Merged patches (2.7.0): +- fe9d1cf pc: Use right HW_COMPAT_* macros at PC_RHEL7* compat macros +- 3938189 compat: Add missing "any_layout" in HW_COMPAT_RHEL7_1 +- 6dffc9d spapr: update RHEL-7.2 machine type +- c5d5910 migration: fix HW_COMPAT_RHEL7_2 +- 2da9bb8 pc: New (default) pc-i440fx-rhel7.3.0 machine-type +- 0520d7e 7.3 mismerge fix: Fix ich9-intel-hda compatibility +- 89528b3 PC migration compat: Section footers/global state +- 2231e35 fw_cfg for 7.2 compatibility +- b8a3ade pc: Create new pc-q35-rhel7.3.0 machine-type +- 340929b q35: Remove 7.0, 7.1, 7.2 machine types +- bb7fc95 machine types: fix pc_machine_*_options chain +- d9fa9aa Fix rhel6 rom file +- dc39363 fix vga type for older machines +- 255a2d1 7.2 machine type compatibility +- 16c3d25 target-i386: Remove SSE4a from qemu64 CPU model (rhel only part) +- 76a1796 target-i386: Remove ABM from qemu64 CPU model (rhel only part) +- a9f8773 pc: Recover PC_RHEL7_1_COMPAT from RHEL-7.2 code +- 7a6ed67 pc: Include missing PC_COMPAT_2_3 entries in PC_RHEL7_2_COMPAT +- 07428f6 Revert "static checker: e1000-82540em got aliased to e1000" +- 446cf1f Revert "e1000: use alias for default model" +- 615096e 7.x compat: e1000-82540em +- 0855905 hw/arm/virt: kill 7.2 machine type +- 18bbea2 usbredir: turn off streams for rhel7.2 & older +- 910cf4a target-i386: Fill high bits of mtrr mask (rhel only part) +- 0e8ab1b target-i386: Enable host-phys-bits on RHEL +- 8c5f8a5 pc: Fix rhel6.3.0 compat_props setting +- 8f869f1 pc: use new CPU hotplug interface since 2.7 machine type (rhel only part) +- d9d646f machine: add properties to compat_props incrementaly (rhel only part) +- acb18fd apic: Use apic_id as apic's migration instance_id (rhel only part) +- c7e37d4 apic: fix broken migration for kvm-apic (rhel only part) +- eca64aee hw/virtio-pci: fix virtio behaviour +- c56b8F6e pc-rhel-7.2: pcie: fix link active status bit migration +- 5522aa3 q35-rhel: allow dynamic sysbus + +Merged patches (2.6.0): +- f915d7f arm: virt: Add an abstract RHEL ARM virt machine type +- deffcc0 arm: virt: Add RHEL 7.3.0 virt machine type +- 04ca07d arm: virt: Consolidate the naming of RHEL virt machine types +- 2856ce2 Define HW_COMPAT_RHEL7_2 +- 1869242 spapr: move pseries-2.5 machine to RHEL disabled machine zone +- cc59ce7 spapr: add RHEL-7.3 machine type +- 98549c5 pc: Fix property names on CPU compat code +- caa47bb Fix ich9-intel-hda compatibility + +Merged patches (2.3.0): +- bb4e53c2 pc: add rhel6.6.0 machine type +- 129a2b3 Downstream-only: Restore "pseries" machine alias + +Merged patches (2.4.0): +- 8e8107c numa: Don't allow memdev= on RHEL-6 machine-types +- 8b220c0 pc_sysfw: prevent pflash and/or mis-sized firmware for rhel6.x.0 machtypes +- 9dba3a5 Add pc-i440fx-rhel7.2.0 machine type +- 1c88ffa Add pc-q35-rhel7.2.0 machine type +- 6f74d0c Downstream-only: Add rhel7.2.0 machine type +- a7d6105 Add flag for pre-2.2 migration compatibility +- 17f9a18 Serial: Migration compatibility pre 2.2/7.2 +- 3799a57 Migration compat for mc146818rtc/irq_reinject_on_ack_count subsection +- 5668cc1 Fix reported machine type +- 2417534 386: drop FDC in pc-q35-rhel7.2.0 if neither it nor fl. drives are anted +- f42eee5 global_state: Make section optional +- 8640f84 migration: Add configuration section +- 48c857b pc: memhotplug: fix incorrectly set reserved-memory-end +- f33f0b6 pc: memhotplug: keep reserved-memory-end broken on rhel71 and earlier machines + +(cherry picked from commit 44f7e7595c416686a00015e317e74183037a8136) + +Conflicts: + redhat/qemu-kvm.spec.template + +Conflicts: + hw/arm/Makefile.objs + hw/i386/acpi-build.c + hw/ppc/spapr.c + hw/timer/mc146818rtc.c + migration/migration.h + target/i386/machine.c + +Conflicts: + tests/boot-serial-test.c + +(cherry picked from commit f3d24bf7acf06b294404ec0c9849df6211b7b4a7) +--- + hw/acpi/ich9.c | 16 + + hw/acpi/piix4.c | 6 +- + hw/arm/virt.c | 121 +++++- + hw/char/serial.c | 28 ++ + hw/display/cirrus_vga.c | 4 +- + hw/display/vga-isa.c | 2 +- + hw/i386/Makefile.objs | 1 + + hw/i386/acpi-build.c | 3 + + hw/i386/pc.c | 7 +- + hw/i386/pc_piix.c | 894 +++++++++++++++++++++++++++++++++++++- + hw/i386/pc_q35.c | 74 +++- + hw/i386/pc_sysfw.c | 16 + + hw/i386/shadow-bios.c | 64 +++ + hw/net/e1000.c | 20 +- + hw/net/e1000e.c | 21 + + hw/net/ne2000.c | 2 +- + hw/net/pcnet-pci.c | 2 +- + hw/net/rtl8139.c | 6 +- + hw/ppc/spapr.c | 213 +++++++++ + hw/ppc/spapr_cpu_core.c | 13 + + hw/s390x/s390-virtio-ccw.c | 17 +- + hw/smbios/smbios.c | 1 + + hw/timer/i8254_common.c | 2 +- + hw/timer/mc146818rtc.c | 6 + + hw/usb/hcd-uhci.c | 15 +- + hw/usb/hcd-xhci.c | 20 + + hw/usb/hcd-xhci.h | 2 + + hw/virtio/virtio-pci.c | 2 +- + hw/virtio/virtio.c | 22 +- + include/hw/acpi/ich9.h | 3 + + include/hw/arm/virt.h | 22 + + include/hw/compat.h | 195 +++++++++ + include/hw/i386/pc.h | 554 +++++++++++++++++++++++ + include/hw/ppc/spapr.h | 1 + + include/hw/usb.h | 7 + + include/hw/virtio/virtio.h | 1 + + include/sysemu/sysemu.h | 2 + + migration/migration.c | 2 + + migration/migration.h | 5 + + migration/savevm.c | 9 + + numa.c | 13 + + qdev-monitor.c | 1 - + redhat/qemu-kvm.spec.template | 15 +- + scripts/vmstate-static-checker.py | 1 - + stubs/Makefile.objs | 1 + + stubs/shadow-bios.c | 7 + + target/i386/cpu.c | 9 +- + target/i386/machine.c | 21 + + target/ppc/compat.c | 11 + + target/ppc/cpu.h | 1 + + tests/Makefile.include | 8 +- + tests/cpu-plug-test.c | 3 +- + 52 files changed, 2450 insertions(+), 42 deletions(-) + create mode 100644 hw/i386/shadow-bios.c + create mode 100644 stubs/shadow-bios.c + +diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c +index a4e87b8..23a7baa 100644 +--- a/hw/acpi/ich9.c ++++ b/hw/acpi/ich9.c +@@ -441,6 +441,18 @@ static void ich9_pm_set_enable_tco(Object *obj, bool value, Error **errp) + s->pm.enable_tco = value; + } + ++static bool ich9_pm_get_force_rev1_fadt(Object *obj, Error **errp) ++{ ++ ICH9LPCState *s = ICH9_LPC_DEVICE(obj); ++ return s->pm.force_rev1_fadt; ++} ++ ++static void ich9_pm_set_force_rev1_fadt(Object *obj, bool value, Error **errp) ++{ ++ ICH9LPCState *s = ICH9_LPC_DEVICE(obj); ++ s->pm.force_rev1_fadt = value; ++} ++ + void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp) + { + static const uint32_t gpe0_len = ICH9_PMIO_GPE0_LEN; +@@ -465,6 +477,10 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp) + ich9_pm_get_cpu_hotplug_legacy, + ich9_pm_set_cpu_hotplug_legacy, + NULL); ++ object_property_add_bool(obj, "__com.redhat_force-rev1-fadt", ++ ich9_pm_get_force_rev1_fadt, ++ ich9_pm_set_force_rev1_fadt, ++ NULL); + object_property_add(obj, ACPI_PM_PROP_S3_DISABLED, "uint8", + ich9_pm_get_disable_s3, + ich9_pm_set_disable_s3, +diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c +index 8b70345..d706360 100644 +--- a/hw/acpi/piix4.c ++++ b/hw/acpi/piix4.c +@@ -311,7 +311,7 @@ static const VMStateDescription vmstate_cpuhp_state = { + static const VMStateDescription vmstate_acpi = { + .name = "piix4_pm", + .version_id = 3, +- .minimum_version_id = 3, ++ .minimum_version_id = 2, + .minimum_version_id_old = 1, + .load_state_old = acpi_load_old, + .post_load = vmstate_acpi_post_load, +@@ -671,8 +671,8 @@ static void piix4_send_gpe(AcpiDeviceIf *adev, AcpiEventStatusBits ev) + + static Property piix4_pm_properties[] = { + DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0), +- DEFINE_PROP_UINT8(ACPI_PM_PROP_S3_DISABLED, PIIX4PMState, disable_s3, 0), +- DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_DISABLED, PIIX4PMState, disable_s4, 0), ++ DEFINE_PROP_UINT8(ACPI_PM_PROP_S3_DISABLED, PIIX4PMState, disable_s3, 1), ++ DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_DISABLED, PIIX4PMState, disable_s4, 1), + DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_VAL, PIIX4PMState, s4_val, 2), + DEFINE_PROP_BOOL("acpi-pci-hotplug-with-bridge-support", PIIX4PMState, + use_acpi_pci_hotplug, true), +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 94dcb12..806eb1e 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -59,6 +59,7 @@ + #include "qapi/visitor.h" + #include "standard-headers/linux/input.h" + ++#if 0 /* disabled Red Hat Enterprise Linux */ + #define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \ + static void virt_##major##_##minor##_class_init(ObjectClass *oc, \ + void *data) \ +@@ -86,7 +87,36 @@ + DEFINE_VIRT_MACHINE_LATEST(major, minor, true) + #define DEFINE_VIRT_MACHINE(major, minor) \ + DEFINE_VIRT_MACHINE_LATEST(major, minor, false) +- ++#endif /* disabled for RHEL */ ++ ++#define DEFINE_RHEL_MACHINE_LATEST(m, n, s, latest) \ ++ static void rhel##m##n##s##_virt_class_init(ObjectClass *oc, \ ++ void *data) \ ++ { \ ++ MachineClass *mc = MACHINE_CLASS(oc); \ ++ rhel##m##n##s##_virt_options(mc); \ ++ mc->desc = "RHEL " # m "." # n "." # s " ARM Virtual Machine"; \ ++ if (latest) { \ ++ mc->alias = "virt"; \ ++ mc->is_default = 1; \ ++ } \ ++ } \ ++ static const TypeInfo rhel##m##n##s##_machvirt_info = { \ ++ .name = MACHINE_TYPE_NAME("virt-rhel" # m "." # n "." # s), \ ++ .parent = TYPE_RHEL_MACHINE, \ ++ .instance_init = rhel##m##n##s##_virt_instance_init, \ ++ .class_init = rhel##m##n##s##_virt_class_init, \ ++ }; \ ++ static void rhel##m##n##s##_machvirt_init(void) \ ++ { \ ++ type_register_static(&rhel##m##n##s##_machvirt_info); \ ++ } \ ++ type_init(rhel##m##n##s##_machvirt_init); ++ ++#define DEFINE_RHEL_MACHINE_AS_LATEST(major, minor, subminor) \ ++ DEFINE_RHEL_MACHINE_LATEST(major, minor, subminor, true) ++#define DEFINE_RHEL_MACHINE(major, minor, subminor) \ ++ DEFINE_RHEL_MACHINE_LATEST(major, minor, subminor, false) + + /* Number of external interrupt lines to configure the GIC with */ + #define NUM_IRQS 256 +@@ -1416,6 +1446,7 @@ static void machvirt_init(MachineState *machine) + create_platform_bus(vms, pic); + } + ++#if 0 /* disabled for RHEL */ + static bool virt_get_secure(Object *obj, Error **errp) + { + VirtMachineState *vms = VIRT_MACHINE(obj); +@@ -1444,6 +1475,7 @@ static void virt_set_virt(Object *obj, bool value, Error **errp) + vms->virt = value; + } + ++#endif /* disabled for RHEL */ + static bool virt_get_highmem(Object *obj, Error **errp) + { + VirtMachineState *vms = VIRT_MACHINE(obj); +@@ -1536,6 +1568,7 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) + return ms->possible_cpus; + } + ++#if 0 /* disabled for RHEL */ + static void virt_machine_class_init(ObjectClass *oc, void *data) + { + MachineClass *mc = MACHINE_CLASS(oc); +@@ -1748,3 +1781,89 @@ static void virt_machine_2_6_options(MachineClass *mc) + vmc->no_pmu = true; + } + DEFINE_VIRT_MACHINE(2, 6) ++#endif /* disabled for RHEL */ ++ ++static void rhel_machine_class_init(ObjectClass *oc, void *data) ++{ ++ MachineClass *mc = MACHINE_CLASS(oc); ++ ++ mc->family = "virt-rhel-Z"; ++ mc->init = machvirt_init; ++ /* Start max_cpus at the maximum QEMU supports. We'll further restrict ++ * it later in machvirt_init, where we have more information about the ++ * configuration of the particular instance. ++ */ ++ mc->max_cpus = 255; ++ mc->block_default_type = IF_VIRTIO; ++ mc->no_cdrom = 1; ++ mc->pci_allow_0_address = true; ++ /* We know we will never create a pre-ARMv7 CPU which needs 1K pages */ ++ mc->minimum_page_bits = 12; ++ mc->possible_cpu_arch_ids = virt_possible_cpu_arch_ids; ++ mc->cpu_index_to_instance_props = virt_cpu_index_to_props; ++ mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a57"); ++ mc->get_default_cpu_node_id = virt_get_default_cpu_node_id; ++} ++ ++static const TypeInfo rhel_machine_info = { ++ .name = TYPE_RHEL_MACHINE, ++ .parent = TYPE_MACHINE, ++ .abstract = true, ++ .instance_size = sizeof(VirtMachineState), ++ .class_size = sizeof(VirtMachineClass), ++ .class_init = rhel_machine_class_init, ++}; ++ ++static void rhel_machine_init(void) ++{ ++ type_register_static(&rhel_machine_info); ++} ++type_init(rhel_machine_init); ++ ++static void rhel750_virt_instance_init(Object *obj) ++{ ++ VirtMachineState *vms = VIRT_MACHINE(obj); ++ VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); ++ ++ /* EL3 is disabled by default and non-configurable for RHEL */ ++ vms->secure = false; ++ /* EL2 is disabled by default and non-configurable for RHEL */ ++ vms->virt = false; ++ /* High memory is enabled by default for RHEL */ ++ vms->highmem = true; ++ object_property_add_bool(obj, "highmem", virt_get_highmem, ++ virt_set_highmem, NULL); ++ object_property_set_description(obj, "highmem", ++ "Set on/off to enable/disable using " ++ "physical address space above 32 bits", ++ NULL); ++ /* Default GIC type is still v2, but became configurable for RHEL */ ++ vms->gic_version = 2; ++ object_property_add_str(obj, "gic-version", virt_get_gic_version, ++ virt_set_gic_version, NULL); ++ object_property_set_description(obj, "gic-version", ++ "Set GIC version. " ++ "Valid values are 2, 3 and host", NULL); ++ ++ if (vmc->no_its) { ++ vms->its = false; ++ } else { ++ /* Default allows ITS instantiation */ ++ vms->its = true; ++ object_property_add_bool(obj, "its", virt_get_its, ++ virt_set_its, NULL); ++ object_property_set_description(obj, "its", ++ "Set on/off to enable/disable " ++ "ITS instantiation", ++ NULL); ++ } ++ ++ vms->memmap=a15memmap; ++ vms->irqmap=a15irqmap; ++} ++ ++static void rhel750_virt_options(MachineClass *mc) ++{ ++ SET_MACHINE_COMPAT(mc, ARM_RHEL_COMPAT); ++} ++DEFINE_RHEL_MACHINE_AS_LATEST(7, 5, 0) +diff --git a/hw/char/serial.c b/hw/char/serial.c +index eb72191..7647fac 100644 +--- a/hw/char/serial.c ++++ b/hw/char/serial.c +@@ -30,6 +30,7 @@ + #include "qemu/timer.h" + #include "exec/address-spaces.h" + #include "qemu/error-report.h" ++#include "migration/migration.h" + + //#define DEBUG_SERIAL + +@@ -691,6 +692,9 @@ static int serial_post_load(void *opaque, int version_id) + static bool serial_thr_ipending_needed(void *opaque) + { + SerialState *s = opaque; ++ if (migrate_pre_2_2) { ++ return false; ++ } + + if (s->ier & UART_IER_THRI) { + bool expected_value = ((s->iir & UART_IIR_ID) == UART_IIR_THRI); +@@ -718,6 +722,10 @@ static const VMStateDescription vmstate_serial_thr_ipending = { + static bool serial_tsr_needed(void *opaque) + { + SerialState *s = (SerialState *)opaque; ++ if (migrate_pre_2_2) { ++ return false; ++ } ++ + return s->tsr_retry != 0; + } + +@@ -737,6 +745,10 @@ static const VMStateDescription vmstate_serial_tsr = { + static bool serial_recv_fifo_needed(void *opaque) + { + SerialState *s = (SerialState *)opaque; ++ if (migrate_pre_2_2) { ++ return false; ++ } ++ + return !fifo8_is_empty(&s->recv_fifo); + + } +@@ -755,6 +767,10 @@ static const VMStateDescription vmstate_serial_recv_fifo = { + static bool serial_xmit_fifo_needed(void *opaque) + { + SerialState *s = (SerialState *)opaque; ++ if (migrate_pre_2_2) { ++ return false; ++ } ++ + return !fifo8_is_empty(&s->xmit_fifo); + } + +@@ -772,6 +788,10 @@ static const VMStateDescription vmstate_serial_xmit_fifo = { + static bool serial_fifo_timeout_timer_needed(void *opaque) + { + SerialState *s = (SerialState *)opaque; ++ if (migrate_pre_2_2) { ++ return false; ++ } ++ + return timer_pending(s->fifo_timeout_timer); + } + +@@ -789,6 +809,10 @@ static const VMStateDescription vmstate_serial_fifo_timeout_timer = { + static bool serial_timeout_ipending_needed(void *opaque) + { + SerialState *s = (SerialState *)opaque; ++ if (migrate_pre_2_2) { ++ return false; ++ } ++ + return s->timeout_ipending != 0; + } + +@@ -806,6 +830,10 @@ static const VMStateDescription vmstate_serial_timeout_ipending = { + static bool serial_poll_needed(void *opaque) + { + SerialState *s = (SerialState *)opaque; ++ if (migrate_pre_2_2) { ++ return false; ++ } ++ + return s->poll_msl >= 0; + } + +diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c +index d116651..feacb45 100644 +--- a/hw/display/cirrus_vga.c ++++ b/hw/display/cirrus_vga.c +@@ -3060,7 +3060,7 @@ static void isa_cirrus_vga_realizefn(DeviceState *dev, Error **errp) + + static Property isa_cirrus_vga_properties[] = { + DEFINE_PROP_UINT32("vgamem_mb", struct ISACirrusVGAState, +- cirrus_vga.vga.vram_size_mb, 4), ++ cirrus_vga.vga.vram_size_mb, 16), + DEFINE_PROP_BOOL("blitter", struct ISACirrusVGAState, + cirrus_vga.enable_blitter, true), + DEFINE_PROP_END_OF_LIST(), +@@ -3133,7 +3133,7 @@ static void pci_cirrus_vga_realize(PCIDevice *dev, Error **errp) + + static Property pci_vga_cirrus_properties[] = { + DEFINE_PROP_UINT32("vgamem_mb", struct PCICirrusVGAState, +- cirrus_vga.vga.vram_size_mb, 4), ++ cirrus_vga.vga.vram_size_mb, 16), + DEFINE_PROP_BOOL("blitter", struct PCICirrusVGAState, + cirrus_vga.enable_blitter, true), + DEFINE_PROP_END_OF_LIST(), +diff --git a/hw/display/vga-isa.c b/hw/display/vga-isa.c +index 469834a..eb44d21 100644 +--- a/hw/display/vga-isa.c ++++ b/hw/display/vga-isa.c +@@ -79,7 +79,7 @@ static void vga_isa_realizefn(DeviceState *dev, Error **errp) + } + + static Property vga_isa_properties[] = { +- DEFINE_PROP_UINT32("vgamem_mb", ISAVGAState, state.vram_size_mb, 8), ++ DEFINE_PROP_UINT32("vgamem_mb", ISAVGAState, state.vram_size_mb, 16), + DEFINE_PROP_END_OF_LIST(), + }; + +diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs +index fa87a14..8c25538 100644 +--- a/hw/i386/Makefile.objs ++++ b/hw/i386/Makefile.objs +@@ -10,3 +10,4 @@ obj-$(CONFIG_VMMOUSE) += vmmouse.o + + obj-y += kvmvapic.o + obj-y += acpi-build.o ++obj-y += shadow-bios.o +diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c +index 3cf2a16..976d151 100644 +--- a/hw/i386/acpi-build.c ++++ b/hw/i386/acpi-build.c +@@ -183,6 +183,9 @@ static void acpi_get_pm_info(AcpiPmInfo *pm) + pm->fadt.reset_reg = r; + pm->fadt.reset_val = 0xf; + pm->fadt.flags |= 1 << ACPI_FADT_F_RESET_REG_SUP; ++ if (object_property_get_bool(lpc, ++ "__com.redhat_force-rev1-fadt", NULL)) ++ pm->fadt.rev = 1; + pm->cpu_hp_io_base = ICH9_CPU_HOTPLUG_IO_BASE; + } + assert(obj); +diff --git a/hw/i386/pc.c b/hw/i386/pc.c +index ab4323d..d38a328 100644 +--- a/hw/i386/pc.c ++++ b/hw/i386/pc.c +@@ -1417,7 +1417,8 @@ void pc_memory_init(PCMachineState *pcms, + option_rom_mr = g_malloc(sizeof(*option_rom_mr)); + memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE, + &error_fatal); +- if (pcmc->pci_enabled) { ++ /* RH difference: See bz 1489800, explicitly make ROM ro */ ++ if (pcmc->pc_rom_ro) { + memory_region_set_readonly(option_rom_mr, true); + } + memory_region_add_subregion_overlap(rom_memory, +@@ -2360,6 +2361,7 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) + pcmc->acpi_data_size = 0x20000 + 0x8000; + pcmc->save_tsc_khz = true; + pcmc->linuxboot_dma_enabled = true; ++ pcmc->pc_rom_ro = true; + mc->get_hotplug_handler = pc_get_hotpug_handler; + mc->cpu_index_to_instance_props = pc_cpu_index_to_props; + mc->get_default_cpu_node_id = pc_get_default_cpu_node_id; +@@ -2369,7 +2371,8 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) + mc->default_boot_order = "cad"; + mc->hot_add_cpu = pc_hot_add_cpu; + mc->block_default_type = IF_IDE; +- mc->max_cpus = 255; ++ /* 240: max CPU count for RHEL */ ++ mc->max_cpus = 240; + mc->reset = pc_machine_reset; + hc->pre_plug = pc_machine_device_pre_plug_cb; + hc->plug = pc_machine_device_plug_cb; +diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c +index 729a050..6794bb7 100644 +--- a/hw/i386/pc_piix.c ++++ b/hw/i386/pc_piix.c +@@ -48,6 +48,7 @@ + #include "cpu.h" + #include "qapi/error.h" + #include "qemu/error-report.h" ++#include "migration/migration.h" + #ifdef CONFIG_XEN + #include + #include "hw/xen/xen_pt.h" +@@ -168,8 +169,8 @@ static void pc_init1(MachineState *machine, + if (pcmc->smbios_defaults) { + MachineClass *mc = MACHINE_GET_CLASS(machine); + /* These values are guest ABI, do not change */ +- smbios_set_defaults("QEMU", "Standard PC (i440FX + PIIX, 1996)", +- mc->name, pcmc->smbios_legacy_mode, ++ smbios_set_defaults("Red Hat", "KVM", ++ mc->desc, pcmc->smbios_legacy_mode, + pcmc->smbios_uuid_encoded, + SMBIOS_ENTRY_POINT_21); + } +@@ -307,6 +308,7 @@ static void pc_init1(MachineState *machine, + * HW_COMPAT_*, PC_COMPAT_*, or * pc_*_machine_options(). + */ + ++#if 0 /* Disabled for Red Hat Enterprise Linux */ + static void pc_compat_2_3(MachineState *machine) + { + PCMachineState *pcms = PC_MACHINE(machine); +@@ -1135,3 +1137,891 @@ static void xenfv_machine_options(MachineClass *m) + DEFINE_PC_MACHINE(xenfv, "xenfv", pc_xen_hvm_init, + xenfv_machine_options); + #endif ++machine_init(pc_machine_init); ++ ++#endif /* Disabled for Red Hat Enterprise Linux */ ++ ++/* Red Hat Enterprise Linux machine types */ ++ ++/* Options for the latest rhel7 machine type */ ++static void pc_machine_rhel7_options(MachineClass *m) ++{ ++ PCMachineClass *pcmc = PC_MACHINE_CLASS(m); ++ m->family = "pc_piix_Y"; ++ m->default_machine_opts = "firmware=bios-256k.bin"; ++ pcmc->default_nic_model = "e1000"; ++ m->default_display = "std"; ++ SET_MACHINE_COMPAT(m, PC_RHEL_COMPAT); ++ m->alias = "pc"; ++ m->is_default = 1; ++} ++ ++static void pc_init_rhel750(MachineState *machine) ++{ ++ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \ ++ TYPE_I440FX_PCI_DEVICE); ++} ++ ++static void pc_machine_rhel750_options(MachineClass *m) ++{ ++ pc_machine_rhel7_options(m); ++ m->desc = "RHEL 7.5.0 PC (i440FX + PIIX, 1996)"; ++} ++ ++DEFINE_PC_MACHINE(rhel750, "pc-i440fx-rhel7.5.0", pc_init_rhel750, ++ pc_machine_rhel750_options); ++ ++static void pc_init_rhel740(MachineState *machine) ++{ ++ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \ ++ TYPE_I440FX_PCI_DEVICE); ++} ++ ++static void pc_machine_rhel740_options(MachineClass *m) ++{ ++ PCMachineClass *pcmc = PC_MACHINE_CLASS(m); ++ pc_machine_rhel750_options(m); ++ m->alias = NULL; ++ m->is_default = 0; ++ m->desc = "RHEL 7.4.0 PC (i440FX + PIIX, 1996)"; ++ m->numa_auto_assign_ram = numa_legacy_auto_assign_ram; ++ pcmc->pc_rom_ro = false; ++ SET_MACHINE_COMPAT(m, PC_RHEL7_4_COMPAT); ++} ++ ++DEFINE_PC_MACHINE(rhel740, "pc-i440fx-rhel7.4.0", pc_init_rhel740, ++ pc_machine_rhel740_options); ++ ++static void pc_init_rhel730(MachineState *machine) ++{ ++ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \ ++ TYPE_I440FX_PCI_DEVICE); ++} ++ ++static void pc_machine_rhel730_options(MachineClass *m) ++{ ++ PCMachineClass *pcmc = PC_MACHINE_CLASS(m); ++ pc_machine_rhel740_options(m); ++ m->alias = NULL; ++ m->is_default = 0; ++ m->desc = "RHEL 7.3.0 PC (i440FX + PIIX, 1996)"; ++ pcmc->linuxboot_dma_enabled = false; ++ SET_MACHINE_COMPAT(m, PC_RHEL7_3_COMPAT); ++} ++ ++DEFINE_PC_MACHINE(rhel730, "pc-i440fx-rhel7.3.0", pc_init_rhel730, ++ pc_machine_rhel730_options); ++ ++ ++static void pc_init_rhel720(MachineState *machine) ++{ ++ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \ ++ TYPE_I440FX_PCI_DEVICE); ++} ++ ++static void pc_machine_rhel720_options(MachineClass *m) ++{ ++ PCMachineClass *pcmc = PC_MACHINE_CLASS(m); ++ pc_machine_rhel730_options(m); ++ m->desc = "RHEL 7.2.0 PC (i440FX + PIIX, 1996)"; ++ /* From pc_i440fx_2_5_machine_options */ ++ pcmc->save_tsc_khz = false; ++ m->legacy_fw_cfg_order = 1; ++ /* Note: broken_reserved_end was already in 7.2 */ ++ /* From pc_i440fx_2_6_machine_options */ ++ pcmc->legacy_cpu_hotplug = true; ++ SET_MACHINE_COMPAT(m, PC_RHEL7_2_COMPAT); ++} ++ ++DEFINE_PC_MACHINE(rhel720, "pc-i440fx-rhel7.2.0", pc_init_rhel720, ++ pc_machine_rhel720_options); ++ ++static void pc_compat_rhel710(MachineState *machine) ++{ ++ PCMachineState *pcms = PC_MACHINE(machine); ++ PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); ++ ++ /* From pc_compat_2_2 */ ++ pcmc->rsdp_in_ram = false; ++ machine->suppress_vmdesc = true; ++ ++ /* From pc_compat_2_1 */ ++ pcmc->smbios_uuid_encoded = false; ++ x86_cpu_change_kvm_default("svm", NULL); ++ pcmc->enforce_aligned_dimm = false; ++ ++ /* Disable all the extra subsections that were added in 2.2 */ ++ migrate_pre_2_2 = true; ++ ++ /* From pc_i440fx_2_4_machine_options */ ++ pcmc->broken_reserved_end = true; ++} ++ ++static void pc_init_rhel710(MachineState *machine) ++{ ++ pc_compat_rhel710(machine); ++ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \ ++ TYPE_I440FX_PCI_DEVICE); ++} ++ ++static void pc_machine_rhel710_options(MachineClass *m) ++{ ++ pc_machine_rhel720_options(m); ++ m->family = "pc_piix_Y"; ++ m->desc = "RHEL 7.1.0 PC (i440FX + PIIX, 1996)"; ++ m->default_display = "cirrus"; ++ SET_MACHINE_COMPAT(m, PC_RHEL7_1_COMPAT); ++} ++ ++DEFINE_PC_MACHINE(rhel710, "pc-i440fx-rhel7.1.0", pc_init_rhel710, ++ pc_machine_rhel710_options); ++ ++static void pc_compat_rhel700(MachineState *machine) ++{ ++ PCMachineState *pcms = PC_MACHINE(machine); ++ PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); ++ ++ pc_compat_rhel710(machine); ++ ++ /* Upstream enables it for everyone, we're a little more selective */ ++ x86_cpu_change_kvm_default("x2apic", NULL); ++ x86_cpu_change_kvm_default("svm", NULL); ++ pcmc->legacy_acpi_table_size = 6418; /* see pc_compat_2_0() */ ++ pcmc->smbios_legacy_mode = true; ++ pcmc->has_reserved_memory = false; ++ migrate_cve_2014_5263_xhci_fields = true; ++} ++ ++static void pc_init_rhel700(MachineState *machine) ++{ ++ pc_compat_rhel700(machine); ++ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \ ++ TYPE_I440FX_PCI_DEVICE); ++} ++ ++static void pc_machine_rhel700_options(MachineClass *m) ++{ ++ pc_machine_rhel710_options(m); ++ m->family = "pc_piix_Y"; ++ m->desc = "RHEL 7.0.0 PC (i440FX + PIIX, 1996)"; ++ SET_MACHINE_COMPAT(m, PC_RHEL7_0_COMPAT); ++} ++ ++DEFINE_PC_MACHINE(rhel700, "pc-i440fx-rhel7.0.0", pc_init_rhel700, ++ pc_machine_rhel700_options); ++ ++#define PC_RHEL6_6_COMPAT \ ++ {\ ++ .driver = "scsi-hd",\ ++ .property = "discard_granularity",\ ++ .value = stringify(0),\ ++ },{\ ++ .driver = "scsi-cd",\ ++ .property = "discard_granularity",\ ++ .value = stringify(0),\ ++ },{\ ++ .driver = "scsi-disk",\ ++ .property = "discard_granularity",\ ++ .value = stringify(0),\ ++ },{\ ++ .driver = "ide-hd",\ ++ .property = "discard_granularity",\ ++ .value = stringify(0),\ ++ },{\ ++ .driver = "ide-cd",\ ++ .property = "discard_granularity",\ ++ .value = stringify(0),\ ++ },{\ ++ .driver = "ide-drive",\ ++ .property = "discard_granularity",\ ++ .value = stringify(0),\ ++ },{\ ++ .driver = "virtio-blk-pci",\ ++ .property = "discard_granularity",\ ++ .value = stringify(0),\ ++ },{\ ++ .driver = "virtio-serial-pci",\ ++ .property = "vectors",\ ++ /* DEV_NVECTORS_UNSPECIFIED as a uint32_t string */\ ++ .value = stringify(0xFFFFFFFF),\ ++ },{\ ++ .driver = "486-" TYPE_X86_CPU,\ ++ .property = "model",\ ++ .value = stringify(0),\ ++ },{\ ++ .driver = "usb-tablet",\ ++ .property = "usb_version",\ ++ .value = stringify(1),\ ++ },{\ ++ .driver = "virtio-net-pci",\ ++ .property = "mq",\ ++ .value = "off",\ ++ },{\ ++ .driver = "VGA",\ ++ .property = "mmio",\ ++ .value = "off",\ ++ },{\ ++ .driver = "virtio-blk-pci",\ ++ .property = "config-wce",\ ++ .value = "off",\ ++ },{\ ++ .driver = TYPE_ISA_FDC,\ ++ .property = "check_media_rate",\ ++ .value = "off",\ ++ },{\ ++ .driver = "virtio-balloon-pci",\ ++ .property = "class",\ ++ .value = stringify(PCI_CLASS_MEMORY_RAM),\ ++ },{\ ++ .driver = TYPE_PCI_DEVICE,\ ++ .property = "command_serr_enable",\ ++ .value = "off",\ ++ },{\ ++ .driver = "AC97",\ ++ .property = "use_broken_id",\ ++ .value = stringify(1),\ ++ },{\ ++ .driver = "intel-hda",\ ++ .property = "msi",\ ++ .value = "off",\ ++ },{\ ++ .driver = "qemu32-" TYPE_X86_CPU,\ ++ .property = "min-xlevel",\ ++ .value = stringify(0),\ ++ },{\ ++ .driver = "486-" TYPE_X86_CPU,\ ++ .property = "min-level",\ ++ .value = stringify(0),\ ++ },{\ ++ .driver = "qemu32-" TYPE_X86_CPU,\ ++ .property = "model",\ ++ .value = stringify(3),\ ++ },{\ ++ .driver = "usb-ccid",\ ++ .property = "serial",\ ++ .value = "1",\ ++ },{\ ++ .driver = "ne2k_pci",\ ++ .property = "romfile",\ ++ .value = "rhel6-ne2k_pci.rom",\ ++ },{\ ++ .driver = "pcnet",\ ++ .property = "romfile",\ ++ .value = "rhel6-pcnet.rom",\ ++ },{\ ++ .driver = "rtl8139",\ ++ .property = "romfile",\ ++ .value = "rhel6-rtl8139.rom",\ ++ },{\ ++ .driver = "e1000",\ ++ .property = "romfile",\ ++ .value = "rhel6-e1000.rom",\ ++ },{\ ++ .driver = "virtio-net-pci",\ ++ .property = "romfile",\ ++ .value = "rhel6-virtio.rom",\ ++ },{\ ++ .driver = "virtio-net-pci",\ ++ .property = "any_layout",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = "pentium" "-" TYPE_X86_CPU,\ ++ .property = "apic",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = "pentium2" "-" TYPE_X86_CPU,\ ++ .property = "apic",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = "pentium3" "-" TYPE_X86_CPU,\ ++ .property = "apic",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = "Conroe" "-" TYPE_X86_CPU,\ ++ .property = "x2apic",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "Penryn" "-" TYPE_X86_CPU,\ ++ .property = "x2apic",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "Nehalem" "-" TYPE_X86_CPU,\ ++ .property = "x2apic",\ ++ .value = "on",\ ++ },\ ++ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ ++ .driver = "Nehalem-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "x2apic",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "Westmere" "-" TYPE_X86_CPU,\ ++ .property = "x2apic",\ ++ .value = "on",\ ++ },\ ++ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ ++ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "x2apic",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "Westmere" "-" TYPE_X86_CPU,\ ++ .property = "pclmulqdq",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ ++ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "pclmulqdq",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = "Westmere" "-" TYPE_X86_CPU,\ ++ .property = "fxsr",\ ++ .value = "on",\ ++ },\ ++ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ ++ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "fxsr",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "Westmere" "-" TYPE_X86_CPU,\ ++ .property = "mmx",\ ++ .value = "on",\ ++ },\ ++ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ ++ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "mmx",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "Westmere" "-" TYPE_X86_CPU,\ ++ .property = "pat",\ ++ .value = "on",\ ++ },\ ++ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ ++ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "pat",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "Westmere" "-" TYPE_X86_CPU,\ ++ .property = "cmov",\ ++ .value = "on",\ ++ },\ ++ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ ++ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "cmov",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "Westmere" "-" TYPE_X86_CPU,\ ++ .property = "pge",\ ++ .value = "on",\ ++ },\ ++ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ ++ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "pge",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "Westmere" "-" TYPE_X86_CPU,\ ++ .property = "apic",\ ++ .value = "on",\ ++ },\ ++ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ ++ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "apic",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "Westmere" "-" TYPE_X86_CPU,\ ++ .property = "cx8",\ ++ .value = "on",\ ++ },\ ++ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ ++ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "cx8",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "Westmere" "-" TYPE_X86_CPU,\ ++ .property = "mce",\ ++ .value = "on",\ ++ },\ ++ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ ++ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "mce",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "Westmere" "-" TYPE_X86_CPU,\ ++ .property = "pae",\ ++ .value = "on",\ ++ },\ ++ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ ++ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "pae",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "Westmere" "-" TYPE_X86_CPU,\ ++ .property = "msr",\ ++ .value = "on",\ ++ },\ ++ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ ++ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "msr",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "Westmere" "-" TYPE_X86_CPU,\ ++ .property = "tsc",\ ++ .value = "on",\ ++ },\ ++ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ ++ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "tsc",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "Westmere" "-" TYPE_X86_CPU,\ ++ .property = "pse",\ ++ .value = "on",\ ++ },\ ++ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ ++ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "pse",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "Westmere" "-" TYPE_X86_CPU,\ ++ .property = "de",\ ++ .value = "on",\ ++ },\ ++ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ ++ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "de",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "Westmere" "-" TYPE_X86_CPU,\ ++ .property = "fpu",\ ++ .value = "on",\ ++ },\ ++ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ ++ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "fpu",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "Broadwell" "-" TYPE_X86_CPU,\ ++ .property = "rdtscp",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ ++ .driver = "Broadwell-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "rdtscp",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = "Broadwell" "-" TYPE_X86_CPU,\ ++ .property = "smap",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ ++ .driver = "Broadwell-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "smap",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = TYPE_X86_CPU,\ ++ .property = "rdtscp",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = "Opteron_G1" "-" TYPE_X86_CPU,\ ++ .property = "x2apic",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "Opteron_G2" "-" TYPE_X86_CPU,\ ++ .property = "x2apic",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "Opteron_G3" "-" TYPE_X86_CPU,\ ++ .property = "x2apic",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "Opteron_G4" "-" TYPE_X86_CPU,\ ++ .property = "x2apic",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = "Opteron_G5" "-" TYPE_X86_CPU,\ ++ .property = "x2apic",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = TYPE_X86_CPU,\ ++ .property = "3dnow",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = TYPE_X86_CPU,\ ++ .property = "3dnowext",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = "virtio-net-pci",\ ++ .property = "__com.redhat_rhel6_ctrl_guest_workaround", \ ++ .value = "on",\ ++ }, ++ ++static void pc_compat_rhel660(MachineState *machine) ++{ ++ PCMachineState *pcms = PC_MACHINE(machine); ++ PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); ++ ++ pc_compat_rhel700(machine); ++ if (!machine->cpu_type) { ++ machine->cpu_type = "cpu64-rhel6"; ++ } ++ ++ x86_cpu_change_kvm_default("kvm-pv-unhalt", NULL); ++ ++ pcmc->gigabyte_align = false; ++ shadow_bios_after_incoming = true; ++ ich9_uhci123_irqpin_override = true; ++} ++ ++static void pc_init_rhel660(MachineState *machine) ++{ ++ pc_compat_rhel660(machine); ++ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \ ++ TYPE_I440FX_PCI_DEVICE);} ++ ++static void pc_machine_rhel660_options(MachineClass *m) ++{ ++ PCMachineClass *pcmc = PC_MACHINE_CLASS(m); ++ pc_machine_rhel700_options(m); ++ m->family = "pc_piix_Z"; ++ m->desc = "RHEL 6.6.0 PC"; ++ m->rom_file_has_mr = false; ++ m->default_machine_opts = "firmware=bios.bin"; ++ pcmc->has_acpi_build = false; ++ SET_MACHINE_COMPAT(m, PC_RHEL6_6_COMPAT); ++} ++ ++DEFINE_PC_MACHINE(rhel660, "rhel6.6.0", pc_init_rhel660, ++ pc_machine_rhel660_options); ++ ++#define PC_RHEL6_5_COMPAT \ ++ {\ ++ .driver = TYPE_USB_DEVICE,\ ++ .property = "msos-desc",\ ++ .value = "no",\ ++ }, ++ ++static void pc_compat_rhel650(MachineState *machine) ++{ ++ pc_compat_rhel660(machine); ++} ++ ++static void pc_init_rhel650(MachineState *machine) ++{ ++ pc_compat_rhel650(machine); ++ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \ ++ TYPE_I440FX_PCI_DEVICE);} ++ ++static void pc_machine_rhel650_options(MachineClass *m) ++{ ++ pc_machine_rhel660_options(m); ++ m->family = "pc_piix_Z"; ++ m->desc = "RHEL 6.5.0 PC"; ++ SET_MACHINE_COMPAT(m, PC_RHEL6_5_COMPAT); ++} ++ ++DEFINE_PC_MACHINE(rhel650, "rhel6.5.0", pc_init_rhel650, ++ pc_machine_rhel650_options); ++ ++#define PC_RHEL6_4_COMPAT \ ++ {\ ++ .driver = "virtio-scsi-pci",\ ++ .property = "vectors",\ ++ .value = stringify(2),\ ++ },{\ ++ .driver = "hda-micro",\ ++ .property = "mixer",\ ++ .value = "off",\ ++ },{\ ++ .driver = "hda-duplex",\ ++ .property = "mixer",\ ++ .value = "off",\ ++ },{\ ++ .driver = "hda-output",\ ++ .property = "mixer",\ ++ .value = "off",\ ++ },{\ ++ .driver = "virtio-net-pci",\ ++ .property = "ctrl_mac_addr",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = TYPE_X86_CPU,\ ++ .property = "sep",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = "virtio-net-pci",\ ++ .property = "__com.redhat_rhel6_ctrl_guest_workaround", \ ++ .value = "off",\ ++ }, ++ ++static void pc_compat_rhel640(MachineState *machine) ++{ ++ pc_compat_rhel650(machine); ++} ++ ++static void pc_init_rhel640(MachineState *machine) ++{ ++ pc_compat_rhel640(machine); ++ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \ ++ TYPE_I440FX_PCI_DEVICE);} ++ ++static void pc_machine_rhel640_options(MachineClass *m) ++{ ++ pc_machine_rhel650_options(m); ++ m->family = "pc_piix_Z"; ++ m->desc = "RHEL 6.4.0 PC"; ++ SET_MACHINE_COMPAT(m, PC_RHEL6_4_COMPAT); ++} ++ ++DEFINE_PC_MACHINE(rhel640, "rhel6.4.0", pc_init_rhel640, ++ pc_machine_rhel640_options); ++ ++#define PC_RHEL6_3_COMPAT \ ++ {\ ++ .driver = "Conroe-" TYPE_X86_CPU,\ ++ .property = "min-level",\ ++ .value = stringify(2),\ ++ },{\ ++ .driver = "Penryn-" TYPE_X86_CPU,\ ++ .property = "min-level",\ ++ .value = stringify(2),\ ++ },{\ ++ .driver = "Nehalem-" TYPE_X86_CPU,\ ++ .property = "min-level",\ ++ .value = stringify(2),\ ++ },{\ ++ .driver = "e1000",\ ++ .property = "autonegotiation",\ ++ .value = "off",\ ++ },{\ ++ .driver = "qxl",\ ++ .property = "revision",\ ++ .value = stringify(3),\ ++ },{\ ++ .driver = "qxl-vga",\ ++ .property = "revision",\ ++ .value = stringify(3),\ ++ },{\ ++ .driver = "virtio-scsi-pci",\ ++ .property = "hotplug",\ ++ .value = "off",\ ++ },{\ ++ .driver = "virtio-scsi-pci",\ ++ .property = "param_change",\ ++ .value = "off",\ ++ },{\ ++ .driver = TYPE_X86_CPU,\ ++ .property = "pmu",\ ++ .value = "on",\ ++ },{\ ++ .driver = "usb-hub",\ ++ .property = "serial",\ ++ .value = "314159",\ ++ },{\ ++ .driver = "usb-storage",\ ++ .property = "serial",\ ++ .value = "1",\ ++ },\ ++ {\ ++ .driver = "SandyBridge" "-" TYPE_X86_CPU,\ ++ .property = "tsc-deadline",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL6_3_COMPAT (copied from the entry above) */ \ ++ .driver = "SandyBridge-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "tsc-deadline",\ ++ .value = "off",\ ++ }, ++ ++static void pc_compat_rhel630(MachineState *machine) ++{ ++ pc_compat_rhel640(machine); ++ x86_cpu_change_kvm_default("kvm-pv-eoi",NULL); ++ enable_compat_apic_id_mode(); ++} ++ ++static void pc_init_rhel630(MachineState *machine) ++{ ++ pc_compat_rhel630(machine); ++ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \ ++ TYPE_I440FX_PCI_DEVICE);} ++ ++static void pc_machine_rhel630_options(MachineClass *m) ++{ ++ pc_machine_rhel640_options(m); ++ m->family = "pc_piix_Z"; ++ m->desc = "RHEL 6.3.0 PC"; ++ SET_MACHINE_COMPAT(m, PC_RHEL6_3_COMPAT); ++} ++ ++DEFINE_PC_MACHINE(rhel630, "rhel6.3.0", pc_init_rhel630, ++ pc_machine_rhel630_options); ++ ++ ++#define PC_RHEL6_2_COMPAT \ ++ {\ ++ .driver = TYPE_X86_CPU,\ ++ .property = "pmu",\ ++ .value = "off",\ ++ }, ++ ++static void pc_compat_rhel620(MachineState *machine) ++{ ++ pc_compat_rhel630(machine); ++} ++ ++static void pc_init_rhel620(MachineState *machine) ++{ ++ pc_compat_rhel620(machine); ++ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \ ++ TYPE_I440FX_PCI_DEVICE);} ++ ++static void pc_machine_rhel620_options(MachineClass *m) ++{ ++ pc_machine_rhel630_options(m); ++ m->family = "pc_piix_Z"; ++ m->desc = "RHEL 6.2.0 PC"; ++ SET_MACHINE_COMPAT(m, PC_RHEL6_2_COMPAT); ++} ++ ++DEFINE_PC_MACHINE(rhel620, "rhel6.2.0", pc_init_rhel620, ++ pc_machine_rhel620_options); ++ ++/* ++ * NOTE: We don't have the event_idx compat entry for the ++ * virtio-balloon-pci driver because RHEL6 doesn't disable ++ * it either due to a bug (see RHBZ 1029539 fo more info) ++ */ ++#define PC_RHEL6_1_COMPAT \ ++ {\ ++ .driver = "PIIX4_PM",\ ++ .property = "disable_s3",\ ++ .value = "0",\ ++ },{\ ++ .driver = "PIIX4_PM",\ ++ .property = "disable_s4",\ ++ .value = "0",\ ++ },{\ ++ .driver = "qxl",\ ++ .property = "revision",\ ++ .value = stringify(2),\ ++ },{\ ++ .driver = "qxl-vga",\ ++ .property = "revision",\ ++ .value = stringify(2),\ ++ },{\ ++ .driver = "virtio-blk-pci",\ ++ .property = "event_idx",\ ++ .value = "off",\ ++ },{\ ++ .driver = "virtio-serial-pci",\ ++ .property = "event_idx",\ ++ .value = "off",\ ++ },{\ ++ .driver = "virtio-net-pci",\ ++ .property = "event_idx",\ ++ .value = "off",\ ++ },{\ ++ .driver = "usb-kbd",\ ++ .property = "serial",\ ++ .value = "1",\ ++ },{\ ++ .driver = "usb-mouse",\ ++ .property = "serial",\ ++ .value = "1",\ ++ },{\ ++ .driver = "usb-tablet",\ ++ .property = "serial",\ ++ .value = "1",\ ++ }, ++ ++static void pc_compat_rhel610(MachineState *machine) ++{ ++ pc_compat_rhel620(machine); ++} ++ ++static void pc_init_rhel610(MachineState *machine) ++{ ++ pc_compat_rhel610(machine); ++ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \ ++ TYPE_I440FX_PCI_DEVICE);} ++ ++static void pc_machine_rhel610_options(MachineClass *m) ++{ ++ pc_machine_rhel620_options(m); ++ m->family = "pc_piix_Z"; ++ m->desc = "RHEL 6.1.0 PC"; ++ SET_MACHINE_COMPAT(m, PC_RHEL6_1_COMPAT); ++} ++ ++DEFINE_PC_MACHINE(rhel610, "rhel6.1.0", pc_init_rhel610, ++ pc_machine_rhel610_options); ++ ++#define PC_RHEL6_0_COMPAT \ ++ {\ ++ .driver = "qxl",\ ++ .property = "revision",\ ++ .value = stringify(1),\ ++ },{\ ++ .driver = "qxl-vga",\ ++ .property = "revision",\ ++ .value = stringify(1),\ ++ },{\ ++ .driver = "VGA",\ ++ .property = "rombar",\ ++ .value = stringify(0),\ ++ }, ++ ++static void pc_compat_rhel600(MachineState *machine) ++{ ++ pc_compat_rhel610(machine); ++} ++ ++static void pc_init_rhel600(MachineState *machine) ++{ ++ pc_compat_rhel600(machine); ++ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \ ++ TYPE_I440FX_PCI_DEVICE);} ++ ++static void pc_machine_rhel600_options(MachineClass *m) ++{ ++ pc_machine_rhel610_options(m); ++ m->family = "pc_piix_Z"; ++ m->desc = "RHEL 6.0.0 PC"; ++ SET_MACHINE_COMPAT(m, PC_RHEL6_0_COMPAT); ++} ++ ++DEFINE_PC_MACHINE(rhel600, "rhel6.0.0", pc_init_rhel600, ++ pc_machine_rhel600_options); +diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c +index 9ae9163..ecd6255 100644 +--- a/hw/i386/pc_q35.c ++++ b/hw/i386/pc_q35.c +@@ -143,8 +143,8 @@ static void pc_q35_init(MachineState *machine) + + if (pcmc->smbios_defaults) { + /* These values are guest ABI, do not change */ +- smbios_set_defaults("QEMU", "Standard PC (Q35 + ICH9, 2009)", +- mc->name, pcmc->smbios_legacy_mode, ++ smbios_set_defaults("Red Hat", "KVM", ++ mc->desc, pcmc->smbios_legacy_mode, + pcmc->smbios_uuid_encoded, + SMBIOS_ENTRY_POINT_21); + } +@@ -292,6 +292,7 @@ static void pc_q35_init(MachineState *machine) + DEFINE_PC_MACHINE(suffix, name, pc_init_##suffix, optionfn) + + ++#if 0 /* Disabled for Red Hat Enterprise Linux */ + static void pc_q35_machine_options(MachineClass *m) + { + PCMachineClass *pcmc = PC_MACHINE_CLASS(m); +@@ -404,3 +405,72 @@ static void pc_q35_2_4_machine_options(MachineClass *m) + + DEFINE_Q35_MACHINE(v2_4, "pc-q35-2.4", NULL, + pc_q35_2_4_machine_options); ++#endif /* Disabled for Red Hat Enterprise Linux */ ++ ++/* Red Hat Enterprise Linux machine types */ ++ ++/* Options for the latest rhel7 q35 machine type */ ++static void pc_q35_machine_rhel7_options(MachineClass *m) ++{ ++ PCMachineClass *pcmc = PC_MACHINE_CLASS(m); ++ pcmc->default_nic_model = "e1000e"; ++ m->family = "pc_q35_Z"; ++ m->default_machine_opts = "firmware=bios-256k.bin"; ++ m->default_display = "std"; ++ m->no_floppy = 1; ++ machine_class_allow_dynamic_sysbus_dev(m, TYPE_SYS_BUS_DEVICE); m->alias = "q35"; ++ m->max_cpus = 384; ++ SET_MACHINE_COMPAT(m, PC_RHEL_COMPAT); ++} ++ ++static void pc_q35_init_rhel750(MachineState *machine) ++{ ++ pc_q35_init(machine); ++} ++ ++static void pc_q35_machine_rhel750_options(MachineClass *m) ++{ ++ pc_q35_machine_rhel7_options(m); ++ m->desc = "RHEL-7.5.0 PC (Q35 + ICH9, 2009)"; ++} ++ ++DEFINE_PC_MACHINE(q35_rhel750, "pc-q35-rhel7.5.0", pc_q35_init_rhel750, ++ pc_q35_machine_rhel750_options); ++ ++static void pc_q35_init_rhel740(MachineState *machine) ++{ ++ pc_q35_init(machine); ++} ++ ++static void pc_q35_machine_rhel740_options(MachineClass *m) ++{ ++ PCMachineClass *pcmc = PC_MACHINE_CLASS(m); ++ pc_q35_machine_rhel750_options(m); ++ m->alias = NULL; ++ m->desc = "RHEL-7.4.0 PC (Q35 + ICH9, 2009)"; ++ m->numa_auto_assign_ram = numa_legacy_auto_assign_ram; ++ pcmc->pc_rom_ro = false; ++ SET_MACHINE_COMPAT(m, PC_RHEL7_4_COMPAT); ++} ++ ++DEFINE_PC_MACHINE(q35_rhel740, "pc-q35-rhel7.4.0", pc_q35_init_rhel740, ++ pc_q35_machine_rhel740_options); ++ ++static void pc_q35_init_rhel730(MachineState *machine) ++{ ++ pc_q35_init(machine); ++} ++ ++static void pc_q35_machine_rhel730_options(MachineClass *m) ++{ ++ PCMachineClass *pcmc = PC_MACHINE_CLASS(m); ++ pc_q35_machine_rhel740_options(m); ++ m->alias = NULL; ++ m->desc = "RHEL-7.3.0 PC (Q35 + ICH9, 2009)"; ++ m->max_cpus = 255; ++ pcmc->linuxboot_dma_enabled = false; ++ SET_MACHINE_COMPAT(m, PC_RHEL7_3_COMPAT); ++} ++ ++DEFINE_PC_MACHINE(q35_rhel730, "pc-q35-rhel7.3.0", pc_q35_init_rhel730, ++ pc_q35_machine_rhel730_options); +diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c +index 73ac783..2a6de35 100644 +--- a/hw/i386/pc_sysfw.c ++++ b/hw/i386/pc_sysfw.c +@@ -207,6 +207,13 @@ static void old_pc_system_rom_init(MemoryRegion *rom_memory, bool isapc_ram_fw) + (bios_size % 65536) != 0) { + goto bios_error; + } ++ if (shadow_bios_after_incoming && bios_size != 128 * 1024) { ++ MachineClass *mc; ++ ++ mc = MACHINE_GET_CLASS(current_machine); ++ error_report("machine %s only supports a 128KB BIOS image", mc->name); ++ exit(1); ++ } + bios = g_malloc(sizeof(*bios)); + memory_region_init_ram(bios, NULL, "pc.bios", bios_size, &error_fatal); + if (!isapc_ram_fw) { +@@ -254,6 +261,15 @@ void pc_system_firmware_init(MemoryRegion *rom_memory, bool isapc_ram_fw) + return; + } + ++ if (shadow_bios_after_incoming) { ++ MachineClass *mc; ++ ++ mc = MACHINE_GET_CLASS(current_machine); ++ error_report("flash-based firmware is not supported by machine %s", ++ mc->name); ++ exit(1); ++ } ++ + if (kvm_enabled() && !kvm_readonly_mem_enabled()) { + /* Older KVM cannot execute from device memory. So, flash memory + * cannot be used unless the readonly memory kvm capability is present. */ +diff --git a/hw/i386/shadow-bios.c b/hw/i386/shadow-bios.c +new file mode 100644 +index 0000000..65a4cb8 +--- /dev/null ++++ b/hw/i386/shadow-bios.c +@@ -0,0 +1,64 @@ ++#include "qemu/osdep.h" ++#include "sysemu/sysemu.h" ++#include "target/i386/cpu.h" ++#include "exec/ram_addr.h" ++#include "qemu/cutils.h" ++ ++void shadow_bios(void) ++{ ++ RAMBlock *block, *ram, *oprom, *bios; ++ size_t one_meg, oprom_size, bios_size; ++ uint8_t *cd_seg_host, *ef_seg_host; ++ ++ ram = NULL; ++ oprom = NULL; ++ bios = NULL; ++ rcu_read_lock(); ++ QLIST_FOREACH_RCU(block, &ram_list.blocks, next) { ++ if (strcmp("pc.ram", block->idstr) == 0) { ++ assert(ram == NULL); ++ ram = block; ++ } else if (strcmp("pc.rom", block->idstr) == 0) { ++ assert(oprom == NULL); ++ oprom = block; ++ } else if (strcmp("pc.bios", block->idstr) == 0) { ++ assert(bios == NULL); ++ bios = block; ++ } ++ } ++ assert(ram != NULL); ++ assert(oprom != NULL); ++ assert(bios != NULL); ++ assert(memory_region_is_ram(ram->mr)); ++ assert(memory_region_is_ram(oprom->mr)); ++ assert(memory_region_is_ram(bios->mr)); ++ assert(int128_eq(ram->mr->size, int128_make64(ram->used_length))); ++ assert(int128_eq(oprom->mr->size, int128_make64(oprom->used_length))); ++ assert(int128_eq(bios->mr->size, int128_make64(bios->used_length))); ++ ++ one_meg = 1024 * 1024; ++ oprom_size = 128 * 1024; ++ bios_size = 128 * 1024; ++ assert(ram->used_length >= one_meg); ++ assert(oprom->used_length == oprom_size); ++ assert(bios->used_length == bios_size); ++ ++ ef_seg_host = memory_region_get_ram_ptr(ram->mr) + (one_meg - bios_size); ++ cd_seg_host = ef_seg_host - oprom_size; ++ ++ /* This is a crude hack, but we must distinguish a rhel6.x.0 machtype guest ++ * coming in from a RHEL-6 emulator (where shadowing has had no effect on ++ * "pc.ram") from a similar guest coming in from a RHEL-7 emulator (where ++ * shadowing has worked). In the latter case we must not trample the live ++ * SeaBIOS variables in "pc.ram". ++ */ ++ if (buffer_is_zero(ef_seg_host, bios_size)) { ++ fprintf(stderr, "copying E and F segments from pc.bios to pc.ram\n"); ++ memcpy(ef_seg_host, memory_region_get_ram_ptr(bios->mr), bios_size); ++ } ++ if (buffer_is_zero(cd_seg_host, oprom_size)) { ++ fprintf(stderr, "copying C and D segments from pc.rom to pc.ram\n"); ++ memcpy(cd_seg_host, memory_region_get_ram_ptr(oprom->mr), oprom_size); ++ } ++ rcu_read_unlock(); ++} +diff --git a/hw/net/e1000.c b/hw/net/e1000.c +index 742cd0a..479ac77 100644 +--- a/hw/net/e1000.c ++++ b/hw/net/e1000.c +@@ -1663,6 +1663,16 @@ static void pci_e1000_realize(PCIDevice *pci_dev, Error **errp) + + pci_conf = pci_dev->config; + ++ if (!(d->compat_flags & E1000_FLAG_AUTONEG)) { ++ /* ++ * We have no capabilities, so capability list bit should normally be 0. ++ * Keep it on for compat machine types to avoid breaking migration. ++ * HACK: abuse E1000_FLAG_AUTONEG, which is off exactly for ++ * the machine types that need this. ++ */ ++ pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_CAP_LIST); ++ } ++ + /* TODO: RST# value should be 0, PCI spec 6.2.4 */ + pci_conf[PCI_CACHE_LINE_SIZE] = 0x10; + +@@ -1727,7 +1737,7 @@ static void e1000_class_init(ObjectClass *klass, void *data) + + k->realize = pci_e1000_realize; + k->exit = pci_e1000_uninit; +- k->romfile = "efi-e1000.rom"; ++ k->romfile = "pxe-e1000.rom"; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = info->device_id; + k->revision = info->revision; +@@ -1763,7 +1773,7 @@ static const TypeInfo e1000_base_info = { + + static const E1000Info e1000_devices[] = { + { +- .name = "e1000", ++ .name = "e1000-82540em", + .device_id = E1000_DEV_ID_82540EM, + .revision = 0x03, + .phy_id2 = E1000_PHY_ID2_8254xx_DEFAULT, +@@ -1784,6 +1794,11 @@ static const E1000Info e1000_devices[] = { + #endif + }; + ++static const TypeInfo e1000_default_info = { ++ .name = "e1000", ++ .parent = "e1000-82540em", ++}; ++ + static void e1000_register_types(void) + { + int i; +@@ -1801,6 +1816,7 @@ static void e1000_register_types(void) + + type_register(&type_info); + } ++ type_register_static(&e1000_default_info); + } + + type_init(e1000_register_types) +diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c +index c934c22..7dd8744 100644 +--- a/hw/net/e1000e.c ++++ b/hw/net/e1000e.c +@@ -74,6 +74,11 @@ typedef struct E1000EState { + + E1000ECore core; + ++ /* 7.3 had the intr_state field that was in the original e1000e code ++ * but that was removed prior to 2.7's release ++ */ ++ bool redhat_7_3_intr_state_enable; ++ uint32_t redhat_7_3_intr_state; + } E1000EState; + + #define E1000E_MMIO_IDX 0 +@@ -89,6 +94,10 @@ typedef struct E1000EState { + #define E1000E_MSIX_TABLE (0x0000) + #define E1000E_MSIX_PBA (0x2000) + ++/* Values as in RHEL 7.3 build and original upstream */ ++#define RH_E1000E_USE_MSI BIT(0) ++#define RH_E1000E_USE_MSIX BIT(1) ++ + static uint64_t + e1000e_mmio_read(void *opaque, hwaddr addr, unsigned size) + { +@@ -300,6 +309,8 @@ e1000e_init_msix(E1000EState *s) + } else { + if (!e1000e_use_msix_vectors(s, E1000E_MSIX_VEC_NUM)) { + msix_uninit(d, &s->msix, &s->msix); ++ } else { ++ s->redhat_7_3_intr_state |= RH_E1000E_USE_MSIX; + } + } + } +@@ -471,6 +482,8 @@ static void e1000e_pci_realize(PCIDevice *pci_dev, Error **errp) + ret = msi_init(PCI_DEVICE(s), 0xD0, 1, true, false, NULL); + if (ret) { + trace_e1000e_msi_init_fail(ret); ++ } else { ++ s->redhat_7_3_intr_state |= RH_E1000E_USE_MSI; + } + + if (e1000e_add_pm_capability(pci_dev, e1000e_pmrb_offset, +@@ -594,6 +607,11 @@ static const VMStateDescription e1000e_vmstate_intr_timer = { + VMSTATE_STRUCT_ARRAY(_f, _s, _num, 0, \ + e1000e_vmstate_intr_timer, E1000IntrDelayTimer) + ++static bool rhel_7_3_check(void *opaque, int version_id) ++{ ++ return ((E1000EState *)opaque)->redhat_7_3_intr_state_enable; ++} ++ + static const VMStateDescription e1000e_vmstate = { + .name = "e1000e", + .version_id = 1, +@@ -605,6 +623,7 @@ static const VMStateDescription e1000e_vmstate = { + VMSTATE_MSIX(parent_obj, E1000EState), + + VMSTATE_UINT32(ioaddr, E1000EState), ++ VMSTATE_UINT32_TEST(redhat_7_3_intr_state, E1000EState, rhel_7_3_check), + VMSTATE_UINT32(core.rxbuf_min_shift, E1000EState), + VMSTATE_UINT8(core.rx_desc_len, E1000EState), + VMSTATE_UINT32_ARRAY(core.rxbuf_sizes, E1000EState, +@@ -653,6 +672,8 @@ static PropertyInfo e1000e_prop_disable_vnet, + + static Property e1000e_properties[] = { + DEFINE_NIC_PROPERTIES(E1000EState, conf), ++ DEFINE_PROP_BOOL("__redhat_e1000e_7_3_intr_state", E1000EState, ++ redhat_7_3_intr_state_enable, false), + DEFINE_PROP_SIGNED("disable_vnet_hdr", E1000EState, disable_vnet, false, + e1000e_prop_disable_vnet, bool), + DEFINE_PROP_SIGNED("subsys_ven", E1000EState, subsys_ven, +diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c +index 3a9fc89..c629530 100644 +--- a/hw/net/ne2000.c ++++ b/hw/net/ne2000.c +@@ -769,7 +769,7 @@ static void ne2000_class_init(ObjectClass *klass, void *data) + + k->realize = pci_ne2000_realize; + k->exit = pci_ne2000_exit; +- k->romfile = "efi-ne2k_pci.rom", ++ k->romfile = "pxe-ne2k_pci.rom", + k->vendor_id = PCI_VENDOR_ID_REALTEK; + k->device_id = PCI_DEVICE_ID_REALTEK_8029; + k->class_id = PCI_CLASS_NETWORK_ETHERNET; +diff --git a/hw/net/pcnet-pci.c b/hw/net/pcnet-pci.c +index 70dc8b3..35b6d8a 100644 +--- a/hw/net/pcnet-pci.c ++++ b/hw/net/pcnet-pci.c +@@ -347,7 +347,7 @@ static void pcnet_class_init(ObjectClass *klass, void *data) + + k->realize = pci_pcnet_realize; + k->exit = pci_pcnet_uninit; +- k->romfile = "efi-pcnet.rom", ++ k->romfile = "pxe-pcnet.rom", + k->vendor_id = PCI_VENDOR_ID_AMD; + k->device_id = PCI_DEVICE_ID_AMD_LANCE; + k->revision = 0x10; +diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c +index 46daa16..bc37326 100644 +--- a/hw/net/rtl8139.c ++++ b/hw/net/rtl8139.c +@@ -3174,7 +3174,7 @@ static int rtl8139_pre_save(void *opaque) + + static const VMStateDescription vmstate_rtl8139 = { + .name = "rtl8139", +- .version_id = 5, ++ .version_id = 4, + .minimum_version_id = 3, + .post_load = rtl8139_post_load, + .pre_save = rtl8139_pre_save, +@@ -3255,7 +3255,9 @@ static const VMStateDescription vmstate_rtl8139 = { + VMSTATE_UINT32(tally_counters.TxMCol, RTL8139State), + VMSTATE_UINT64(tally_counters.RxOkPhy, RTL8139State), + VMSTATE_UINT64(tally_counters.RxOkBrd, RTL8139State), ++#if 0 /* Disabled for Red Hat Enterprise Linux bz 1420195 */ + VMSTATE_UINT32_V(tally_counters.RxOkMul, RTL8139State, 5), ++#endif + VMSTATE_UINT16(tally_counters.TxAbt, RTL8139State), + VMSTATE_UINT16(tally_counters.TxUndrn, RTL8139State), + +@@ -3425,7 +3427,7 @@ static void rtl8139_class_init(ObjectClass *klass, void *data) + + k->realize = pci_rtl8139_realize; + k->exit = pci_rtl8139_uninit; +- k->romfile = "efi-rtl8139.rom"; ++ k->romfile = "pxe-rtl8139.rom"; + k->vendor_id = PCI_VENDOR_ID_REALTEK; + k->device_id = PCI_DEVICE_ID_REALTEK_8139; + k->revision = RTL8139_PCI_REVID; /* >=0x20 is for 8139C+ */ +diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c +index 6a92b20..3ea94de 100644 +--- a/hw/ppc/spapr.c ++++ b/hw/ppc/spapr.c +@@ -3935,6 +3935,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) + smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN; + smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN; + spapr_caps_add_properties(smc, &error_abort); ++ smc->has_power9_support = true; + } + + static const TypeInfo spapr_machine_info = { +@@ -3985,6 +3986,7 @@ static const TypeInfo spapr_machine_info = { + } \ + type_init(spapr_machine_register_##suffix) + ++#if 0 /* Disabled for Red Hat Enterprise Linux */ + /* + * pseries-2.12 + */ +@@ -4136,7 +4138,9 @@ DEFINE_SPAPR_MACHINE(2_8, "2.8", false); + .property = "pre-2.8-migration", \ + .value = "on", \ + }, ++#endif + ++#if defined(CONFIG_RHV) + static void phb_placement_2_7(sPAPRMachineState *spapr, uint32_t index, + uint64_t *buid, hwaddr *pio, + hwaddr *mmio32, hwaddr *mmio64, +@@ -4185,7 +4189,9 @@ static void phb_placement_2_7(sPAPRMachineState *spapr, uint32_t index, + * window into contiguous 32-bit and 64-bit windows + */ + } ++#endif /* CONFIG_RHV */ + ++#if 0 /* Disabled for Red Hat Enterprise Linux */ + static void spapr_machine_2_7_instance_options(MachineState *machine) + { + sPAPRMachineState *spapr = SPAPR_MACHINE(machine); +@@ -4345,6 +4351,213 @@ static void spapr_machine_2_1_class_options(MachineClass *mc) + SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_1); + } + DEFINE_SPAPR_MACHINE(2_1, "2.1", false); ++#endif ++ ++/* ++ * pseries-rhel7.5.0 ++ */ ++ ++static void spapr_machine_rhel750_instance_options(MachineState *machine) ++{ ++} ++ ++static void spapr_machine_rhel750_class_options(MachineClass *mc) ++{ ++ /* Defaults for the latest behaviour inherited from the base class */ ++} ++ ++DEFINE_SPAPR_MACHINE(rhel750, "rhel7.5.0", true); ++ ++/* ++ * pseries-rhel7.5.0-sxxm ++ * ++ * pseries-rhel7.5.0 with speculative execution exploit mitigations enabled by default ++ */ ++static void spapr_machine_rhel750sxxm_instance_options(MachineState *machine) ++{ ++ spapr_machine_rhel750_instance_options(machine); ++} ++ ++static void spapr_machine_rhel750sxxm_class_options(MachineClass *mc) ++{ ++ sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); ++ ++ spapr_machine_rhel750_class_options(mc); ++ smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND; ++ smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND; ++ smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_FIXED_CCD; ++} ++ ++DEFINE_SPAPR_MACHINE(rhel750sxxm, "rhel7.5.0-sxxm", false); ++ ++#if defined(CONFIG_RHV) ++ ++/* ++ * pseries-rhel7.4.0 ++ * like SPAPR_COMPAT_2_9 ++ */ ++ ++#define SPAPR_COMPAT_RHEL7_4 \ ++ HW_COMPAT_RHEL7_4 \ ++ { \ ++ .driver = TYPE_POWERPC_CPU, \ ++ .property = "pre-2.10-migration", \ ++ .value = "on", \ ++ }, \ ++ ++static void spapr_machine_rhel740_instance_options(MachineState *machine) ++{ ++ spapr_machine_rhel750_instance_options(machine); ++} ++ ++static void spapr_machine_rhel740_class_options(MachineClass *mc) ++{ ++ sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); ++ ++ spapr_machine_rhel750_class_options(mc); ++ SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_RHEL7_4); ++ mc->numa_auto_assign_ram = numa_legacy_auto_assign_ram; ++ smc->has_power9_support = false; ++ smc->pre_2_10_has_unused_icps = true; ++ smc->resize_hpt_default = SPAPR_RESIZE_HPT_DISABLED; ++ smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_ON; ++} ++ ++DEFINE_SPAPR_MACHINE(rhel740, "rhel7.4.0", false); ++ ++/* ++ * pseries-rhel7.4.0-sxxm ++ * ++ * pseries-rhel7.4.0 with speculative execution exploit mitigations enabled by default ++ */ ++static void spapr_machine_rhel740sxxm_instance_options(MachineState *machine) ++{ ++ spapr_machine_rhel740_instance_options(machine); ++} ++ ++static void spapr_machine_rhel740sxxm_class_options(MachineClass *mc) ++{ ++ sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); ++ ++ spapr_machine_rhel740_class_options(mc); ++ smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND; ++ smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND; ++ smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_FIXED_CCD; ++} ++ ++DEFINE_SPAPR_MACHINE(rhel740sxxm, "rhel7.4.0-sxxm", false); ++ ++/* ++ * pseries-rhel7.3.0 ++ * like SPAPR_COMPAT_2_6/_2_7/_2_8 but "ddw" has been backported to RHEL7_3 ++ */ ++#define SPAPR_COMPAT_RHEL7_3 \ ++ HW_COMPAT_RHEL7_3 \ ++ { \ ++ .driver = TYPE_SPAPR_PCI_HOST_BRIDGE, \ ++ .property = "mem_win_size", \ ++ .value = stringify(SPAPR_PCI_2_7_MMIO_WIN_SIZE),\ ++ }, \ ++ { \ ++ .driver = TYPE_SPAPR_PCI_HOST_BRIDGE, \ ++ .property = "mem64_win_size", \ ++ .value = "0", \ ++ }, \ ++ { \ ++ .driver = TYPE_POWERPC_CPU, \ ++ .property = "pre-2.8-migration", \ ++ .value = "on", \ ++ }, \ ++ { \ ++ .driver = TYPE_SPAPR_PCI_HOST_BRIDGE, \ ++ .property = "pre-2.8-migration", \ ++ .value = "on", \ ++ }, \ ++ { \ ++ .driver = TYPE_SPAPR_PCI_HOST_BRIDGE, \ ++ .property = "pcie-extended-configuration-space",\ ++ .value = "off", \ ++ }, ++ ++static void spapr_machine_rhel730_instance_options(MachineState *machine) ++{ ++ sPAPRMachineState *spapr = SPAPR_MACHINE(machine); ++ ++ spapr_machine_rhel740_instance_options(machine); ++ spapr->use_hotplug_event_source = false; ++} ++ ++static void spapr_machine_rhel730_class_options(MachineClass *mc) ++{ ++ sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); ++ ++ spapr_machine_rhel740_class_options(mc); ++ mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power7_v2.3"); ++ SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_RHEL7_3); ++ smc->phb_placement = phb_placement_2_7; ++} ++ ++DEFINE_SPAPR_MACHINE(rhel730, "rhel7.3.0", false); ++ ++/* ++ * pseries-rhel7.3.0-sxxm ++ * ++ * pseries-rhel7.3.0 with speculative execution exploit mitigations enabled by default ++ */ ++static void spapr_machine_rhel730sxxm_instance_options(MachineState *machine) ++{ ++ spapr_machine_rhel730_instance_options(machine); ++} ++ ++static void spapr_machine_rhel730sxxm_class_options(MachineClass *mc) ++{ ++ sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); ++ ++ spapr_machine_rhel730_class_options(mc); ++ smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND; ++ smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND; ++ smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_FIXED_CCD; ++} ++ ++DEFINE_SPAPR_MACHINE(rhel730sxxm, "rhel7.3.0-sxxm", false); ++ ++/* ++ * pseries-rhel7.2.0 ++ */ ++/* Should be like SPAPR_COMPAT_2_5 + 2_4 + 2_3, but "dynamic-reconfiguration" ++ * has been backported to RHEL7_2 so we don't need it here. ++ */ ++ ++#define SPAPR_COMPAT_RHEL7_2 \ ++ HW_COMPAT_RHEL7_2 \ ++ { \ ++ .driver = "spapr-vlan", \ ++ .property = "use-rx-buffer-pools", \ ++ .value = "off", \ ++ },{ \ ++ .driver = TYPE_SPAPR_PCI_HOST_BRIDGE,\ ++ .property = "ddw",\ ++ .value = stringify(off),\ ++ }, ++ ++ ++static void spapr_machine_rhel720_instance_options(MachineState *machine) ++{ ++ spapr_machine_rhel730_instance_options(machine); ++} ++ ++static void spapr_machine_rhel720_class_options(MachineClass *mc) ++{ ++ sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); ++ ++ spapr_machine_rhel730_class_options(mc); ++ smc->use_ohci_by_default = true; ++ mc->has_hotpluggable_cpus = NULL; ++ SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_RHEL7_2); ++} ++ ++DEFINE_SPAPR_MACHINE(rhel720, "rhel7.2.0", false); ++#endif /* CONFIG_RHV */ + + static void spapr_machine_register_types(void) + { +diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c +index 1eda854..c5f0c72 100644 +--- a/hw/ppc/spapr_cpu_core.c ++++ b/hw/ppc/spapr_cpu_core.c +@@ -21,6 +21,7 @@ + #include "sysemu/numa.h" + #include "sysemu/hw_accel.h" + #include "qemu/error-report.h" ++#include "cpu-models.h" + + static void spapr_cpu_reset(void *opaque) + { +@@ -62,6 +63,7 @@ static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, + Error **errp) + { + CPUPPCState *env = &cpu->env; ++ sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); + + /* Set time-base frequency to 512 MHz */ + cpu_ppc_tb_init(env, SPAPR_TIMEBASE_FREQ); +@@ -69,6 +71,17 @@ static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, + /* Enable PAPR mode in TCG or KVM */ + cpu_ppc_set_papr(cpu, PPC_VIRTUAL_HYPERVISOR(spapr)); + ++ if (!smc->has_power9_support && ++ (((spapr->max_compat_pvr && ++ ppc_compat_cmp(spapr->max_compat_pvr, ++ CPU_POWERPC_LOGICAL_3_00) >= 0)) || ++ (!spapr->max_compat_pvr && ++ ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00, 0, 0)))) { ++ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, ++ "POWER9 CPU is not supported by this machine class"); ++ return; ++ } ++ + qemu_register_reset(spapr_cpu_reset, cpu); + spapr_cpu_reset(cpu); + } +diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c +index 435f7c9..3956ac3 100644 +--- a/hw/s390x/s390-virtio-ccw.c ++++ b/hw/s390x/s390-virtio-ccw.c +@@ -647,7 +647,7 @@ bool css_migration_enabled(void) + { \ + MachineClass *mc = MACHINE_CLASS(oc); \ + ccw_machine_##suffix##_class_options(mc); \ +- mc->desc = "VirtIO-ccw based S390 machine v" verstr; \ ++ mc->desc = "VirtIO-ccw based S390 machine " verstr; \ + if (latest) { \ + mc->alias = "s390-ccw-virtio"; \ + mc->is_default = 1; \ +@@ -682,6 +682,8 @@ bool css_migration_enabled(void) + #define CCW_COMPAT_2_10 \ + HW_COMPAT_2_10 + ++#if 0 /* Disabled for Red Hat Enterprise Linux */ ++ + #define CCW_COMPAT_2_9 \ + HW_COMPAT_2_9 \ + {\ +@@ -879,6 +881,19 @@ static void ccw_machine_2_4_class_options(MachineClass *mc) + } + DEFINE_CCW_MACHINE(2_4, "2.4", false); + ++#else ++ ++static void ccw_machine_rhel750_instance_options(MachineState *machine) ++{ ++} ++ ++static void ccw_machine_rhel750_class_options(MachineClass *mc) ++{ ++} ++DEFINE_CCW_MACHINE(rhel750, "rhel7.5.0", true); ++ ++#endif ++ + static void ccw_machine_register_types(void) + { + type_register_static(&ccw_machine_info); +diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c +index 27a07e9..df8f0ae 100644 +--- a/hw/smbios/smbios.c ++++ b/hw/smbios/smbios.c +@@ -778,6 +778,7 @@ void smbios_set_defaults(const char *manufacturer, const char *product, + SMBIOS_SET_DEFAULT(type1.manufacturer, manufacturer); + SMBIOS_SET_DEFAULT(type1.product, product); + SMBIOS_SET_DEFAULT(type1.version, version); ++ SMBIOS_SET_DEFAULT(type1.family, "Red Hat Enterprise Linux"); + SMBIOS_SET_DEFAULT(type2.manufacturer, manufacturer); + SMBIOS_SET_DEFAULT(type2.product, product); + SMBIOS_SET_DEFAULT(type2.version, version); +diff --git a/hw/timer/i8254_common.c b/hw/timer/i8254_common.c +index 6190b6f..ad2ad2d 100644 +--- a/hw/timer/i8254_common.c ++++ b/hw/timer/i8254_common.c +@@ -268,7 +268,7 @@ static const VMStateDescription vmstate_pit_common = { + .pre_save = pit_dispatch_pre_save, + .post_load = pit_dispatch_post_load, + .fields = (VMStateField[]) { +- VMSTATE_UINT32_V(channels[0].irq_disabled, PITCommonState, 3), ++ VMSTATE_UINT32(channels[0].irq_disabled, PITCommonState), /* qemu-kvm's v2 had 'flags' here */ + VMSTATE_STRUCT_ARRAY(channels, PITCommonState, 3, 2, + vmstate_pit_channel, PITChannelState), + VMSTATE_INT64(channels[0].next_transition_time, +diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c +index 6f1f723..68c353f 100644 +--- a/hw/timer/mc146818rtc.c ++++ b/hw/timer/mc146818rtc.c +@@ -34,6 +34,7 @@ + #include "qapi/qapi-commands-misc.h" + #include "qapi/qapi-events-misc.h" + #include "qapi/visitor.h" ++#include "migration/migration.h" + + #ifdef TARGET_I386 + #include "hw/i386/apic.h" +@@ -839,6 +840,11 @@ static int rtc_post_load(void *opaque, int version_id) + static bool rtc_irq_reinject_on_ack_count_needed(void *opaque) + { + RTCState *s = (RTCState *)opaque; ++ ++ if (migrate_pre_2_2) { ++ return false; ++ } ++ + return s->irq_reinject_on_ack_count != 0; + } + +diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c +index 836b11f..86d6ab8 100644 +--- a/hw/usb/hcd-uhci.c ++++ b/hw/usb/hcd-uhci.c +@@ -152,6 +152,8 @@ typedef struct UHCI_QH { + uint32_t el_link; + } UHCI_QH; + ++bool ich9_uhci123_irqpin_override; ++ + static void uhci_async_cancel(UHCIAsync *async); + static void uhci_queue_fill(UHCIQueue *q, UHCI_TD *td); + static void uhci_resume(void *opaque); +@@ -1214,12 +1216,23 @@ static void usb_uhci_common_realize(PCIDevice *dev, Error **errp) + UHCIState *s = UHCI(dev); + uint8_t *pci_conf = s->dev.config; + int i; ++ int irq_pin; + + pci_conf[PCI_CLASS_PROG] = 0x00; + /* TODO: reset value should be 0. */ + pci_conf[USB_SBRN] = USB_RELEASE_1; // release number + +- pci_config_set_interrupt_pin(pci_conf, u->info.irq_pin + 1); ++ if (ich9_uhci123_irqpin_override && ++ u->info.vendor_id == PCI_VENDOR_ID_INTEL && ++ (u->info.device_id == PCI_DEVICE_ID_INTEL_82801I_UHCI1 || ++ u->info.device_id == PCI_DEVICE_ID_INTEL_82801I_UHCI2 || ++ u->info.device_id == PCI_DEVICE_ID_INTEL_82801I_UHCI3)) { ++ fprintf(stderr, "RHEL-6 compat: %s: irq_pin = 3\n", u->info.name); ++ irq_pin = 3; ++ } else { ++ irq_pin = u->info.irq_pin; ++ } ++ pci_config_set_interrupt_pin(pci_conf, irq_pin + 1); + + if (s->masterbus) { + USBPort *ports[NB_PORTS]; +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index 721beb5..883141f 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -3555,9 +3555,27 @@ static const VMStateDescription vmstate_xhci_slot = { + } + }; + ++static int xhci_event_pre_save(void *opaque) ++{ ++ XHCIEvent *s = opaque; ++ ++ s->cve_2014_5263_a = ((uint8_t *)&s->type)[0]; ++ s->cve_2014_5263_b = ((uint8_t *)&s->type)[1]; ++ ++ return 0; ++} ++ ++bool migrate_cve_2014_5263_xhci_fields; ++ ++static bool xhci_event_cve_2014_5263(void *opaque, int version_id) ++{ ++ return migrate_cve_2014_5263_xhci_fields; ++} ++ + static const VMStateDescription vmstate_xhci_event = { + .name = "xhci-event", + .version_id = 1, ++ .pre_save = xhci_event_pre_save, + .fields = (VMStateField[]) { + VMSTATE_UINT32(type, XHCIEvent), + VMSTATE_UINT32(ccode, XHCIEvent), +@@ -3566,6 +3584,8 @@ static const VMStateDescription vmstate_xhci_event = { + VMSTATE_UINT32(flags, XHCIEvent), + VMSTATE_UINT8(slotid, XHCIEvent), + VMSTATE_UINT8(epid, XHCIEvent), ++ VMSTATE_UINT8_TEST(cve_2014_5263_a, XHCIEvent, xhci_event_cve_2014_5263), ++ VMSTATE_UINT8_TEST(cve_2014_5263_b, XHCIEvent, xhci_event_cve_2014_5263), + VMSTATE_END_OF_LIST() + } + }; +diff --git a/hw/usb/hcd-xhci.h b/hw/usb/hcd-xhci.h +index fc36a4c..89d4cf7 100644 +--- a/hw/usb/hcd-xhci.h ++++ b/hw/usb/hcd-xhci.h +@@ -153,6 +153,8 @@ typedef struct XHCIEvent { + uint32_t flags; + uint8_t slotid; + uint8_t epid; ++ uint8_t cve_2014_5263_a; ++ uint8_t cve_2014_5263_b; + } XHCIEvent; + + typedef struct XHCIInterrupter { +diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c +index e3e49d6..18f7c2c 100644 +--- a/hw/virtio/virtio-pci.c ++++ b/hw/virtio/virtio-pci.c +@@ -2422,7 +2422,7 @@ static void virtio_net_pci_class_init(ObjectClass *klass, void *data) + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass); + +- k->romfile = "efi-virtio.rom"; ++ k->romfile = "pxe-virtio.rom"; + k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + k->device_id = PCI_DEVICE_ID_VIRTIO_NET; + k->revision = VIRTIO_PCI_ABI_VERSION; +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 006d3d1..4bcb4f4 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -24,6 +24,7 @@ + #include "hw/virtio/virtio-access.h" + #include "sysemu/dma.h" + ++#include "standard-headers/linux/virtio_net.h" + /* + * The alignment to use between consumer and producer parts of vring. + * x86 pagesize again. This is the default, used by transports like PCI +@@ -1991,7 +1992,24 @@ const VMStateInfo virtio_vmstate_info = { + static int virtio_set_features_nocheck(VirtIODevice *vdev, uint64_t val) + { + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); +- bool bad = (val & ~(vdev->host_features)) != 0; ++ bool bad; ++ uint64_t ctrl_guest_mask = 1ull << VIRTIO_NET_F_CTRL_GUEST_OFFLOADS; ++ ++ if (vdev->rhel6_ctrl_guest_workaround && (val & ctrl_guest_mask) && ++ !(vdev->host_features & ctrl_guest_mask)) { ++ /* ++ * This works around a mistake in the definition of the rhel6.[56].0 ++ * machinetypes, ctrl-guest-offload was not set in qemu-kvm-rhev for ++ * those machine types, but is set on the rhel6 qemu-kvm-rhev build. ++ * If an incoming rhel6 guest uses it then we need to allow it. ++ * Note: There's a small race where a guest read the flag but didn't ++ * declare it's useage yet. ++ */ ++ fprintf(stderr, "RHEL6 ctrl_guest_offload workaround\n"); ++ vdev->host_features |= ctrl_guest_mask; ++ } ++ ++ bad = (val & ~(vdev->host_features)) != 0; + + val &= vdev->host_features; + if (k->set_features) { +@@ -2566,6 +2584,8 @@ static void virtio_device_instance_finalize(Object *obj) + + static Property virtio_properties[] = { + DEFINE_VIRTIO_COMMON_FEATURES(VirtIODevice, host_features), ++ DEFINE_PROP_BOOL("__com.redhat_rhel6_ctrl_guest_workaround", VirtIODevice, ++ rhel6_ctrl_guest_workaround, false), + DEFINE_PROP_END_OF_LIST(), + }; + +diff --git a/include/hw/acpi/ich9.h b/include/hw/acpi/ich9.h +index 59aeb06..7b5cc25 100644 +--- a/include/hw/acpi/ich9.h ++++ b/include/hw/acpi/ich9.h +@@ -61,6 +61,9 @@ typedef struct ICH9LPCPMRegs { + uint8_t smm_enabled; + bool enable_tco; + TCOIORegs tco_regs; ++ ++ /* RH addition, see bz 1489800 */ ++ bool force_rev1_fadt; + } ICH9LPCPMRegs; + + #define ACPI_PM_PROP_TCO_ENABLED "enable_tco" +diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h +index ba0c1a4..2e8e78a 100644 +--- a/include/hw/arm/virt.h ++++ b/include/hw/arm/virt.h +@@ -109,6 +109,7 @@ typedef struct { + int psci_conduit; + } VirtMachineState; + ++#if 0 /* disabled for Red Hat Enterprise Linux */ + #define TYPE_VIRT_MACHINE MACHINE_TYPE_NAME("virt") + #define VIRT_MACHINE(obj) \ + OBJECT_CHECK(VirtMachineState, (obj), TYPE_VIRT_MACHINE) +@@ -117,6 +118,27 @@ typedef struct { + #define VIRT_MACHINE_CLASS(klass) \ + OBJECT_CLASS_CHECK(VirtMachineClass, klass, TYPE_VIRT_MACHINE) + ++#else ++#define TYPE_RHEL_MACHINE MACHINE_TYPE_NAME("virt-rhel") ++#define VIRT_MACHINE(obj) \ ++ OBJECT_CHECK(VirtMachineState, (obj), TYPE_RHEL_MACHINE) ++#define VIRT_MACHINE_GET_CLASS(obj) \ ++ OBJECT_GET_CLASS(VirtMachineClass, obj, TYPE_RHEL_MACHINE) ++#define VIRT_MACHINE_CLASS(klass) \ ++ OBJECT_CLASS_CHECK(VirtMachineClass, klass, TYPE_RHEL_MACHINE) ++#endif ++ ++/* This macro is for changes to properties that are RHEL specific, ++ * different to the current upstream and to be applied to the latest ++ * machine type. ++ */ ++#define ARM_RHEL_COMPAT \ ++ {\ ++ .driver = "virtio-net-pci",\ ++ .property = "romfile",\ ++ .value = "",\ ++ }, ++ + void virt_acpi_setup(VirtMachineState *vms); + + #endif /* QEMU_ARM_VIRT_H */ +diff --git a/include/hw/compat.h b/include/hw/compat.h +index 13242b8..503b5c8 100644 +--- a/include/hw/compat.h ++++ b/include/hw/compat.h +@@ -255,4 +255,199 @@ + .value = "on",\ + }, + ++/* Mostly like HW_COMPAT_2_1 but: ++ * we don't need virtio-scsi-pci since 7.0 already had that on ++ * ++ * RH: Note, qemu-extended-regs should have been enabled in the 7.1 ++ * machine type, but was accidentally turned off in 7.2 onwards. ++ * ++ */ ++#define HW_COMPAT_RHEL7_1 \ ++ { /* COMPAT_RHEL7.1 */ \ ++ .driver = "intel-hda-generic",\ ++ .property = "old_msi_addr",\ ++ .value = "on",\ ++ },{\ ++ .driver = "VGA",\ ++ .property = "qemu-extended-regs",\ ++ .value = "off",\ ++ },{\ ++ .driver = "secondary-vga",\ ++ .property = "qemu-extended-regs",\ ++ .value = "off",\ ++ },{\ ++ .driver = "usb-mouse",\ ++ .property = "usb_version",\ ++ .value = stringify(1),\ ++ },{\ ++ .driver = "usb-kbd",\ ++ .property = "usb_version",\ ++ .value = stringify(1),\ ++ },{\ ++ .driver = "virtio-pci",\ ++ .property = "virtio-pci-bus-master-bug-migration",\ ++ .value = "on",\ ++ },{\ ++ .driver = "virtio-blk-pci",\ ++ .property = "any_layout",\ ++ .value = "off",\ ++ },{\ ++ .driver = "virtio-balloon-pci",\ ++ .property = "any_layout",\ ++ .value = "off",\ ++ },{\ ++ .driver = "virtio-serial-pci",\ ++ .property = "any_layout",\ ++ .value = "off",\ ++ },{\ ++ .driver = "virtio-9p-pci",\ ++ .property = "any_layout",\ ++ .value = "off",\ ++ },{\ ++ .driver = "virtio-rng-pci",\ ++ .property = "any_layout",\ ++ .value = "off",\ ++ },{ /* HW_COMPAT_RHEL7_1 - introduced with 2.10.0 */ \ ++ .driver = "migration",\ ++ .property = "send-configuration",\ ++ .value = "off",\ ++ }, ++ ++/* Mostly like HW_COMPAT_2_4 + 2_3 but: ++ * we don't need "any_layout" as it has been backported to 7.2 ++ */ ++ ++#define HW_COMPAT_RHEL7_2 \ ++ {\ ++ .driver = "virtio-blk-device",\ ++ .property = "scsi",\ ++ .value = "true",\ ++ },{\ ++ .driver = "e1000-82540em",\ ++ .property = "extra_mac_registers",\ ++ .value = "off",\ ++ },{\ ++ .driver = "virtio-pci",\ ++ .property = "x-disable-pcie",\ ++ .value = "on",\ ++ },{\ ++ .driver = "virtio-pci",\ ++ .property = "migrate-extra",\ ++ .value = "off",\ ++ },{ /* HW_COMPAT_RHEL7_2 */ \ ++ .driver = "fw_cfg_mem",\ ++ .property = "dma_enabled",\ ++ .value = "off",\ ++ },{ /* HW_COMPAT_RHEL7_2 */ \ ++ .driver = "fw_cfg_io",\ ++ .property = "dma_enabled",\ ++ .value = "off",\ ++ },{ /* HW_COMPAT_RHEL7_2 */ \ ++ .driver = "isa-fdc",\ ++ .property = "fallback",\ ++ .value = "144",\ ++ },{ /* HW_COMPAT_RHEL7_2 */ \ ++ .driver = "virtio-pci",\ ++ .property = "disable-modern",\ ++ .value = "on",\ ++ },{ /* HW_COMPAT_RHEL7_2 */ \ ++ .driver = "virtio-pci",\ ++ .property = "disable-legacy",\ ++ .value = "off",\ ++ },{ /* HW_COMPAT_RHEL7_2 */ \ ++ .driver = TYPE_PCI_DEVICE,\ ++ .property = "x-pcie-lnksta-dllla",\ ++ .value = "off",\ ++ },{ /* HW_COMPAT_RHEL7_2 */ \ ++ .driver = "virtio-pci",\ ++ .property = "page-per-vq",\ ++ .value = "on",\ ++ },{ /* HW_COMPAT_RHEL7_2 from HW_COMPAT_2_4 added in 2.9 */ \ ++ .driver = "vmgenid",\ ++ .property = "x-write-pointer-available",\ ++ .value = "off",\ ++ },{ /* HW_COMPAT_RHEL7_2 - introduced with 2.10.0 */ \ ++ .driver = "migration",\ ++ .property = "send-section-footer",\ ++ .value = "off",\ ++ },{ /* HW_COMPAT_RHEL7_2 - introduced with 2.10.0 */ \ ++ .driver = "migration",\ ++ .property = "store-global-state",\ ++ .value = "off",\ ++ }, ++ ++/* Mostly like HW_COMPAT_2_6 + HW_COMPAT_2_7 + HW_COMPAT_2_8 except ++ * disable-modern, disable-legacy, page-per-vq have already been ++ * backported to RHEL7.3 ++ */ ++#define HW_COMPAT_RHEL7_3 \ ++ { /* HW_COMPAT_RHEL7_3 */ \ ++ .driver = "virtio-mmio",\ ++ .property = "format_transport_address",\ ++ .value = "off",\ ++ },{ /* HW_COMPAT_RHEL7_3 */ \ ++ .driver = "virtio-serial-device",\ ++ .property = "emergency-write",\ ++ .value = "off",\ ++ },{ /* HW_COMPAT_RHEL7_3 */ \ ++ .driver = "ioapic",\ ++ .property = "version",\ ++ .value = "0x11",\ ++ },{ /* HW_COMPAT_RHEL7_3 */ \ ++ .driver = "intel-iommu",\ ++ .property = "x-buggy-eim",\ ++ .value = "true",\ ++ },{ /* HW_COMPAT_RHEL7_3 */ \ ++ .driver = "virtio-pci",\ ++ .property = "x-ignore-backend-features",\ ++ .value = "on",\ ++ },{ /* HW_COMPAT_RHEL7_3 */ \ ++ .driver = "fw_cfg_mem",\ ++ .property = "x-file-slots",\ ++ .value = stringify(0x10),\ ++ },{ /* HW_COMPAT_RHEL7_3 */ \ ++ .driver = "fw_cfg_io",\ ++ .property = "x-file-slots",\ ++ .value = stringify(0x10),\ ++ },{ /* HW_COMPAT_RHEL7_3 */ \ ++ .driver = "pflash_cfi01",\ ++ .property = "old-multiple-chip-handling",\ ++ .value = "on",\ ++ },{ /* HW_COMPAT_RHEL7_3 */ \ ++ .driver = TYPE_PCI_DEVICE,\ ++ .property = "x-pcie-extcap-init",\ ++ .value = "off",\ ++ },{ /* HW_COMPAT_RHEL7_3 */ \ ++ .driver = "virtio-pci",\ ++ .property = "x-pcie-deverr-init",\ ++ .value = "off",\ ++ },{ /* HW_COMPAT_RHEL7_3 */ \ ++ .driver = "virtio-pci",\ ++ .property = "x-pcie-lnkctl-init",\ ++ .value = "off",\ ++ },{ /* HW_COMPAT_RHEL7_3 */ \ ++ .driver = "virtio-pci",\ ++ .property = "x-pcie-pm-init",\ ++ .value = "off",\ ++ },{ /* HW_COMPAT_RHEL7_3 */ \ ++ .driver = "virtio-net-device",\ ++ .property = "x-mtu-bypass-backend",\ ++ .value = "off",\ ++ },{ /* HW_COMPAT_RHEL7_3 */ \ ++ .driver = "e1000e",\ ++ .property = "__redhat_e1000e_7_3_intr_state",\ ++ .value = "on",\ ++ }, ++ ++/* Mostly like HW_COMPAT_2_9 except ++ * x-mtu-bypass-backend, x-migrate-msix has already been ++ * backported to RHEL7.4. shpc was already on in 7.4. ++ */ ++#define HW_COMPAT_RHEL7_4 \ ++ { /* HW_COMPAT_RHEL7_4 */ \ ++ .driver = "intel-iommu",\ ++ .property = "pt",\ ++ .value = "off",\ ++ }, ++ + #endif /* HW_COMPAT_H */ +diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h +index ffee841..faddeba 100644 +--- a/include/hw/i386/pc.h ++++ b/include/hw/i386/pc.h +@@ -142,6 +142,9 @@ struct PCMachineClass { + + /* use DMA capable linuxboot option rom */ + bool linuxboot_dma_enabled; ++ ++ /* RH only, see bz 1489800 */ ++ bool pc_rom_ro; + }; + + #define TYPE_PC_MACHINE "generic-pc-machine" +@@ -947,4 +950,555 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *); + type_init(pc_machine_init_##suffix) + + extern void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id); ++ ++/* See include/hw/compat.h for shared compatibility lists */ ++ ++/* This macro is for changes to properties that are RHEL specific, ++ * different to the current upstream and to be applied to the latest ++ * machine type. ++ */ ++#define PC_RHEL_COMPAT \ ++ { /* PC_RHEL_COMPAT */ \ ++ .driver = TYPE_X86_CPU,\ ++ .property = "host-phys-bits",\ ++ .value = "on",\ ++ },\ ++ { /* PC_RHEL_COMPAT bz 1508330 */ \ ++ .driver = "vfio-pci",\ ++ .property = "x-no-geforce-quirks",\ ++ .value = "on",\ ++ }, ++ ++#define PC_RHEL7_4_COMPAT \ ++ HW_COMPAT_RHEL7_4 \ ++ { /* PC_RHEL7_4_COMPAT from PC_COMPAT_2_9 */ \ ++ .driver = "mch",\ ++ .property = "extended-tseg-mbytes",\ ++ .value = stringify(0),\ ++ },\ ++ { /* PC_RHEL7_4_COMPAT bz 1489800 */ \ ++ .driver = "ICH9-LPC",\ ++ .property = "__com.redhat_force-rev1-fadt",\ ++ .value = "on",\ ++ },\ ++ { /* PC_RHEL7_4_COMPAT from PC_COMPAT_2_10 */ \ ++ .driver = "i440FX-pcihost",\ ++ .property = "x-pci-hole64-fix",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_4_COMPAT from PC_COMPAT_2_10 */ \ ++ .driver = "q35-pcihost",\ ++ .property = "x-pci-hole64-fix",\ ++ .value = "off",\ ++ }, ++ ++ ++#define PC_RHEL7_3_COMPAT \ ++ HW_COMPAT_RHEL7_3 \ ++ { /* PC_RHEL7_3_COMPAT from PC_COMPAT_2_8 */ \ ++ .driver = "kvmclock",\ ++ .property = "x-mach-use-reliable-get-clock",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_3_COMPAT from PC_COMPAT_2_7 */ \ ++ .driver = TYPE_X86_CPU,\ ++ .property = "l3-cache",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_3_COMPAT from PC_COMPAT_2_7 */ \ ++ .driver = TYPE_X86_CPU,\ ++ .property = "full-cpuid-auto-level",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_3_COMPAT from PC_COMPAT_2_7 */ \ ++ .driver = "Opteron_G3" "-" TYPE_X86_CPU,\ ++ .property = "family",\ ++ .value = "15",\ ++ },\ ++ { /* PC_RHEL7_3_COMPAT from PC_COMPAT_2_7 */ \ ++ .driver = "Opteron_G3" "-" TYPE_X86_CPU,\ ++ .property = "model",\ ++ .value = "6",\ ++ },\ ++ { /* PC_RHEL7_3_COMPAT from PC_COMPAT_2_7 */ \ ++ .driver = "Opteron_G3" "-" TYPE_X86_CPU,\ ++ .property = "stepping",\ ++ .value = "1",\ ++ },\ ++ { /* PC_RHEL7_3_COMPAT from PC_COMPAT_2_7 */ \ ++ .driver = "isa-pcspk",\ ++ .property = "migrate",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_3_COMPAT from PC_COMPAT_2_6 */ \ ++ .driver = TYPE_X86_CPU,\ ++ .property = "cpuid-0xb",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_3_COMPAT from PC_COMPAT_2_8 */ \ ++ .driver = "ICH9-LPC",\ ++ .property = "x-smi-broadcast",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_3_COMPAT from PC_COMPAT_2_8 */ \ ++ .driver = TYPE_X86_CPU,\ ++ .property = "vmware-cpuid-freq",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_3_COMPAT from PC_COMPAT_2_8 */ \ ++ .driver = "Haswell-" TYPE_X86_CPU,\ ++ .property = "stepping",\ ++ .value = "1",\ ++ },\ ++ { /* PC_RHEL7_3_COMPAT from PC_COMPAT_2_3 added in 2.9 */ \ ++ .driver = TYPE_X86_CPU,\ ++ .property = "kvm-no-smi-migration",\ ++ .value = "on",\ ++ },\ ++ { /* PC_RHEL7_4_COMPAT from PC_COMPAT_2_10 */ \ ++ .driver = TYPE_X86_CPU,\ ++ .property = "x-hv-max-vps",\ ++ .value = "0x40",\ ++ }, ++ ++#define PC_RHEL7_2_COMPAT \ ++ HW_COMPAT_RHEL7_2 \ ++ {\ ++ .driver = "phenom" "-" TYPE_X86_CPU,\ ++ .property = "rdtscp",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_2_COMPAT */ \ ++ .driver = "qemu64" "-" TYPE_X86_CPU,\ ++ .property = "sse4a",\ ++ .value = "on",\ ++ },\ ++ { /* PC_RHEL7_2_COMPAT */ \ ++ .driver = "qemu64" "-" TYPE_X86_CPU,\ ++ .property = "abm",\ ++ .value = "on",\ ++ },\ ++ { /* PC_RHEL7_2_COMPAT */ \ ++ .driver = "Haswell-" TYPE_X86_CPU,\ ++ .property = "abm",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_2_COMPAT (copied from the entry above) */ \ ++ .driver = "Haswell-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "abm",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_2_COMPAT */ \ ++ .driver = "Haswell-noTSX-" TYPE_X86_CPU,\ ++ .property = "abm",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_2_COMPAT (copied from the entry above) */ \ ++ .driver = "Haswell-noTSX-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "abm",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_2_COMPAT */ \ ++ .driver = "Broadwell-" TYPE_X86_CPU,\ ++ .property = "abm",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_2_COMPAT (copied from the entry above) */ \ ++ .driver = "Broadwell-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "abm",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_2_COMPAT */ \ ++ .driver = "Broadwell-noTSX-" TYPE_X86_CPU,\ ++ .property = "abm",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_2_COMPAT (copied from the entry above) */ \ ++ .driver = "Broadwell-noTSX-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "abm",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_2_COMPAT */ \ ++ .driver = "host" "-" TYPE_X86_CPU,\ ++ .property = "host-cache-info",\ ++ .value = "on",\ ++ },\ ++ { /* PC_RHEL7_2_COMPAT */ \ ++ .driver = TYPE_X86_CPU,\ ++ .property = "check",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_2_COMPAT */ \ ++ .driver = "qemu32" "-" TYPE_X86_CPU,\ ++ .property = "popcnt",\ ++ .value = "on",\ ++ },\ ++ { /* PC_RHEL7_2_COMPAT */ \ ++ .driver = TYPE_X86_CPU,\ ++ .property = "arat",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_2_COMPAT */ \ ++ .driver = "usb-redir",\ ++ .property = "streams",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_2_COMPAT */ \ ++ .driver = TYPE_X86_CPU,\ ++ .property = "fill-mtrr-mask",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_2_COMPAT */ \ ++ .driver = "apic-common",\ ++ .property = "legacy-instance-id",\ ++ .value = "on",\ ++ }, ++ ++ ++ ++#define PC_RHEL7_1_COMPAT \ ++ HW_COMPAT_RHEL7_1 \ ++ {\ ++ .driver = "kvm64" "-" TYPE_X86_CPU,\ ++ .property = "vme",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = "kvm32" "-" TYPE_X86_CPU,\ ++ .property = "vme",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = "Conroe" "-" TYPE_X86_CPU,\ ++ .property = "vme",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = "Penryn" "-" TYPE_X86_CPU,\ ++ .property = "vme",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = "Nehalem" "-" TYPE_X86_CPU,\ ++ .property = "vme",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_1_COMPAT (copied from the entry above) */ \ ++ .driver = "Nehalem-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "vme",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = "Westmere" "-" TYPE_X86_CPU,\ ++ .property = "vme",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_1_COMPAT (copied from the entry above) */ \ ++ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "vme",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = "SandyBridge" "-" TYPE_X86_CPU,\ ++ .property = "vme",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_1_COMPAT (copied from the entry above) */ \ ++ .driver = "SandyBridge-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "vme",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = "Haswell" "-" TYPE_X86_CPU,\ ++ .property = "vme",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_1_COMPAT (copied from the entry above) */ \ ++ .driver = "Haswell-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "vme",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = "Broadwell" "-" TYPE_X86_CPU,\ ++ .property = "vme",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_1_COMPAT (copied from the entry above) */ \ ++ .driver = "Broadwell-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "vme",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = "Opteron_G1" "-" TYPE_X86_CPU,\ ++ .property = "vme",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = "Opteron_G2" "-" TYPE_X86_CPU,\ ++ .property = "vme",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = "Opteron_G3" "-" TYPE_X86_CPU,\ ++ .property = "vme",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = "Opteron_G4" "-" TYPE_X86_CPU,\ ++ .property = "vme",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = "Opteron_G5" "-" TYPE_X86_CPU,\ ++ .property = "vme",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = "Haswell" "-" TYPE_X86_CPU,\ ++ .property = "f16c",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_1_COMPAT (copied from the entry above) */ \ ++ .driver = "Haswell-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "f16c",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = "Haswell" "-" TYPE_X86_CPU,\ ++ .property = "rdrand",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_1_COMPAT (copied from the entry above) */ \ ++ .driver = "Haswell-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "rdrand",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = "Broadwell" "-" TYPE_X86_CPU,\ ++ .property = "f16c",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_1_COMPAT (copied from the entry above) */ \ ++ .driver = "Broadwell-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "f16c",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = "Broadwell" "-" TYPE_X86_CPU,\ ++ .property = "rdrand",\ ++ .value = "off",\ ++ },\ ++ { /* PC_RHEL7_1_COMPAT (copied from the entry above) */ \ ++ .driver = "Broadwell-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "rdrand",\ ++ .value = "off",\ ++ },\ ++ {\ ++ .driver = "coreduo" "-" TYPE_X86_CPU,\ ++ .property = "vmx",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "core2duo" "-" TYPE_X86_CPU,\ ++ .property = "vmx",\ ++ .value = "on",\ ++ },\ ++ { /* PC_RHEL7_1_COMPAT */ \ ++ .driver = "qemu64" "-" TYPE_X86_CPU,\ ++ .property = "min-level",\ ++ .value = stringify(4),\ ++ },{ /* PC_RHEL7_1_COMPAT */ \ ++ .driver = "kvm64" "-" TYPE_X86_CPU,\ ++ .property = "min-level",\ ++ .value = stringify(5),\ ++ },{ /* PC_RHEL7_1_COMPAT */ \ ++ .driver = "pentium3" "-" TYPE_X86_CPU,\ ++ .property = "min-level",\ ++ .value = stringify(2),\ ++ },{ /* PC_RHEL7_1_COMPAT */ \ ++ .driver = "n270" "-" TYPE_X86_CPU,\ ++ .property = "min-level",\ ++ .value = stringify(5),\ ++ },{ /* PC_RHEL7_1_COMPAT */ \ ++ .driver = "Conroe" "-" TYPE_X86_CPU,\ ++ .property = "min-level",\ ++ .value = stringify(4),\ ++ },{ /* PC_RHEL7_1_COMPAT */ \ ++ .driver = "Penryn" "-" TYPE_X86_CPU,\ ++ .property = "min-level",\ ++ .value = stringify(4),\ ++ },{ /* PC_RHEL7_1_COMPAT */ \ ++ .driver = "Nehalem" "-" TYPE_X86_CPU,\ ++ .property = "min-level",\ ++ .value = stringify(4),\ ++ },{ /* PC_RHEL7_1_COMPAT */ \ ++ .driver = "n270" "-" TYPE_X86_CPU,\ ++ .property = "min-xlevel",\ ++ .value = stringify(0x8000000a),\ ++ },{ /* PC_RHEL7_1_COMPAT */ \ ++ .driver = "Penryn" "-" TYPE_X86_CPU,\ ++ .property = "min-xlevel",\ ++ .value = stringify(0x8000000a),\ ++ },{ /* PC_RHEL7_1_COMPAT */ \ ++ .driver = "Conroe" "-" TYPE_X86_CPU,\ ++ .property = "min-xlevel",\ ++ .value = stringify(0x8000000a),\ ++ },{ /* PC_RHEL7_1_COMPAT */ \ ++ .driver = "Nehalem" "-" TYPE_X86_CPU,\ ++ .property = "min-xlevel",\ ++ .value = stringify(0x8000000a),\ ++ },{ /* PC_RHEL7_1_COMPAT */ \ ++ .driver = "Westmere" "-" TYPE_X86_CPU,\ ++ .property = "min-xlevel",\ ++ .value = stringify(0x8000000a),\ ++ },{ /* PC_RHEL7_1_COMPAT */ \ ++ .driver = "SandyBridge" "-" TYPE_X86_CPU,\ ++ .property = "min-xlevel",\ ++ .value = stringify(0x8000000a),\ ++ },{ /* PC_RHEL7_1_COMPAT */ \ ++ .driver = "IvyBridge" "-" TYPE_X86_CPU,\ ++ .property = "min-xlevel",\ ++ .value = stringify(0x8000000a),\ ++ },{ /* PC_RHEL7_1_COMPAT */ \ ++ .driver = "Haswell" "-" TYPE_X86_CPU,\ ++ .property = "min-xlevel",\ ++ .value = stringify(0x8000000a),\ ++ },{ /* PC_RHEL7_1_COMPAT */ \ ++ .driver = "Haswell-noTSX" "-" TYPE_X86_CPU,\ ++ .property = "min-xlevel",\ ++ .value = stringify(0x8000000a),\ ++ },{ /* PC_RHEL7_1_COMPAT */ \ ++ .driver = "Broadwell" "-" TYPE_X86_CPU,\ ++ .property = "min-xlevel",\ ++ .value = stringify(0x8000000a),\ ++ },{ /* PC_RHEL7_1_COMPAT */ \ ++ .driver = "Broadwell-noTSX" "-" TYPE_X86_CPU,\ ++ .property = "min-xlevel",\ ++ .value = stringify(0x8000000a),\ ++ }, ++ ++/* ++ * The PC_RHEL_*_COMPAT serve the same purpose for RHEL-7 machine ++ * types as the PC_COMPAT_* do for upstream types. ++ * PC_RHEL_7_*_COMPAT apply both to i440fx and q35 types. ++ * PC_RHEL6_*_COMPAT apply to i440fx types only, and therefore live ++ * in pc_piix.c. ++ */ ++ ++/* ++ * RHEL-7 is based on QEMU 1.5.3, so this needs the PC_COMPAT_* ++ * between our base and 1.5, less stuff backported to RHEL-7.0 ++ * (usb-device.msos-desc), less stuff for devices we changed ++ * (qemu64-x86_64-cpu) or don't support (hpet, pci-serial-2x, ++ * pci-serial-4x) in 7.0. ++ */ ++#define PC_RHEL7_0_COMPAT \ ++ {\ ++ .driver = "virtio-scsi-pci",\ ++ .property = "any_layout",\ ++ .value = "off",\ ++ },{\ ++ .driver = "PIIX4_PM",\ ++ .property = "memory-hotplug-support",\ ++ .value = "off",\ ++ },{\ ++ .driver = "apic",\ ++ .property = "version",\ ++ .value = stringify(0x11),\ ++ },{\ ++ .driver = "nec-usb-xhci",\ ++ .property = "superspeed-ports-first",\ ++ .value = "off",\ ++ },{\ ++ .driver = "nec-usb-xhci",\ ++ .property = "force-pcie-endcap",\ ++ .value = "on",\ ++ },{\ ++ .driver = "pci-serial",\ ++ .property = "prog_if",\ ++ .value = stringify(0),\ ++ },{\ ++ .driver = "virtio-net-pci",\ ++ .property = "guest_announce",\ ++ .value = "off",\ ++ },{\ ++ .driver = "ICH9-LPC",\ ++ .property = "memory-hotplug-support",\ ++ .value = "off",\ ++ },{\ ++ .driver = "xio3130-downstream",\ ++ .property = COMPAT_PROP_PCP,\ ++ .value = "off",\ ++ },{\ ++ .driver = "ioh3420",\ ++ .property = COMPAT_PROP_PCP,\ ++ .value = "off",\ ++ },{\ ++ .driver = "PIIX4_PM",\ ++ .property = "acpi-pci-hotplug-with-bridge-support",\ ++ .value = "off",\ ++ },{\ ++ .driver = "e1000",\ ++ .property = "mitigation",\ ++ .value = "off",\ ++ },{ \ ++ .driver = "virtio-net-pci", \ ++ .property = "ctrl_guest_offloads", \ ++ .value = "off", \ ++ },\ ++ {\ ++ .driver = "Conroe" "-" TYPE_X86_CPU,\ ++ .property = "x2apic",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "Penryn" "-" TYPE_X86_CPU,\ ++ .property = "x2apic",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "Nehalem" "-" TYPE_X86_CPU,\ ++ .property = "x2apic",\ ++ .value = "on",\ ++ },\ ++ { /* PC_RHEL7_0_COMPAT (copied from the entry above) */ \ ++ .driver = "Nehalem-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "x2apic",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "Westmere" "-" TYPE_X86_CPU,\ ++ .property = "x2apic",\ ++ .value = "on",\ ++ },\ ++ { /* PC_RHEL7_0_COMPAT (copied from the entry above) */ \ ++ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ ++ .property = "x2apic",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "Opteron_G1" "-" TYPE_X86_CPU,\ ++ .property = "x2apic",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "Opteron_G2" "-" TYPE_X86_CPU,\ ++ .property = "x2apic",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "Opteron_G3" "-" TYPE_X86_CPU,\ ++ .property = "x2apic",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "Opteron_G4" "-" TYPE_X86_CPU,\ ++ .property = "x2apic",\ ++ .value = "on",\ ++ },\ ++ {\ ++ .driver = "Opteron_G5" "-" TYPE_X86_CPU,\ ++ .property = "x2apic",\ ++ .value = "on",\ ++ }, + #endif +diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h +index d60b7c6..5118af6 100644 +--- a/include/hw/ppc/spapr.h ++++ b/include/hw/ppc/spapr.h +@@ -98,6 +98,7 @@ struct sPAPRMachineClass { + bool dr_lmb_enabled; /* enable dynamic-reconfig/hotplug of LMBs */ + bool use_ohci_by_default; /* use USB-OHCI instead of XHCI */ + bool pre_2_10_has_unused_icps; ++ bool has_power9_support; + void (*phb_placement)(sPAPRMachineState *spapr, uint32_t index, + uint64_t *buid, hwaddr *pio, + hwaddr *mmio32, hwaddr *mmio64, +diff --git a/include/hw/usb.h b/include/hw/usb.h +index a5080ad..5b3fb1f 100644 +--- a/include/hw/usb.h ++++ b/include/hw/usb.h +@@ -606,4 +606,11 @@ int usb_get_quirks(uint16_t vendor_id, uint16_t product_id, + uint8_t interface_class, uint8_t interface_subclass, + uint8_t interface_protocol); + ++ ++/* hcd-uhci.c -- RHEL-6 machine type compatibility */ ++extern bool ich9_uhci123_irqpin_override; ++ ++/* hcd-xhci.c -- rhel7.0.0 machine type compatibility */ ++extern bool migrate_cve_2014_5263_xhci_fields; ++ + #endif +diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h +index 098bdaa..41e13d2 100644 +--- a/include/hw/virtio/virtio.h ++++ b/include/hw/virtio/virtio.h +@@ -95,6 +95,7 @@ struct VirtIODevice + uint8_t device_endian; + bool use_guest_notifier_mask; + AddressSpace *dma_as; ++ bool rhel6_ctrl_guest_workaround; + QLIST_HEAD(, VirtQueue) *vector_queues; + }; + +diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h +index 2b42151..5832c38 100644 +--- a/include/sysemu/sysemu.h ++++ b/include/sysemu/sysemu.h +@@ -94,6 +94,8 @@ void qemu_add_machine_init_done_notifier(Notifier *notify); + void qemu_remove_machine_init_done_notifier(Notifier *notify); + + void qemu_announce_self(void); ++extern bool shadow_bios_after_incoming; ++void shadow_bios(void); + + extern int autostart; + +diff --git a/migration/migration.c b/migration/migration.c +index 52a5092..ceb1697 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -99,6 +99,8 @@ enum mig_rp_message_type { + MIG_RP_MSG_MAX + }; + ++bool migrate_pre_2_2; ++ + /* When we add fault tolerance, we could have several + migrations at once. For now we don't need to add + dynamic creation of migration */ +diff --git a/migration/migration.h b/migration/migration.h +index 8d2f320..06833d7 100644 +--- a/migration/migration.h ++++ b/migration/migration.h +@@ -241,5 +241,10 @@ int migrate_send_rp_req_pages(MigrationIncomingState *mis, const char* rbname, + + void dirty_bitmap_mig_before_vm_start(void); + void init_dirty_bitmap_incoming_migration(void); ++/* ++ * Disables a load of subsections that were added in 2.2/rh7.2 for backwards ++ * migration compatibility. ++ */ ++extern bool migrate_pre_2_2; + + #endif +diff --git a/migration/savevm.c b/migration/savevm.c +index e2be02a..56c9feb 100644 +--- a/migration/savevm.c ++++ b/migration/savevm.c +@@ -45,6 +45,7 @@ + #include "qapi/qapi-commands-misc.h" + #include "qapi/qmp/qerror.h" + #include "qemu/error-report.h" ++#include "qemu/rcu_queue.h" + #include "sysemu/cpus.h" + #include "exec/memory.h" + #include "exec/target_page.h" +@@ -83,6 +84,7 @@ enum qemu_vm_cmd { + MIG_CMD_PACKAGED, /* Send a wrapped stream within this stream */ + MIG_CMD_MAX + }; ++bool shadow_bios_after_incoming; + + #define MAX_VM_CMD_PACKAGED_SIZE UINT32_MAX + static struct mig_cmd_args { +@@ -2204,6 +2206,13 @@ int qemu_loadvm_state(QEMUFile *f) + } + + qemu_loadvm_state_cleanup(); ++ /* Supplement SeaBIOS's shadowing now, because it was useless when the ++ * incoming VM started on the RHEL-6 emulator. ++ */ ++ if (shadow_bios_after_incoming) { ++ shadow_bios(); ++ } ++ + cpu_synchronize_all_post_init(); + + return ret; +diff --git a/numa.c b/numa.c +index 1116c90..daf10d8 100644 +--- a/numa.c ++++ b/numa.c +@@ -493,6 +493,19 @@ void memory_region_allocate_system_memory(MemoryRegion *mr, Object *owner, + return; + } + ++ /* The shadow_bios_after_incoming hack at savevm.c:shadow_bios() is not ++ * able to handle the multiple memory blocks added when using NUMA ++ * memdevs. We can disallow -numa memdev= when using rhel6.* machine-types ++ * because RHEL-6 didn't support the NUMA memdev option. ++ */ ++ if (shadow_bios_after_incoming) { ++ MachineClass *mc; ++ mc = MACHINE_GET_CLASS(current_machine); ++ error_report("-numa memdev is not supported by machine %s", ++ mc->name); ++ exit(1); ++ } ++ + memory_region_init(mr, owner, name, ram_size); + for (i = 0; i < nb_numa_nodes; i++) { + uint64_t size = numa_info[i].node_mem; +diff --git a/qdev-monitor.c b/qdev-monitor.c +index 61e0300..f439b83 100644 +--- a/qdev-monitor.c ++++ b/qdev-monitor.c +@@ -47,7 +47,6 @@ typedef struct QDevAlias + + /* Please keep this table sorted by typename. */ + static const QDevAlias qdev_alias_table[] = { +- { "e1000", "e1000-82540em" }, + { "ich9-ahci", "ahci" }, + { "lsi53c895a", "lsi" }, + { "virtio-9p-ccw", "virtio-9p", QEMU_ARCH_S390X }, +diff --git a/scripts/vmstate-static-checker.py b/scripts/vmstate-static-checker.py +index bcef7ee..ffb13d1 100755 +--- a/scripts/vmstate-static-checker.py ++++ b/scripts/vmstate-static-checker.py +@@ -104,7 +104,6 @@ def get_changed_sec_name(sec): + # Section names can change -- see commit 292b1634 for an example. + changes = { + "ICH9 LPC": "ICH9-LPC", +- "e1000-82540em": "e1000", + } + + for item in changes: +diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs +index dfdfca7..8f111c5 100644 +--- a/stubs/Makefile.objs ++++ b/stubs/Makefile.objs +@@ -44,3 +44,4 @@ stub-obj-y += xen-hvm.o + stub-obj-y += pci-host-piix.o + stub-obj-y += ram-block.o + stub-obj-y += ide-isa.o ++stub-obj-y += shadow-bios.o +diff --git a/stubs/shadow-bios.c b/stubs/shadow-bios.c +new file mode 100644 +index 0000000..c77cd7a +--- /dev/null ++++ b/stubs/shadow-bios.c +@@ -0,0 +1,7 @@ ++#include "qemu/osdep.h" ++#include "sysemu/sysemu.h" ++ ++void shadow_bios(void) ++{ ++ abort(); ++} +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index f483a71..a9db495 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -819,11 +819,17 @@ struct X86CPUDefinition { + + static X86CPUDefinition builtin_x86_defs[] = { + { ++ /* qemu64 is the default CPU model for all *-rhel7.* machine-types. ++ * The default on RHEL-6 was cpu64-rhel6. ++ * libvirt assumes that qemu64 is the default for _all_ machine-types, ++ * so we should try to keep qemu64 and cpu64-rhel6 as similar as ++ * possible. ++ */ + .name = "qemu64", + .level = 0xd, + .vendor = CPUID_VENDOR_AMD, + .family = 6, +- .model = 6, ++ .model = 13, + .stepping = 3, + .features[FEAT_1_EDX] = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | + CPUID_MMX | CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | +@@ -2097,6 +2103,7 @@ static PropValue kvm_default_props[] = { + { "acpi", "off" }, + { "monitor", "off" }, + { "svm", "off" }, ++ { "kvm-pv-unhalt", "on" }, + { NULL, NULL }, + }; + +diff --git a/target/i386/machine.c b/target/i386/machine.c +index bd2d82e..c9a3b5c 100644 +--- a/target/i386/machine.c ++++ b/target/i386/machine.c +@@ -893,6 +893,26 @@ static const VMStateDescription vmstate_msr_intel_pt = { + } + }; + ++static bool vmstate_xsave_needed(void *opaque) ++{ ++ /* The xsave state is already on the main "cpu" section */ ++ return false; ++} ++ ++static const VMStateDescription vmstate_xsave ={ ++ .name = "cpu/xsave", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .minimum_version_id_old = 1, ++ .needed = vmstate_xsave_needed, ++ .fields = (VMStateField []) { ++ VMSTATE_UINT64_V(env.xcr0, X86CPU, 1), ++ VMSTATE_UINT64_V(env.xstate_bv, X86CPU, 1), ++ VMSTATE_YMMH_REGS_VARS(env.xmm_regs, X86CPU, CPU_NB_REGS, 1), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ + VMStateDescription vmstate_x86_cpu = { + .name = "cpu", + .version_id = 12, +@@ -1015,6 +1035,7 @@ VMStateDescription vmstate_x86_cpu = { + &vmstate_spec_ctrl, + &vmstate_mcg_ext_ctl, + &vmstate_msr_intel_pt, ++ &vmstate_xsave, + NULL + } + }; +diff --git a/target/ppc/compat.c b/target/ppc/compat.c +index 807c906..33658fb 100644 +--- a/target/ppc/compat.c ++++ b/target/ppc/compat.c +@@ -105,6 +105,17 @@ static const CompatInfo *compat_by_pvr(uint32_t pvr) + return NULL; + } + ++long ppc_compat_cmp(uint32_t pvr1, uint32_t pvr2) ++{ ++ const CompatInfo *compat1 = compat_by_pvr(pvr1); ++ const CompatInfo *compat2 = compat_by_pvr(pvr2); ++ ++ g_assert(compat1); ++ g_assert(compat2); ++ ++ return compat1 - compat2; ++} ++ + bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr, + uint32_t min_compat_pvr, uint32_t max_compat_pvr) + { +diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h +index c621a6b..1932c2e 100644 +--- a/target/ppc/cpu.h ++++ b/target/ppc/cpu.h +@@ -1391,6 +1391,7 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch) + + /* Compatibility modes */ + #if defined(TARGET_PPC64) ++long ppc_compat_cmp(uint32_t pvr1, uint32_t pvr2); + bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr, + uint32_t min_compat_pvr, uint32_t max_compat_pvr); + void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp); +diff --git a/tests/Makefile.include b/tests/Makefile.include +index e4125a6..5cb1902 100644 +--- a/tests/Makefile.include ++++ b/tests/Makefile.include +@@ -310,14 +310,14 @@ check-qtest-ppc-y += tests/boot-order-test$(EXESUF) + #check-qtest-ppc-y += tests/prom-env-test$(EXESUF) + check-qtest-ppc-y += tests/drive_del-test$(EXESUF) + check-qtest-ppc-y += tests/boot-serial-test$(EXESUF) +-check-qtest-ppc-y += tests/m48t59-test$(EXESUF) +-gcov-files-ppc-y += hw/timer/m48t59.c ++#check-qtest-ppc-y += tests/m48t59-test$(EXESUF) ++#gcov-files-ppc-y += hw/timer/m48t59.c + + check-qtest-ppc64-y = $(check-qtest-ppc-y) + gcov-files-ppc64-y = $(subst ppc-softmmu/,ppc64-softmmu/,$(gcov-files-ppc-y)) + check-qtest-ppc64-y += tests/spapr-phb-test$(EXESUF) + gcov-files-ppc64-y += ppc64-softmmu/hw/ppc/spapr_pci.c +-check-qtest-ppc64-y += tests/pnv-xscom-test$(EXESUF) ++#check-qtest-ppc64-y += tests/pnv-xscom-test$(EXESUF) + check-qtest-ppc64-y += tests/migration-test$(EXESUF) + check-qtest-ppc64-y += tests/rtas-test$(EXESUF) + check-qtest-ppc64-$(CONFIG_SLIRP) += tests/pxe-test$(EXESUF) +@@ -733,7 +733,7 @@ libqos-virtio-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/virt + tests/qmp-test$(EXESUF): tests/qmp-test.o + tests/device-introspect-test$(EXESUF): tests/device-introspect-test.o + tests/rtc-test$(EXESUF): tests/rtc-test.o +-tests/m48t59-test$(EXESUF): tests/m48t59-test.o ++#tests/m48t59-test$(EXESUF): tests/m48t59-test.o + tests/endianness-test$(EXESUF): tests/endianness-test.o + tests/spapr-phb-test$(EXESUF): tests/spapr-phb-test.o $(libqos-obj-y) + #tests/prom-env-test$(EXESUF): tests/prom-env-test.o $(libqos-obj-y) +diff --git a/tests/cpu-plug-test.c b/tests/cpu-plug-test.c +index 8b5ab1f..112869b 100644 +--- a/tests/cpu-plug-test.c ++++ b/tests/cpu-plug-test.c +@@ -192,7 +192,8 @@ static void add_pseries_test_case(const char *mname) + PlugTestData *data; + + if (!g_str_has_prefix(mname, "pseries-") || +- (g_str_has_prefix(mname, "pseries-2.") && atoi(&mname[10]) < 7)) { ++ (g_str_has_prefix(mname, "pseries-2.") && atoi(&mname[10]) < 7) || ++ strcmp(mname,"pseries-rhel7.2.0") == 0) { + return; + } + data = g_new(PlugTestData, 1); +-- +1.8.3.1 + diff --git a/SOURCES/0005-Use-kvm-by-default.patch b/SOURCES/0005-Use-kvm-by-default.patch deleted file mode 100644 index 7145f04..0000000 --- a/SOURCES/0005-Use-kvm-by-default.patch +++ /dev/null @@ -1,40 +0,0 @@ -From eca6d5766d956c37e3f7f28d70903d357308c846 Mon Sep 17 00:00:00 2001 -From: Miroslav Rezanina -Date: Thu, 18 Dec 2014 06:27:49 +0100 -Subject: Use kvm by default - -Bugzilla: 906185 - -RHEL uses kvm accelerator by default, if available. - -Signed-off-by: Miroslav Rezanina - -Rebase notes (2.10.0) -- variable rename (upstream) - -Rebase notes (2.2.0): -- Move code from vl.c to accel.c - -(cherry picked from commit abcd662eb8e516ebe4a6b401e83a62f749491a15) ---- - accel/accel.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/accel/accel.c b/accel/accel.c -index 8ae40e1..9e757ff 100644 ---- a/accel/accel.c -+++ b/accel/accel.c -@@ -79,8 +79,8 @@ void configure_accelerator(MachineState *ms) - - accel = qemu_opt_get(qemu_get_machine_opts(), "accel"); - if (accel == NULL) { -- /* Use the default "accelerator", tcg */ -- accel = "tcg"; -+ /* RHEL uses kvm as the default accelerator, fallback to tcg */ -+ accel = "kvm:tcg"; - } - - p = accel; --- -1.8.3.1 - diff --git a/SOURCES/0006-Revert-kvm_stat-Remove.patch b/SOURCES/0006-Revert-kvm_stat-Remove.patch new file mode 100644 index 0000000..fe519e9 --- /dev/null +++ b/SOURCES/0006-Revert-kvm_stat-Remove.patch @@ -0,0 +1,1815 @@ +From 49ebd26734d492cc4189b97704052780b3641854 Mon Sep 17 00:00:00 2001 +From: "Danilo C. L. de Paula" +Date: Mon, 16 Jan 2017 11:52:49 +0100 +Subject: Revert "kvm_stat: Remove" + +RH-Author: ddepaula +Message-id: <1479302806-10135-2-git-send-email-ddepaula@redhat.com> +Patchwork-id: 72851 +O-Subject: [RHEV-7.4 qemu-kvm-rhev PATCH v3 1/3] Revert "kvm_stat: Remove" +Bugzilla: 1389238 +RH-Acked-by: John Snow +RH-Acked-by: David Hildenbrand +RH-Acked-by: Miroslav Rezanina + +kvm_stat script was removed in QEMU 2.7.0 as it become part of kernel +tree. However kvm_stat is shipped in qemu-kvm-tools package in RHEL. + +This reverts commit 60b412dd18362bd4ddc44ba7022aacb6af074b5d. + +Signed-off-by: Danilo Cesar Lemes de Paula +Signed-off-by: Miroslav Rezanina + +Merged patches (2.11.0): +- beffa30342 tools/kvm_stat: hide cursor +- 98cf56caaa tools/kvm_stat: catch curses exceptions only +- dada85e20a tools/kvm_stat: handle SIGINT in log and batch modes +- 8654f68785 tools/kvm_stat: fix misc glitches +- d4525d7460 tools/kvm_stat: fix trace setup glitch on field updates in TracepointProvider +- 5f41d9716a tools/kvm_stat: full PEP8 compliance +- 5bf653923c tools/kvm_stat: reduce perceived idle time on filter updates +- 2ef292f12d tools/kvm_stat: document list of interactive commands +- 3e1d2fc34c tools/kvm_stat: display guest name when using pid filter +- 66f2e8203e tools/kvm_stat: remove pid filter on empty input +- 05cc1c1aab tools/kvm_stat: print error messages on faulty pid filter input +- a0c6451760 tools/kvm_stat: display regex when set to non-default +- 3c7dae7507 tools/kvm_stat: remove regex filter on empty input +- 8b7b31fc24 tools/kvm_stat: add option '--guest' +- 38362f9d75 tools/kvm_stat: add interactive command 'c' +- 243d90a041 tools/kvm_stat: add interactive command 'r' +- 4f80c9081b tools/kvm_stat: add '%Total' column +- e21fb4a96e tools/kvm_stat: fix typo +- 7bc419ee18 tools/kvm_stat: fix event counts display for interrupted intervals +- d54183dd4b tools/kvm_stat: fix undue use of initial sleeptime +- 6514729674 tools/kvm_stat: remove unnecessary header redraws +- c4f941df75 tools/kvm_stat: simplify line print logic +- 35c050e4fd tools/kvm_stat: removed unused function +- 92d06e843c tools/kvm_stat: remove extra statement +- d0ced131bf tools/kvm_stat: simplify initializers +- 1dbc0659ac tools/kvm_stat: move functions to corresponding classes +- bf53d77372 tools/kvm_stat: show cursor in selection screens +- 6b557dc235 tools/kvm_stat: display message indicating lack of events +- 7f50a8be62 tools/kvm_stat: make heading look a bit more like 'top' +- 8ba2fd89d1 tools/kvm_stat: rename 'Current' column to 'CurAvg/s' +- 95b5c46145 tools/kvm_stat: add new interactive command 'h' +- 25c56e3212 tools/kvm_stat: add new interactive command 's' +- 55f7ed9b2c tools/kvm_stat: add new interactive command 'o' +- 53a1267b00 tools/kvm_stat: display guest list in pid/guest selection screens +- 554fa10df5 tools/kvm_stat: display guest list in pid/guest selection screens +- 72f660ddfc tools/kvm_stat: add new command line switch '-i' +- 17165a0bc8 tools/kvm_stat: add new interactive command 'b' +- ac6ba9a14b tools/kvm_stat: use variables instead of hard paths in help output +- 592b801e5c tools/kvm_stat: add '-f help' to get the available event list +- 283aa25f75 tools/kvm_stat: fix command line option '-g' + +Merged patches (2.9.0): +- 1e69b1b Include kvm_stat in qemu-kvm.spec +- 7fcfc94 tools: kvm_stat: Powerpc related fixes +- 7f89136 tools: kvm_stat: Introduce pid monitoring +- c728a6b tools: kvm_stat: Add comments +- 27fb856 Package man page of "kvm_stat" tool + +(cherry picked from commit d4a8e35b84072816c79e23f5d0a69a2145217004) +(cherry picked from commit e0425f69f136a05a59ee5cb7022409ed2be94a0b) +(cherry picked from commit 57e760aee8b28f3b2c6b9f3aad0d2b916dd13595) +(cherry picked from commit d711afa1b8ef8aba1397158626816008936ed0d6) +(cherry picked from commit 8ceca7bebce67440898c22d058047daa8ec37031) +--- + Makefile | 8 + + redhat/qemu-kvm.spec.template | 7 +- + scripts/kvm/kvm_stat | 1585 +++++++++++++++++++++++++++++++++++++++++ + scripts/kvm/kvm_stat.texi | 104 +++ + 4 files changed, 1703 insertions(+), 1 deletion(-) + create mode 100755 scripts/kvm/kvm_stat + create mode 100644 scripts/kvm/kvm_stat.texi + +diff --git a/Makefile b/Makefile +index 89ba4c5..2ffac2b 100644 +--- a/Makefile ++++ b/Makefile +@@ -354,6 +354,9 @@ DOCS=qemu-doc.html qemu-doc.txt qemu.1 qemu-img.1 qemu-nbd.8 qemu-ga.8 + DOCS+=docs/interop/qemu-qmp-ref.html docs/interop/qemu-qmp-ref.txt docs/interop/qemu-qmp-ref.7 + DOCS+=docs/interop/qemu-ga-ref.html docs/interop/qemu-ga-ref.txt docs/interop/qemu-ga-ref.7 + DOCS+=docs/qemu-block-drivers.7 ++ifdef CONFIG_LINUX ++DOCS+=kvm_stat.1 ++endif + ifdef CONFIG_VIRTFS + DOCS+=fsdev/virtfs-proxy-helper.1 + endif +@@ -955,6 +958,11 @@ html: qemu-doc.html docs/interop/qemu-qmp-ref.html docs/interop/qemu-ga-ref.html + info: qemu-doc.info docs/interop/qemu-qmp-ref.info docs/interop/qemu-ga-ref.info + pdf: qemu-doc.pdf docs/interop/qemu-qmp-ref.pdf docs/interop/qemu-ga-ref.pdf + txt: qemu-doc.txt docs/interop/qemu-qmp-ref.txt docs/interop/qemu-ga-ref.txt ++kvm_stat.1: scripts/kvm/kvm_stat.texi ++ $(call quiet-command, \ ++ perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< kvm_stat.pod && \ ++ $(POD2MAN) --section=1 --center=" " --release=" " kvm_stat.pod > $@, \ ++ " GEN $@") + + qemu-doc.html qemu-doc.info qemu-doc.pdf qemu-doc.txt: \ + qemu-img.texi qemu-nbd.texi qemu-options.texi qemu-option-trace.texi \ +diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat +new file mode 100755 +index 0000000..c74a9a0 +--- /dev/null ++++ b/scripts/kvm/kvm_stat +@@ -0,0 +1,1585 @@ ++#!/usr/bin/python ++# ++# top-like utility for displaying kvm statistics ++# ++# Copyright 2006-2008 Qumranet Technologies ++# Copyright 2008-2011 Red Hat, Inc. ++# ++# Authors: ++# Avi Kivity ++# ++# This work is licensed under the terms of the GNU GPL, version 2. See ++# the COPYING file in the top-level directory. ++"""The kvm_stat module outputs statistics about running KVM VMs ++ ++Three different ways of output formatting are available: ++- as a top-like text ui ++- in a key -> value format ++- in an all keys, all values format ++ ++The data is sampled from the KVM's debugfs entries and its perf events. ++""" ++ ++import curses ++import sys ++import os ++import time ++import optparse ++import ctypes ++import fcntl ++import resource ++import struct ++import re ++import subprocess ++from collections import defaultdict ++ ++VMX_EXIT_REASONS = { ++ 'EXCEPTION_NMI': 0, ++ 'EXTERNAL_INTERRUPT': 1, ++ 'TRIPLE_FAULT': 2, ++ 'PENDING_INTERRUPT': 7, ++ 'NMI_WINDOW': 8, ++ 'TASK_SWITCH': 9, ++ 'CPUID': 10, ++ 'HLT': 12, ++ 'INVLPG': 14, ++ 'RDPMC': 15, ++ 'RDTSC': 16, ++ 'VMCALL': 18, ++ 'VMCLEAR': 19, ++ 'VMLAUNCH': 20, ++ 'VMPTRLD': 21, ++ 'VMPTRST': 22, ++ 'VMREAD': 23, ++ 'VMRESUME': 24, ++ 'VMWRITE': 25, ++ 'VMOFF': 26, ++ 'VMON': 27, ++ 'CR_ACCESS': 28, ++ 'DR_ACCESS': 29, ++ 'IO_INSTRUCTION': 30, ++ 'MSR_READ': 31, ++ 'MSR_WRITE': 32, ++ 'INVALID_STATE': 33, ++ 'MWAIT_INSTRUCTION': 36, ++ 'MONITOR_INSTRUCTION': 39, ++ 'PAUSE_INSTRUCTION': 40, ++ 'MCE_DURING_VMENTRY': 41, ++ 'TPR_BELOW_THRESHOLD': 43, ++ 'APIC_ACCESS': 44, ++ 'EPT_VIOLATION': 48, ++ 'EPT_MISCONFIG': 49, ++ 'WBINVD': 54, ++ 'XSETBV': 55, ++ 'APIC_WRITE': 56, ++ 'INVPCID': 58, ++} ++ ++SVM_EXIT_REASONS = { ++ 'READ_CR0': 0x000, ++ 'READ_CR3': 0x003, ++ 'READ_CR4': 0x004, ++ 'READ_CR8': 0x008, ++ 'WRITE_CR0': 0x010, ++ 'WRITE_CR3': 0x013, ++ 'WRITE_CR4': 0x014, ++ 'WRITE_CR8': 0x018, ++ 'READ_DR0': 0x020, ++ 'READ_DR1': 0x021, ++ 'READ_DR2': 0x022, ++ 'READ_DR3': 0x023, ++ 'READ_DR4': 0x024, ++ 'READ_DR5': 0x025, ++ 'READ_DR6': 0x026, ++ 'READ_DR7': 0x027, ++ 'WRITE_DR0': 0x030, ++ 'WRITE_DR1': 0x031, ++ 'WRITE_DR2': 0x032, ++ 'WRITE_DR3': 0x033, ++ 'WRITE_DR4': 0x034, ++ 'WRITE_DR5': 0x035, ++ 'WRITE_DR6': 0x036, ++ 'WRITE_DR7': 0x037, ++ 'EXCP_BASE': 0x040, ++ 'INTR': 0x060, ++ 'NMI': 0x061, ++ 'SMI': 0x062, ++ 'INIT': 0x063, ++ 'VINTR': 0x064, ++ 'CR0_SEL_WRITE': 0x065, ++ 'IDTR_READ': 0x066, ++ 'GDTR_READ': 0x067, ++ 'LDTR_READ': 0x068, ++ 'TR_READ': 0x069, ++ 'IDTR_WRITE': 0x06a, ++ 'GDTR_WRITE': 0x06b, ++ 'LDTR_WRITE': 0x06c, ++ 'TR_WRITE': 0x06d, ++ 'RDTSC': 0x06e, ++ 'RDPMC': 0x06f, ++ 'PUSHF': 0x070, ++ 'POPF': 0x071, ++ 'CPUID': 0x072, ++ 'RSM': 0x073, ++ 'IRET': 0x074, ++ 'SWINT': 0x075, ++ 'INVD': 0x076, ++ 'PAUSE': 0x077, ++ 'HLT': 0x078, ++ 'INVLPG': 0x079, ++ 'INVLPGA': 0x07a, ++ 'IOIO': 0x07b, ++ 'MSR': 0x07c, ++ 'TASK_SWITCH': 0x07d, ++ 'FERR_FREEZE': 0x07e, ++ 'SHUTDOWN': 0x07f, ++ 'VMRUN': 0x080, ++ 'VMMCALL': 0x081, ++ 'VMLOAD': 0x082, ++ 'VMSAVE': 0x083, ++ 'STGI': 0x084, ++ 'CLGI': 0x085, ++ 'SKINIT': 0x086, ++ 'RDTSCP': 0x087, ++ 'ICEBP': 0x088, ++ 'WBINVD': 0x089, ++ 'MONITOR': 0x08a, ++ 'MWAIT': 0x08b, ++ 'MWAIT_COND': 0x08c, ++ 'XSETBV': 0x08d, ++ 'NPF': 0x400, ++} ++ ++# EC definition of HSR (from arch/arm64/include/asm/kvm_arm.h) ++AARCH64_EXIT_REASONS = { ++ 'UNKNOWN': 0x00, ++ 'WFI': 0x01, ++ 'CP15_32': 0x03, ++ 'CP15_64': 0x04, ++ 'CP14_MR': 0x05, ++ 'CP14_LS': 0x06, ++ 'FP_ASIMD': 0x07, ++ 'CP10_ID': 0x08, ++ 'CP14_64': 0x0C, ++ 'ILL_ISS': 0x0E, ++ 'SVC32': 0x11, ++ 'HVC32': 0x12, ++ 'SMC32': 0x13, ++ 'SVC64': 0x15, ++ 'HVC64': 0x16, ++ 'SMC64': 0x17, ++ 'SYS64': 0x18, ++ 'IABT': 0x20, ++ 'IABT_HYP': 0x21, ++ 'PC_ALIGN': 0x22, ++ 'DABT': 0x24, ++ 'DABT_HYP': 0x25, ++ 'SP_ALIGN': 0x26, ++ 'FP_EXC32': 0x28, ++ 'FP_EXC64': 0x2C, ++ 'SERROR': 0x2F, ++ 'BREAKPT': 0x30, ++ 'BREAKPT_HYP': 0x31, ++ 'SOFTSTP': 0x32, ++ 'SOFTSTP_HYP': 0x33, ++ 'WATCHPT': 0x34, ++ 'WATCHPT_HYP': 0x35, ++ 'BKPT32': 0x38, ++ 'VECTOR32': 0x3A, ++ 'BRK64': 0x3C, ++} ++ ++# From include/uapi/linux/kvm.h, KVM_EXIT_xxx ++USERSPACE_EXIT_REASONS = { ++ 'UNKNOWN': 0, ++ 'EXCEPTION': 1, ++ 'IO': 2, ++ 'HYPERCALL': 3, ++ 'DEBUG': 4, ++ 'HLT': 5, ++ 'MMIO': 6, ++ 'IRQ_WINDOW_OPEN': 7, ++ 'SHUTDOWN': 8, ++ 'FAIL_ENTRY': 9, ++ 'INTR': 10, ++ 'SET_TPR': 11, ++ 'TPR_ACCESS': 12, ++ 'S390_SIEIC': 13, ++ 'S390_RESET': 14, ++ 'DCR': 15, ++ 'NMI': 16, ++ 'INTERNAL_ERROR': 17, ++ 'OSI': 18, ++ 'PAPR_HCALL': 19, ++ 'S390_UCONTROL': 20, ++ 'WATCHDOG': 21, ++ 'S390_TSCH': 22, ++ 'EPR': 23, ++ 'SYSTEM_EVENT': 24, ++} ++ ++IOCTL_NUMBERS = { ++ 'SET_FILTER': 0x40082406, ++ 'ENABLE': 0x00002400, ++ 'DISABLE': 0x00002401, ++ 'RESET': 0x00002403, ++} ++ ++ ++class Arch(object): ++ """Encapsulates global architecture specific data. ++ ++ Contains the performance event open syscall and ioctl numbers, as ++ well as the VM exit reasons for the architecture it runs on. ++ ++ """ ++ @staticmethod ++ def get_arch(): ++ machine = os.uname()[4] ++ ++ if machine.startswith('ppc'): ++ return ArchPPC() ++ elif machine.startswith('aarch64'): ++ return ArchA64() ++ elif machine.startswith('s390'): ++ return ArchS390() ++ else: ++ # X86_64 ++ for line in open('/proc/cpuinfo'): ++ if not line.startswith('flags'): ++ continue ++ ++ flags = line.split() ++ if 'vmx' in flags: ++ return ArchX86(VMX_EXIT_REASONS) ++ if 'svm' in flags: ++ return ArchX86(SVM_EXIT_REASONS) ++ return ++ ++ ++class ArchX86(Arch): ++ def __init__(self, exit_reasons): ++ self.sc_perf_evt_open = 298 ++ self.ioctl_numbers = IOCTL_NUMBERS ++ self.exit_reasons = exit_reasons ++ ++ ++class ArchPPC(Arch): ++ def __init__(self): ++ self.sc_perf_evt_open = 319 ++ self.ioctl_numbers = IOCTL_NUMBERS ++ self.ioctl_numbers['ENABLE'] = 0x20002400 ++ self.ioctl_numbers['DISABLE'] = 0x20002401 ++ self.ioctl_numbers['RESET'] = 0x20002403 ++ ++ # PPC comes in 32 and 64 bit and some generated ioctl ++ # numbers depend on the wordsize. ++ char_ptr_size = ctypes.sizeof(ctypes.c_char_p) ++ self.ioctl_numbers['SET_FILTER'] = 0x80002406 | char_ptr_size << 16 ++ self.exit_reasons = {} ++ ++ ++class ArchA64(Arch): ++ def __init__(self): ++ self.sc_perf_evt_open = 241 ++ self.ioctl_numbers = IOCTL_NUMBERS ++ self.exit_reasons = AARCH64_EXIT_REASONS ++ ++ ++class ArchS390(Arch): ++ def __init__(self): ++ self.sc_perf_evt_open = 331 ++ self.ioctl_numbers = IOCTL_NUMBERS ++ self.exit_reasons = None ++ ++ARCH = Arch.get_arch() ++ ++ ++class perf_event_attr(ctypes.Structure): ++ """Struct that holds the necessary data to set up a trace event. ++ ++ For an extensive explanation see perf_event_open(2) and ++ include/uapi/linux/perf_event.h, struct perf_event_attr ++ ++ All fields that are not initialized in the constructor are 0. ++ ++ """ ++ _fields_ = [('type', ctypes.c_uint32), ++ ('size', ctypes.c_uint32), ++ ('config', ctypes.c_uint64), ++ ('sample_freq', ctypes.c_uint64), ++ ('sample_type', ctypes.c_uint64), ++ ('read_format', ctypes.c_uint64), ++ ('flags', ctypes.c_uint64), ++ ('wakeup_events', ctypes.c_uint32), ++ ('bp_type', ctypes.c_uint32), ++ ('bp_addr', ctypes.c_uint64), ++ ('bp_len', ctypes.c_uint64), ++ ] ++ ++ def __init__(self): ++ super(self.__class__, self).__init__() ++ self.type = PERF_TYPE_TRACEPOINT ++ self.size = ctypes.sizeof(self) ++ self.read_format = PERF_FORMAT_GROUP ++ ++ ++PERF_TYPE_TRACEPOINT = 2 ++PERF_FORMAT_GROUP = 1 << 3 ++ ++PATH_DEBUGFS_TRACING = '/sys/kernel/debug/tracing' ++PATH_DEBUGFS_KVM = '/sys/kernel/debug/kvm' ++ ++ ++class Group(object): ++ """Represents a perf event group.""" ++ ++ def __init__(self): ++ self.events = [] ++ ++ def add_event(self, event): ++ self.events.append(event) ++ ++ def read(self): ++ """Returns a dict with 'event name: value' for all events in the ++ group. ++ ++ Values are read by reading from the file descriptor of the ++ event that is the group leader. See perf_event_open(2) for ++ details. ++ ++ Read format for the used event configuration is: ++ struct read_format { ++ u64 nr; /* The number of events */ ++ struct { ++ u64 value; /* The value of the event */ ++ } values[nr]; ++ }; ++ ++ """ ++ length = 8 * (1 + len(self.events)) ++ read_format = 'xxxxxxxx' + 'Q' * len(self.events) ++ return dict(zip([event.name for event in self.events], ++ struct.unpack(read_format, ++ os.read(self.events[0].fd, length)))) ++ ++ ++class Event(object): ++ """Represents a performance event and manages its life cycle.""" ++ def __init__(self, name, group, trace_cpu, trace_pid, trace_point, ++ trace_filter, trace_set='kvm'): ++ self.libc = ctypes.CDLL('libc.so.6', use_errno=True) ++ self.syscall = self.libc.syscall ++ self.name = name ++ self.fd = None ++ self.setup_event(group, trace_cpu, trace_pid, trace_point, ++ trace_filter, trace_set) ++ ++ def __del__(self): ++ """Closes the event's file descriptor. ++ ++ As no python file object was created for the file descriptor, ++ python will not reference count the descriptor and will not ++ close it itself automatically, so we do it. ++ ++ """ ++ if self.fd: ++ os.close(self.fd) ++ ++ def perf_event_open(self, attr, pid, cpu, group_fd, flags): ++ """Wrapper for the sys_perf_evt_open() syscall. ++ ++ Used to set up performance events, returns a file descriptor or -1 ++ on error. ++ ++ Attributes are: ++ - syscall number ++ - struct perf_event_attr * ++ - pid or -1 to monitor all pids ++ - cpu number or -1 to monitor all cpus ++ - The file descriptor of the group leader or -1 to create a group. ++ - flags ++ ++ """ ++ return self.syscall(ARCH.sc_perf_evt_open, ctypes.pointer(attr), ++ ctypes.c_int(pid), ctypes.c_int(cpu), ++ ctypes.c_int(group_fd), ctypes.c_long(flags)) ++ ++ def setup_event_attribute(self, trace_set, trace_point): ++ """Returns an initialized ctype perf_event_attr struct.""" ++ ++ id_path = os.path.join(PATH_DEBUGFS_TRACING, 'events', trace_set, ++ trace_point, 'id') ++ ++ event_attr = perf_event_attr() ++ event_attr.config = int(open(id_path).read()) ++ return event_attr ++ ++ def setup_event(self, group, trace_cpu, trace_pid, trace_point, ++ trace_filter, trace_set): ++ """Sets up the perf event in Linux. ++ ++ Issues the syscall to register the event in the kernel and ++ then sets the optional filter. ++ ++ """ ++ ++ event_attr = self.setup_event_attribute(trace_set, trace_point) ++ ++ # First event will be group leader. ++ group_leader = -1 ++ ++ # All others have to pass the leader's descriptor instead. ++ if group.events: ++ group_leader = group.events[0].fd ++ ++ fd = self.perf_event_open(event_attr, trace_pid, ++ trace_cpu, group_leader, 0) ++ if fd == -1: ++ err = ctypes.get_errno() ++ raise OSError(err, os.strerror(err), ++ 'while calling sys_perf_event_open().') ++ ++ if trace_filter: ++ fcntl.ioctl(fd, ARCH.ioctl_numbers['SET_FILTER'], ++ trace_filter) ++ ++ self.fd = fd ++ ++ def enable(self): ++ """Enables the trace event in the kernel. ++ ++ Enabling the group leader makes reading counters from it and the ++ events under it possible. ++ ++ """ ++ fcntl.ioctl(self.fd, ARCH.ioctl_numbers['ENABLE'], 0) ++ ++ def disable(self): ++ """Disables the trace event in the kernel. ++ ++ Disabling the group leader makes reading all counters under it ++ impossible. ++ ++ """ ++ fcntl.ioctl(self.fd, ARCH.ioctl_numbers['DISABLE'], 0) ++ ++ def reset(self): ++ """Resets the count of the trace event in the kernel.""" ++ fcntl.ioctl(self.fd, ARCH.ioctl_numbers['RESET'], 0) ++ ++ ++class Provider(object): ++ """Encapsulates functionalities used by all providers.""" ++ @staticmethod ++ def is_field_wanted(fields_filter, field): ++ """Indicate whether field is valid according to fields_filter.""" ++ if not fields_filter or fields_filter == "help": ++ return True ++ return re.match(fields_filter, field) is not None ++ ++ @staticmethod ++ def walkdir(path): ++ """Returns os.walk() data for specified directory. ++ ++ As it is only a wrapper it returns the same 3-tuple of (dirpath, ++ dirnames, filenames). ++ """ ++ return next(os.walk(path)) ++ ++ ++class TracepointProvider(Provider): ++ """Data provider for the stats class. ++ ++ Manages the events/groups from which it acquires its data. ++ ++ """ ++ def __init__(self, pid, fields_filter): ++ self.group_leaders = [] ++ self.filters = self.get_filters() ++ self.update_fields(fields_filter) ++ self.pid = pid ++ ++ @staticmethod ++ def get_filters(): ++ """Returns a dict of trace events, their filter ids and ++ the values that can be filtered. ++ ++ Trace events can be filtered for special values by setting a ++ filter string via an ioctl. The string normally has the format ++ identifier==value. For each filter a new event will be created, to ++ be able to distinguish the events. ++ ++ """ ++ filters = {} ++ filters['kvm_userspace_exit'] = ('reason', USERSPACE_EXIT_REASONS) ++ if ARCH.exit_reasons: ++ filters['kvm_exit'] = ('exit_reason', ARCH.exit_reasons) ++ return filters ++ ++ def get_available_fields(self): ++ """Returns a list of available event's of format 'event name(filter ++ name)'. ++ ++ All available events have directories under ++ /sys/kernel/debug/tracing/events/ which export information ++ about the specific event. Therefore, listing the dirs gives us ++ a list of all available events. ++ ++ Some events like the vm exit reasons can be filtered for ++ specific values. To take account for that, the routine below ++ creates special fields with the following format: ++ event name(filter name) ++ ++ """ ++ path = os.path.join(PATH_DEBUGFS_TRACING, 'events', 'kvm') ++ fields = self.walkdir(path)[1] ++ extra = [] ++ for field in fields: ++ if field in self.filters: ++ filter_name_, filter_dicts = self.filters[field] ++ for name in filter_dicts: ++ extra.append(field + '(' + name + ')') ++ fields += extra ++ return fields ++ ++ def update_fields(self, fields_filter): ++ """Refresh fields, applying fields_filter""" ++ self._fields = [field for field in self.get_available_fields() ++ if self.is_field_wanted(fields_filter, field)] ++ ++ @staticmethod ++ def get_online_cpus(): ++ """Returns a list of cpu id integers.""" ++ def parse_int_list(list_string): ++ """Returns an int list from a string of comma separated integers and ++ integer ranges.""" ++ integers = [] ++ members = list_string.split(',') ++ ++ for member in members: ++ if '-' not in member: ++ integers.append(int(member)) ++ else: ++ int_range = member.split('-') ++ integers.extend(range(int(int_range[0]), ++ int(int_range[1]) + 1)) ++ ++ return integers ++ ++ with open('/sys/devices/system/cpu/online') as cpu_list: ++ cpu_string = cpu_list.readline() ++ return parse_int_list(cpu_string) ++ ++ def setup_traces(self): ++ """Creates all event and group objects needed to be able to retrieve ++ data.""" ++ fields = self.get_available_fields() ++ if self._pid > 0: ++ # Fetch list of all threads of the monitored pid, as qemu ++ # starts a thread for each vcpu. ++ path = os.path.join('/proc', str(self._pid), 'task') ++ groupids = self.walkdir(path)[1] ++ else: ++ groupids = self.get_online_cpus() ++ ++ # The constant is needed as a buffer for python libs, std ++ # streams and other files that the script opens. ++ newlim = len(groupids) * len(fields) + 50 ++ try: ++ softlim_, hardlim = resource.getrlimit(resource.RLIMIT_NOFILE) ++ ++ if hardlim < newlim: ++ # Now we need CAP_SYS_RESOURCE, to increase the hard limit. ++ resource.setrlimit(resource.RLIMIT_NOFILE, (newlim, newlim)) ++ else: ++ # Raising the soft limit is sufficient. ++ resource.setrlimit(resource.RLIMIT_NOFILE, (newlim, hardlim)) ++ ++ except ValueError: ++ sys.exit("NOFILE rlimit could not be raised to {0}".format(newlim)) ++ ++ for groupid in groupids: ++ group = Group() ++ for name in fields: ++ tracepoint = name ++ tracefilter = None ++ match = re.match(r'(.*)\((.*)\)', name) ++ if match: ++ tracepoint, sub = match.groups() ++ tracefilter = ('%s==%d\0' % ++ (self.filters[tracepoint][0], ++ self.filters[tracepoint][1][sub])) ++ ++ # From perf_event_open(2): ++ # pid > 0 and cpu == -1 ++ # This measures the specified process/thread on any CPU. ++ # ++ # pid == -1 and cpu >= 0 ++ # This measures all processes/threads on the specified CPU. ++ trace_cpu = groupid if self._pid == 0 else -1 ++ trace_pid = int(groupid) if self._pid != 0 else -1 ++ ++ group.add_event(Event(name=name, ++ group=group, ++ trace_cpu=trace_cpu, ++ trace_pid=trace_pid, ++ trace_point=tracepoint, ++ trace_filter=tracefilter)) ++ ++ self.group_leaders.append(group) ++ ++ @property ++ def fields(self): ++ return self._fields ++ ++ @fields.setter ++ def fields(self, fields): ++ """Enables/disables the (un)wanted events""" ++ self._fields = fields ++ for group in self.group_leaders: ++ for index, event in enumerate(group.events): ++ if event.name in fields: ++ event.reset() ++ event.enable() ++ else: ++ # Do not disable the group leader. ++ # It would disable all of its events. ++ if index != 0: ++ event.disable() ++ ++ @property ++ def pid(self): ++ return self._pid ++ ++ @pid.setter ++ def pid(self, pid): ++ """Changes the monitored pid by setting new traces.""" ++ self._pid = pid ++ # The garbage collector will get rid of all Event/Group ++ # objects and open files after removing the references. ++ self.group_leaders = [] ++ self.setup_traces() ++ self.fields = self._fields ++ ++ def read(self, by_guest=0): ++ """Returns 'event name: current value' for all enabled events.""" ++ ret = defaultdict(int) ++ for group in self.group_leaders: ++ for name, val in group.read().iteritems(): ++ if name in self._fields: ++ ret[name] += val ++ return ret ++ ++ def reset(self): ++ """Reset all field counters""" ++ for group in self.group_leaders: ++ for event in group.events: ++ event.reset() ++ ++ ++class DebugfsProvider(Provider): ++ """Provides data from the files that KVM creates in the kvm debugfs ++ folder.""" ++ def __init__(self, pid, fields_filter, include_past): ++ self.update_fields(fields_filter) ++ self._baseline = {} ++ self.do_read = True ++ self.paths = [] ++ self.pid = pid ++ if include_past: ++ self.restore() ++ ++ def get_available_fields(self): ++ """"Returns a list of available fields. ++ ++ The fields are all available KVM debugfs files ++ ++ """ ++ return self.walkdir(PATH_DEBUGFS_KVM)[2] ++ ++ def update_fields(self, fields_filter): ++ """Refresh fields, applying fields_filter""" ++ self._fields = [field for field in self.get_available_fields() ++ if self.is_field_wanted(fields_filter, field)] ++ ++ @property ++ def fields(self): ++ return self._fields ++ ++ @fields.setter ++ def fields(self, fields): ++ self._fields = fields ++ self.reset() ++ ++ @property ++ def pid(self): ++ return self._pid ++ ++ @pid.setter ++ def pid(self, pid): ++ self._pid = pid ++ if pid != 0: ++ vms = self.walkdir(PATH_DEBUGFS_KVM)[1] ++ if len(vms) == 0: ++ self.do_read = False ++ ++ self.paths = filter(lambda x: "{}-".format(pid) in x, vms) ++ ++ else: ++ self.paths = [] ++ self.do_read = True ++ self.reset() ++ ++ def read(self, reset=0, by_guest=0): ++ """Returns a dict with format:'file name / field -> current value'. ++ ++ Parameter 'reset': ++ 0 plain read ++ 1 reset field counts to 0 ++ 2 restore the original field counts ++ ++ """ ++ results = {} ++ ++ # If no debugfs filtering support is available, then don't read. ++ if not self.do_read: ++ return results ++ ++ paths = self.paths ++ if self._pid == 0: ++ paths = [] ++ for entry in os.walk(PATH_DEBUGFS_KVM): ++ for dir in entry[1]: ++ paths.append(dir) ++ for path in paths: ++ for field in self._fields: ++ value = self.read_field(field, path) ++ key = path + field ++ if reset == 1: ++ self._baseline[key] = value ++ if reset == 2: ++ self._baseline[key] = 0 ++ if self._baseline.get(key, -1) == -1: ++ self._baseline[key] = value ++ increment = (results.get(field, 0) + value - ++ self._baseline.get(key, 0)) ++ if by_guest: ++ pid = key.split('-')[0] ++ if pid in results: ++ results[pid] += increment ++ else: ++ results[pid] = increment ++ else: ++ results[field] = increment ++ ++ return results ++ ++ def read_field(self, field, path): ++ """Returns the value of a single field from a specific VM.""" ++ try: ++ return int(open(os.path.join(PATH_DEBUGFS_KVM, ++ path, ++ field)) ++ .read()) ++ except IOError: ++ return 0 ++ ++ def reset(self): ++ """Reset field counters""" ++ self._baseline = {} ++ self.read(1) ++ ++ def restore(self): ++ """Reset field counters""" ++ self._baseline = {} ++ self.read(2) ++ ++ ++class Stats(object): ++ """Manages the data providers and the data they provide. ++ ++ It is used to set filters on the provider's data and collect all ++ provider data. ++ ++ """ ++ def __init__(self, options): ++ self.providers = self.get_providers(options) ++ self._pid_filter = options.pid ++ self._fields_filter = options.fields ++ self.values = {} ++ ++ @staticmethod ++ def get_providers(options): ++ """Returns a list of data providers depending on the passed options.""" ++ providers = [] ++ ++ if options.debugfs: ++ providers.append(DebugfsProvider(options.pid, options.fields, ++ options.dbgfs_include_past)) ++ if options.tracepoints or not providers: ++ providers.append(TracepointProvider(options.pid, options.fields)) ++ ++ return providers ++ ++ def update_provider_filters(self): ++ """Propagates fields filters to providers.""" ++ # As we reset the counters when updating the fields we can ++ # also clear the cache of old values. ++ self.values = {} ++ for provider in self.providers: ++ provider.update_fields(self._fields_filter) ++ ++ def reset(self): ++ self.values = {} ++ for provider in self.providers: ++ provider.reset() ++ ++ @property ++ def fields_filter(self): ++ return self._fields_filter ++ ++ @fields_filter.setter ++ def fields_filter(self, fields_filter): ++ if fields_filter != self._fields_filter: ++ self._fields_filter = fields_filter ++ self.update_provider_filters() ++ ++ @property ++ def pid_filter(self): ++ return self._pid_filter ++ ++ @pid_filter.setter ++ def pid_filter(self, pid): ++ if pid != self._pid_filter: ++ self._pid_filter = pid ++ self.values = {} ++ for provider in self.providers: ++ provider.pid = self._pid_filter ++ ++ def get(self, by_guest=0): ++ """Returns a dict with field -> (value, delta to last value) of all ++ provider data.""" ++ for provider in self.providers: ++ new = provider.read(by_guest=by_guest) ++ for key in new if by_guest else provider.fields: ++ oldval = self.values.get(key, (0, 0))[0] ++ newval = new.get(key, 0) ++ newdelta = newval - oldval ++ self.values[key] = (newval, newdelta) ++ return self.values ++ ++ def toggle_display_guests(self, to_pid): ++ """Toggle between collection of stats by individual event and by ++ guest pid ++ ++ Events reported by DebugfsProvider change when switching to/from ++ reading by guest values. Hence we have to remove the excess event ++ names from self.values. ++ ++ """ ++ if any(isinstance(ins, TracepointProvider) for ins in self.providers): ++ return 1 ++ if to_pid: ++ for provider in self.providers: ++ if isinstance(provider, DebugfsProvider): ++ for key in provider.fields: ++ if key in self.values.keys(): ++ del self.values[key] ++ else: ++ oldvals = self.values.copy() ++ for key in oldvals: ++ if key.isdigit(): ++ del self.values[key] ++ # Update oldval (see get()) ++ self.get(to_pid) ++ return 0 ++ ++DELAY_DEFAULT = 3.0 ++MAX_GUEST_NAME_LEN = 48 ++MAX_REGEX_LEN = 44 ++DEFAULT_REGEX = r'^[^\(]*$' ++SORT_DEFAULT = 0 ++ ++ ++class Tui(object): ++ """Instruments curses to draw a nice text ui.""" ++ def __init__(self, stats): ++ self.stats = stats ++ self.screen = None ++ self._delay_initial = 0.25 ++ self._delay_regular = DELAY_DEFAULT ++ self._sorting = SORT_DEFAULT ++ self._display_guests = 0 ++ ++ def __enter__(self): ++ """Initialises curses for later use. Based on curses.wrapper ++ implementation from the Python standard library.""" ++ self.screen = curses.initscr() ++ curses.noecho() ++ curses.cbreak() ++ ++ # The try/catch works around a minor bit of ++ # over-conscientiousness in the curses module, the error ++ # return from C start_color() is ignorable. ++ try: ++ curses.start_color() ++ except curses.error: ++ pass ++ ++ # Hide cursor in extra statement as some monochrome terminals ++ # might support hiding but not colors. ++ try: ++ curses.curs_set(0) ++ except curses.error: ++ pass ++ ++ curses.use_default_colors() ++ return self ++ ++ def __exit__(self, *exception): ++ """Resets the terminal to its normal state. Based on curses.wrapper ++ implementation from the Python standard library.""" ++ if self.screen: ++ self.screen.keypad(0) ++ curses.echo() ++ curses.nocbreak() ++ curses.endwin() ++ ++ @staticmethod ++ def get_all_gnames(): ++ """Returns a list of (pid, gname) tuples of all running guests""" ++ res = [] ++ try: ++ child = subprocess.Popen(['ps', '-A', '--format', 'pid,args'], ++ stdout=subprocess.PIPE) ++ except: ++ raise Exception ++ for line in child.stdout: ++ line = line.lstrip().split(' ', 1) ++ # perform a sanity check before calling the more expensive ++ # function to possibly extract the guest name ++ if ' -name ' in line[1]: ++ res.append((line[0], Tui.get_gname_from_pid(line[0]))) ++ child.stdout.close() ++ ++ return res ++ ++ def print_all_gnames(self, row): ++ """Print a list of all running guests along with their pids.""" ++ self.screen.addstr(row, 2, '%8s %-60s' % ++ ('Pid', 'Guest Name (fuzzy list, might be ' ++ 'inaccurate!)'), ++ curses.A_UNDERLINE) ++ row += 1 ++ try: ++ for line in self.get_all_gnames(): ++ self.screen.addstr(row, 2, '%8s %-60s' % (line[0], line[1])) ++ row += 1 ++ if row >= self.screen.getmaxyx()[0]: ++ break ++ except Exception: ++ self.screen.addstr(row + 1, 2, 'Not available') ++ ++ @staticmethod ++ def get_pid_from_gname(gname): ++ """Fuzzy function to convert guest name to QEMU process pid. ++ ++ Returns a list of potential pids, can be empty if no match found. ++ Throws an exception on processing errors. ++ ++ """ ++ pids = [] ++ for line in Tui.get_all_gnames(): ++ if gname == line[1]: ++ pids.append(int(line[0])) ++ ++ return pids ++ ++ @staticmethod ++ def get_gname_from_pid(pid): ++ """Returns the guest name for a QEMU process pid. ++ ++ Extracts the guest name from the QEMU comma line by processing the ++ '-name' option. Will also handle names specified out of sequence. ++ ++ """ ++ name = '' ++ try: ++ line = open('/proc/{}/cmdline' ++ .format(pid), 'rb').read().split('\0') ++ parms = line[line.index('-name') + 1].split(',') ++ while '' in parms: ++ # commas are escaped (i.e. ',,'), hence e.g. 'foo,bar' results ++ # in # ['foo', '', 'bar'], which we revert here ++ idx = parms.index('') ++ parms[idx - 1] += ',' + parms[idx + 1] ++ del parms[idx:idx+2] ++ # the '-name' switch allows for two ways to specify the guest name, ++ # where the plain name overrides the name specified via 'guest=' ++ for arg in parms: ++ if '=' not in arg: ++ name = arg ++ break ++ if arg[:6] == 'guest=': ++ name = arg[6:] ++ except (ValueError, IOError, IndexError): ++ pass ++ ++ return name ++ ++ def update_drilldown(self): ++ """Sets or removes a filter that only allows fields without braces.""" ++ if not self.stats.fields_filter: ++ self.stats.fields_filter = DEFAULT_REGEX ++ ++ elif self.stats.fields_filter == DEFAULT_REGEX: ++ self.stats.fields_filter = None ++ ++ def update_pid(self, pid): ++ """Propagates pid selection to stats object.""" ++ self.stats.pid_filter = pid ++ ++ def refresh_header(self, pid=None): ++ """Refreshes the header.""" ++ if pid is None: ++ pid = self.stats.pid_filter ++ self.screen.erase() ++ gname = self.get_gname_from_pid(pid) ++ if gname: ++ gname = ('({})'.format(gname[:MAX_GUEST_NAME_LEN] + '...' ++ if len(gname) > MAX_GUEST_NAME_LEN ++ else gname)) ++ if pid > 0: ++ self.screen.addstr(0, 0, 'kvm statistics - pid {0} {1}' ++ .format(pid, gname), curses.A_BOLD) ++ else: ++ self.screen.addstr(0, 0, 'kvm statistics - summary', curses.A_BOLD) ++ if self.stats.fields_filter and self.stats.fields_filter \ ++ != DEFAULT_REGEX: ++ regex = self.stats.fields_filter ++ if len(regex) > MAX_REGEX_LEN: ++ regex = regex[:MAX_REGEX_LEN] + '...' ++ self.screen.addstr(1, 17, 'regex filter: {0}'.format(regex)) ++ if self._display_guests: ++ col_name = 'Guest Name' ++ else: ++ col_name = 'Event' ++ self.screen.addstr(2, 1, '%-40s %10s%7s %8s' % ++ (col_name, 'Total', '%Total', 'CurAvg/s'), ++ curses.A_STANDOUT) ++ self.screen.addstr(4, 1, 'Collecting data...') ++ self.screen.refresh() ++ ++ def refresh_body(self, sleeptime): ++ row = 3 ++ self.screen.move(row, 0) ++ self.screen.clrtobot() ++ stats = self.stats.get(self._display_guests) ++ ++ def sortCurAvg(x): ++ # sort by current events if available ++ if stats[x][1]: ++ return (-stats[x][1], -stats[x][0]) ++ else: ++ return (0, -stats[x][0]) ++ ++ def sortTotal(x): ++ # sort by totals ++ return (0, -stats[x][0]) ++ total = 0. ++ for val in stats.values(): ++ total += val[0] ++ if self._sorting == SORT_DEFAULT: ++ sortkey = sortCurAvg ++ else: ++ sortkey = sortTotal ++ for key in sorted(stats.keys(), key=sortkey): ++ ++ if row >= self.screen.getmaxyx()[0]: ++ break ++ values = stats[key] ++ if not values[0] and not values[1]: ++ break ++ if values[0] is not None: ++ cur = int(round(values[1] / sleeptime)) if values[1] else '' ++ if self._display_guests: ++ key = self.get_gname_from_pid(key) ++ self.screen.addstr(row, 1, '%-40s %10d%7.1f %8s' % ++ (key, values[0], values[0] * 100 / total, ++ cur)) ++ row += 1 ++ if row == 3: ++ self.screen.addstr(4, 1, 'No matching events reported yet') ++ self.screen.refresh() ++ ++ def show_msg(self, text): ++ """Display message centered text and exit on key press""" ++ hint = 'Press any key to continue' ++ curses.cbreak() ++ self.screen.erase() ++ (x, term_width) = self.screen.getmaxyx() ++ row = 2 ++ for line in text: ++ start = (term_width - len(line)) / 2 ++ self.screen.addstr(row, start, line) ++ row += 1 ++ self.screen.addstr(row + 1, (term_width - len(hint)) / 2, hint, ++ curses.A_STANDOUT) ++ self.screen.getkey() ++ ++ def show_help_interactive(self): ++ """Display help with list of interactive commands""" ++ msg = (' b toggle events by guests (debugfs only, honors' ++ ' filters)', ++ ' c clear filter', ++ ' f filter by regular expression', ++ ' g filter by guest name', ++ ' h display interactive commands reference', ++ ' o toggle sorting order (Total vs CurAvg/s)', ++ ' p filter by PID', ++ ' q quit', ++ ' r reset stats', ++ ' s set update interval', ++ ' x toggle reporting of stats for individual child trace' ++ ' events', ++ 'Any other key refreshes statistics immediately') ++ curses.cbreak() ++ self.screen.erase() ++ self.screen.addstr(0, 0, "Interactive commands reference", ++ curses.A_BOLD) ++ self.screen.addstr(2, 0, "Press any key to exit", curses.A_STANDOUT) ++ row = 4 ++ for line in msg: ++ self.screen.addstr(row, 0, line) ++ row += 1 ++ self.screen.getkey() ++ self.refresh_header() ++ ++ def show_filter_selection(self): ++ """Draws filter selection mask. ++ ++ Asks for a valid regex and sets the fields filter accordingly. ++ ++ """ ++ while True: ++ self.screen.erase() ++ self.screen.addstr(0, 0, ++ "Show statistics for events matching a regex.", ++ curses.A_BOLD) ++ self.screen.addstr(2, 0, ++ "Current regex: {0}" ++ .format(self.stats.fields_filter)) ++ self.screen.addstr(3, 0, "New regex: ") ++ curses.echo() ++ regex = self.screen.getstr() ++ curses.noecho() ++ if len(regex) == 0: ++ self.stats.fields_filter = DEFAULT_REGEX ++ self.refresh_header() ++ return ++ try: ++ re.compile(regex) ++ self.stats.fields_filter = regex ++ self.refresh_header() ++ return ++ except re.error: ++ continue ++ ++ def show_vm_selection_by_pid(self): ++ """Draws PID selection mask. ++ ++ Asks for a pid until a valid pid or 0 has been entered. ++ ++ """ ++ msg = '' ++ while True: ++ self.screen.erase() ++ self.screen.addstr(0, 0, ++ 'Show statistics for specific pid.', ++ curses.A_BOLD) ++ self.screen.addstr(1, 0, ++ 'This might limit the shown data to the trace ' ++ 'statistics.') ++ self.screen.addstr(5, 0, msg) ++ self.print_all_gnames(7) ++ ++ curses.echo() ++ self.screen.addstr(3, 0, "Pid [0 or pid]: ") ++ pid = self.screen.getstr() ++ curses.noecho() ++ ++ try: ++ if len(pid) > 0: ++ pid = int(pid) ++ if pid != 0 and not os.path.isdir(os.path.join('/proc/', ++ str(pid))): ++ msg = '"' + str(pid) + '": Not a running process' ++ continue ++ else: ++ pid = 0 ++ self.refresh_header(pid) ++ self.update_pid(pid) ++ break ++ except ValueError: ++ msg = '"' + str(pid) + '": Not a valid pid' ++ ++ def show_set_update_interval(self): ++ """Draws update interval selection mask.""" ++ msg = '' ++ while True: ++ self.screen.erase() ++ self.screen.addstr(0, 0, 'Set update interval (defaults to %fs).' % ++ DELAY_DEFAULT, curses.A_BOLD) ++ self.screen.addstr(4, 0, msg) ++ self.screen.addstr(2, 0, 'Change delay from %.1fs to ' % ++ self._delay_regular) ++ curses.echo() ++ val = self.screen.getstr() ++ curses.noecho() ++ ++ try: ++ if len(val) > 0: ++ delay = float(val) ++ if delay < 0.1: ++ msg = '"' + str(val) + '": Value must be >=0.1' ++ continue ++ if delay > 25.5: ++ msg = '"' + str(val) + '": Value must be <=25.5' ++ continue ++ else: ++ delay = DELAY_DEFAULT ++ self._delay_regular = delay ++ break ++ ++ except ValueError: ++ msg = '"' + str(val) + '": Invalid value' ++ self.refresh_header() ++ ++ def show_vm_selection_by_guest_name(self): ++ """Draws guest selection mask. ++ ++ Asks for a guest name until a valid guest name or '' is entered. ++ ++ """ ++ msg = '' ++ while True: ++ self.screen.erase() ++ self.screen.addstr(0, 0, ++ 'Show statistics for specific guest.', ++ curses.A_BOLD) ++ self.screen.addstr(1, 0, ++ 'This might limit the shown data to the trace ' ++ 'statistics.') ++ self.screen.addstr(5, 0, msg) ++ self.print_all_gnames(7) ++ curses.echo() ++ self.screen.addstr(3, 0, "Guest [ENTER or guest]: ") ++ gname = self.screen.getstr() ++ curses.noecho() ++ ++ if not gname: ++ self.refresh_header(0) ++ self.update_pid(0) ++ break ++ else: ++ pids = [] ++ try: ++ pids = self.get_pid_from_gname(gname) ++ except: ++ msg = '"' + gname + '": Internal error while searching, ' \ ++ 'use pid filter instead' ++ continue ++ if len(pids) == 0: ++ msg = '"' + gname + '": Not an active guest' ++ continue ++ if len(pids) > 1: ++ msg = '"' + gname + '": Multiple matches found, use pid ' \ ++ 'filter instead' ++ continue ++ self.refresh_header(pids[0]) ++ self.update_pid(pids[0]) ++ break ++ ++ def show_stats(self): ++ """Refreshes the screen and processes user input.""" ++ sleeptime = self._delay_initial ++ self.refresh_header() ++ start = 0.0 # result based on init value never appears on screen ++ while True: ++ self.refresh_body(time.time() - start) ++ curses.halfdelay(int(sleeptime * 10)) ++ start = time.time() ++ sleeptime = self._delay_regular ++ try: ++ char = self.screen.getkey() ++ if char == 'b': ++ self._display_guests = not self._display_guests ++ if self.stats.toggle_display_guests(self._display_guests): ++ self.show_msg(['Command not available with tracepoints' ++ ' enabled', 'Restart with debugfs only ' ++ '(see option \'-d\') and try again!']) ++ self._display_guests = not self._display_guests ++ self.refresh_header() ++ if char == 'c': ++ self.stats.fields_filter = DEFAULT_REGEX ++ self.refresh_header(0) ++ self.update_pid(0) ++ if char == 'f': ++ curses.curs_set(1) ++ self.show_filter_selection() ++ curses.curs_set(0) ++ sleeptime = self._delay_initial ++ if char == 'g': ++ curses.curs_set(1) ++ self.show_vm_selection_by_guest_name() ++ curses.curs_set(0) ++ sleeptime = self._delay_initial ++ if char == 'h': ++ self.show_help_interactive() ++ if char == 'o': ++ self._sorting = not self._sorting ++ if char == 'p': ++ curses.curs_set(1) ++ self.show_vm_selection_by_pid() ++ curses.curs_set(0) ++ sleeptime = self._delay_initial ++ if char == 'q': ++ break ++ if char == 'r': ++ self.stats.reset() ++ if char == 's': ++ curses.curs_set(1) ++ self.show_set_update_interval() ++ curses.curs_set(0) ++ sleeptime = self._delay_initial ++ if char == 'x': ++ self.update_drilldown() ++ # prevents display of current values on next refresh ++ self.stats.get() ++ except KeyboardInterrupt: ++ break ++ except curses.error: ++ continue ++ ++ ++def batch(stats): ++ """Prints statistics in a key, value format.""" ++ try: ++ s = stats.get() ++ time.sleep(1) ++ s = stats.get() ++ for key in sorted(s.keys()): ++ values = s[key] ++ print '%-42s%10d%10d' % (key, values[0], values[1]) ++ except KeyboardInterrupt: ++ pass ++ ++ ++def log(stats): ++ """Prints statistics as reiterating key block, multiple value blocks.""" ++ keys = sorted(stats.get().iterkeys()) ++ ++ def banner(): ++ for k in keys: ++ print '%s' % k, ++ print ++ ++ def statline(): ++ s = stats.get() ++ for k in keys: ++ print ' %9d' % s[k][1], ++ print ++ line = 0 ++ banner_repeat = 20 ++ while True: ++ try: ++ time.sleep(1) ++ if line % banner_repeat == 0: ++ banner() ++ statline() ++ line += 1 ++ except KeyboardInterrupt: ++ break ++ ++ ++def get_options(): ++ """Returns processed program arguments.""" ++ description_text = """ ++This script displays various statistics about VMs running under KVM. ++The statistics are gathered from the KVM debugfs entries and / or the ++currently available perf traces. ++ ++The monitoring takes additional cpu cycles and might affect the VM's ++performance. ++ ++Requirements: ++- Access to: ++ %s ++ %s/events/* ++ /proc/pid/task ++- /proc/sys/kernel/perf_event_paranoid < 1 if user has no ++ CAP_SYS_ADMIN and perf events are used. ++- CAP_SYS_RESOURCE if the hard limit is not high enough to allow ++ the large number of files that are possibly opened. ++ ++Interactive Commands: ++ b toggle events by guests (debugfs only, honors filters) ++ c clear filter ++ f filter by regular expression ++ g filter by guest name ++ h display interactive commands reference ++ o toggle sorting order (Total vs CurAvg/s) ++ p filter by PID ++ q quit ++ r reset stats ++ s set update interval ++ x toggle reporting of stats for individual child trace events ++Press any other key to refresh statistics immediately. ++""" % (PATH_DEBUGFS_KVM, PATH_DEBUGFS_TRACING) ++ ++ class PlainHelpFormatter(optparse.IndentedHelpFormatter): ++ def format_description(self, description): ++ if description: ++ return description + "\n" ++ else: ++ return "" ++ ++ def cb_guest_to_pid(option, opt, val, parser): ++ try: ++ pids = Tui.get_pid_from_gname(val) ++ except: ++ raise optparse.OptionValueError('Error while searching for guest ' ++ '"{}", use "-p" to specify a pid ' ++ 'instead'.format(val)) ++ if len(pids) == 0: ++ raise optparse.OptionValueError('No guest by the name "{}" ' ++ 'found'.format(val)) ++ if len(pids) > 1: ++ raise optparse.OptionValueError('Multiple processes found (pids: ' ++ '{}) - use "-p" to specify a pid ' ++ 'instead'.format(" ".join(pids))) ++ parser.values.pid = pids[0] ++ ++ optparser = optparse.OptionParser(description=description_text, ++ formatter=PlainHelpFormatter()) ++ optparser.add_option('-1', '--once', '--batch', ++ action='store_true', ++ default=False, ++ dest='once', ++ help='run in batch mode for one second', ++ ) ++ optparser.add_option('-i', '--debugfs-include-past', ++ action='store_true', ++ default=False, ++ dest='dbgfs_include_past', ++ help='include all available data on past events for ' ++ 'debugfs', ++ ) ++ optparser.add_option('-l', '--log', ++ action='store_true', ++ default=False, ++ dest='log', ++ help='run in logging mode (like vmstat)', ++ ) ++ optparser.add_option('-t', '--tracepoints', ++ action='store_true', ++ default=False, ++ dest='tracepoints', ++ help='retrieve statistics from tracepoints', ++ ) ++ optparser.add_option('-d', '--debugfs', ++ action='store_true', ++ default=False, ++ dest='debugfs', ++ help='retrieve statistics from debugfs', ++ ) ++ optparser.add_option('-f', '--fields', ++ action='store', ++ default=DEFAULT_REGEX, ++ dest='fields', ++ help='''fields to display (regex) ++ "-f help" for a list of available events''', ++ ) ++ optparser.add_option('-p', '--pid', ++ action='store', ++ default=0, ++ type='int', ++ dest='pid', ++ help='restrict statistics to pid', ++ ) ++ optparser.add_option('-g', '--guest', ++ action='callback', ++ type='string', ++ dest='pid', ++ metavar='GUEST', ++ help='restrict statistics to guest by name', ++ callback=cb_guest_to_pid, ++ ) ++ (options, _) = optparser.parse_args(sys.argv) ++ return options ++ ++ ++def check_access(options): ++ """Exits if the current user can't access all needed directories.""" ++ if not os.path.exists('/sys/kernel/debug'): ++ sys.stderr.write('Please enable CONFIG_DEBUG_FS in your kernel.') ++ sys.exit(1) ++ ++ if not os.path.exists(PATH_DEBUGFS_KVM): ++ sys.stderr.write("Please make sure, that debugfs is mounted and " ++ "readable by the current user:\n" ++ "('mount -t debugfs debugfs /sys/kernel/debug')\n" ++ "Also ensure, that the kvm modules are loaded.\n") ++ sys.exit(1) ++ ++ if not os.path.exists(PATH_DEBUGFS_TRACING) and (options.tracepoints or ++ not options.debugfs): ++ sys.stderr.write("Please enable CONFIG_TRACING in your kernel " ++ "when using the option -t (default).\n" ++ "If it is enabled, make {0} readable by the " ++ "current user.\n" ++ .format(PATH_DEBUGFS_TRACING)) ++ if options.tracepoints: ++ sys.exit(1) ++ ++ sys.stderr.write("Falling back to debugfs statistics!\n") ++ options.debugfs = True ++ time.sleep(5) ++ ++ return options ++ ++ ++def main(): ++ options = get_options() ++ options = check_access(options) ++ ++ if (options.pid > 0 and ++ not os.path.isdir(os.path.join('/proc/', ++ str(options.pid)))): ++ sys.stderr.write('Did you use a (unsupported) tid instead of a pid?\n') ++ sys.exit('Specified pid does not exist.') ++ ++ stats = Stats(options) ++ ++ if options.fields == "help": ++ event_list = "\n" ++ s = stats.get() ++ for key in s.keys(): ++ if key.find('(') != -1: ++ key = key[0:key.find('(')] ++ if event_list.find('\n' + key + '\n') == -1: ++ event_list += key + '\n' ++ sys.stdout.write(event_list) ++ return "" ++ ++ if options.log: ++ log(stats) ++ elif not options.once: ++ with Tui(stats) as tui: ++ tui.show_stats() ++ else: ++ batch(stats) ++ ++if __name__ == "__main__": ++ main() +diff --git a/scripts/kvm/kvm_stat.texi b/scripts/kvm/kvm_stat.texi +new file mode 100644 +index 0000000..5d964f6 +--- /dev/null ++++ b/scripts/kvm/kvm_stat.texi +@@ -0,0 +1,104 @@ ++@example ++@c man begin SYNOPSIS ++usage: kvm_stat [OPTION]... ++@c man end ++@end example ++ ++@c man begin DESCRIPTION ++ ++kvm_stat prints counts of KVM kernel module trace events. These events signify ++state transitions such as guest mode entry and exit. ++ ++This tool is useful for observing guest behavior from the host perspective. ++Often conclusions about performance or buggy behavior can be drawn from the ++output. ++ ++The set of KVM kernel module trace events may be specific to the kernel version ++or architecture. It is best to check the KVM kernel module source code for the ++meaning of events. ++ ++Use batch and logging modes for scripting purposes. ++ ++@section Interactive Commands ++ ++While running in regular (interactive) mode, use any of the following keys: ++ ++@table @key ++@item b ++@kindex b ++toggle events by guests (debugfs only, honors filters) ++@item c ++@kindex c ++clear filter ++@item f ++@kindex f ++filter by regular expression ++@item g ++@kindex g ++filter by guest name ++@item h ++@kindex h ++display interactive commands reference ++@item o ++@kindex o ++toggle sorting order (Total vs CurAvg/s) ++@item p ++@kindex p ++filter by PID ++@item q ++@kindex q ++quit ++@item r ++@kindex r ++reset stats ++@item s ++@kindex s ++set update interval ++@item x ++@kindex x ++toggle reporting of stats for child trace events ++@end table ++ ++Press any other key to refresh statistics immediately. ++ ++@c man end ++ ++ ++@c man begin OPTIONS ++@table @option ++@item -1, --once, --batch ++ run in batch mode for one second ++@item -l, --log ++ run in logging mode (like vmstat) ++@item -t, --tracepoints ++ retrieve statistics from tracepoints ++@item -d, --debugfs ++ retrieve statistics from debugfs ++@item -p, --pid=@var{pid} ++ limit statistics to one virtual machine (pid) ++@item -i, --debugfs-include-past ++ include all available data on past events for debugfs ++@item -g, --guest=@var{guest_name} ++ limit statistics to one virtual machine (guest name) ++@item -f, --fields=@var{fields} ++ fields to display (regex) ++@item -h, --help ++ show help message ++@end table ++ ++@c man end ++ ++@ignore ++ ++@setfilename kvm_stat ++@settitle Report KVM kernel module event counters. ++ ++@c man begin AUTHOR ++Stefan Hajnoczi ++@c man end ++ ++@c man begin SEEALSO ++perf(1), trace-cmd(1) ++@c man end ++ ++@end ignore +-- +1.8.3.1 + diff --git a/SOURCES/0006-add-qxl_screendump-monitor-command.patch b/SOURCES/0006-add-qxl_screendump-monitor-command.patch deleted file mode 100644 index e723e30..0000000 --- a/SOURCES/0006-add-qxl_screendump-monitor-command.patch +++ /dev/null @@ -1,188 +0,0 @@ -From fd2ce5e462ee97f4538981f50e9bebc222fbe157 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Tue, 14 Mar 2017 13:21:06 +0100 -Subject: add qxl_screendump monitor command - -RH-Author: Gerd Hoffmann -Message-id: <1375866764-17766-2-git-send-email-kraxel@redhat.com> -Patchwork-id: 53033 -O-Subject: [RHEL-7 qemu-kvm PATCH 1/1] add qxl_screendump monitor command -Bugzilla: 903910 -RH-Acked-by: Hans de Goede -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Michal Novotny - -This patch ports the rhel-6 specific qxl_screendump command to rhel-7. -qxl_screendump takes the device id as additional argument and thus can -be used to take screenshots from non-primary displays. - -The plan to get that functionality upstream in time failed, so we go for -plan b and carry forward the rhel-6 specific qxl_screendump command. -Thanks to the major console subsystem cleanups which made it upstream -the implementation is (a) alot less hackier than the rhel-6 one and (b) -not qxl-specific any more. Given that qxl is the only graphic device -which can work as secondary vga card the later is only a theoretical -benefit though ;) - -RHEL-6 commit: 1c6074d107dff93c7c7b0edfb5da871504802946 - -bugzilla: #903910 - RHEL7 does not have equivalent functionality for -__com.redhat_qxl_screendump - -Signed-off-by: Gerd Hoffmann -(cherry picked from commit 211321c693f46d283205830c6c49b54d7250e98c) - -Rebase notes (2.9.0): -- documentation moved to qapi schema - -Rebase notes (2.8.0): -- qmp-commands.hx replaced by docs/qmp-commands.txt (commit bd6092e) -- mhandler.cmd attribute renamed to cmd (commit 2b9e357) - -Rebase notes (2.4.0): -- replace QERR_DEVICE_NOT_FOUND with ERROR_CLASS_DEVICE_NOT_FOUND - -Merged patches (2.9.0): -- a3b59c0 HMP: Fix user manual typo of __com.redhat_qxl_screendump - -Merged patches (2.6.0): -- f12846f __com.redhat_qxl_screendump: add docs - -(cherry picked from commit 9ff701a5129653d6bd27c0b3cc249691cb6ce6a7) ---- - hmp-commands.hx | 14 ++++++++++++++ - hmp.c | 10 ++++++++++ - hmp.h | 1 + - qapi-schema.json | 22 ++++++++++++++++++++++ - ui/console.c | 24 ++++++++++++++++++++++++ - 5 files changed, 71 insertions(+) - -diff --git a/hmp-commands.hx b/hmp-commands.hx -index 2d137a1..cb00a3e 100644 ---- a/hmp-commands.hx -+++ b/hmp-commands.hx -@@ -270,6 +270,20 @@ Save screen into PPM image @var{filename}. - ETEXI - - { -+ .name = "__com.redhat_qxl_screendump", -+ .args_type = "id:s,filename:F", -+ .params = "id filename", -+ .help = "save screen from qxl device 'id' into PPM image 'filename'", -+ .cmd = hmp___com_redhat_qxl_screen_dump, -+ }, -+ -+STEXI -+@item __com.redhat_qxl_screendump @var{id} @var{filename} -+@findex __com.redhat_qxl_screendump -+Save screen from qxl device @var{id} into PPM image @var{filename}. -+ETEXI -+ -+ { - .name = "logfile", - .args_type = "filename:F", - .params = "filename", -diff --git a/hmp.c b/hmp.c -index ab985c6..5b6eeba 100644 ---- a/hmp.c -+++ b/hmp.c -@@ -2145,6 +2145,16 @@ void hmp_screendump(Monitor *mon, const QDict *qdict) - hmp_handle_error(mon, &err); - } - -+void hmp___com_redhat_qxl_screen_dump(Monitor *mon, const QDict *qdict) -+{ -+ const char *id = qdict_get_str(qdict, "id"); -+ const char *filename = qdict_get_str(qdict, "filename"); -+ Error *err = NULL; -+ -+ qmp___com_redhat_qxl_screendump(id, filename, &err); -+ hmp_handle_error(mon, &err); -+} -+ - void hmp_nbd_server_start(Monitor *mon, const QDict *qdict) - { - const char *uri = qdict_get_str(qdict, "uri"); -diff --git a/hmp.h b/hmp.h -index 1ff4552..8d9cb29 100644 ---- a/hmp.h -+++ b/hmp.h -@@ -98,6 +98,7 @@ void hmp_getfd(Monitor *mon, const QDict *qdict); - void hmp_closefd(Monitor *mon, const QDict *qdict); - void hmp_sendkey(Monitor *mon, const QDict *qdict); - void hmp_screendump(Monitor *mon, const QDict *qdict); -+void hmp___com_redhat_qxl_screen_dump(Monitor *mon, const QDict *qdict); - void hmp_nbd_server_start(Monitor *mon, const QDict *qdict); - void hmp_nbd_server_add(Monitor *mon, const QDict *qdict); - void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict); -diff --git a/qapi-schema.json b/qapi-schema.json -index 802ea53..0591d9d 100644 ---- a/qapi-schema.json -+++ b/qapi-schema.json -@@ -4968,6 +4968,28 @@ - '*logappend': 'bool' } } - - ## -+# @__com.redhat_qxl_screendump: -+# -+# Write a PPM of secondary qxl devices to a file. -+# -+# @id: qxl device id -+# @filename: the path of a new PPM file to store the image -+# -+# Returns: Nothing on success -+# -+# Since: never (rhel-only, not upstream) -+# -+# Example: -+# -+# -> { "execute": "__com.redhat_qxl_screendump", -+# "arguments": { "id": video1", "filename": "v1.ppm" } } -+# <- { "return": {} } -+# -+## -+{ 'command': '__com.redhat_qxl_screendump', 'data': { 'id' : 'str', -+ 'filename': 'str' } } -+ -+## - # @ChardevFile: - # - # Configuration info for file chardevs. -diff --git a/ui/console.c b/ui/console.c -index d2d3534..2616f9c 100644 ---- a/ui/console.c -+++ b/ui/console.c -@@ -357,6 +357,30 @@ void qmp_screendump(const char *filename, Error **errp) - ppm_save(filename, surface, errp); - } - -+void qmp___com_redhat_qxl_screendump(const char *id, const char *filename, Error **errp) -+{ -+ DeviceState *dev; -+ QemuConsole *con; -+ DisplaySurface *surface; -+ -+ dev = qdev_find_recursive(sysbus_get_default(), id); -+ if (NULL == dev) { -+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, -+ "Device '%s' not found", id); -+ return; -+ } -+ -+ con = qemu_console_lookup_by_device(dev, 0); -+ if (con == NULL) { -+ error_setg(errp, "Device %s has no QemuConsole attached to it.", id); -+ return; -+ } -+ -+ graphic_hw_update(con); -+ surface = qemu_console_surface(con); -+ ppm_save(filename, surface, errp); -+} -+ - void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata) - { - if (!con) { --- -1.8.3.1 - diff --git a/SOURCES/0007-Use-kvm-by-default.patch b/SOURCES/0007-Use-kvm-by-default.patch new file mode 100644 index 0000000..1dd0a03 --- /dev/null +++ b/SOURCES/0007-Use-kvm-by-default.patch @@ -0,0 +1,44 @@ +From 5723fea739b8f883cbd7e158292199a01b566e55 Mon Sep 17 00:00:00 2001 +From: Miroslav Rezanina +Date: Thu, 18 Dec 2014 06:27:49 +0100 +Subject: Use kvm by default + +Bugzilla: 906185 + +RHEL uses kvm accelerator by default, if available. + +Signed-off-by: Miroslav Rezanina + +Rebase notes (2.10.0) +- variable rename (upstream) + +Rebase notes (2.2.0): +- Move code from vl.c to accel.c + +(cherry picked from commit abcd662eb8e516ebe4a6b401e83a62f749491a15) +(cherry picked from commit eca6d5766d956c37e3f7f28d70903d357308c846) +(cherry picked from commit 0672656bb595f3d864b2e108a0278324ee2e7250) +(cherry picked from commit b3c79df62c3d7b1c9355dddb3c4fde285fdfc8c3) +(cherry picked from commit c303c9746b7ccfa46c4b1938ab00a29fea6ced9a) +--- + accel/accel.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/accel/accel.c b/accel/accel.c +index 93e2434..5f3d73f 100644 +--- a/accel/accel.c ++++ b/accel/accel.c +@@ -79,8 +79,8 @@ void configure_accelerator(MachineState *ms) + + accel = qemu_opt_get(qemu_get_machine_opts(), "accel"); + if (accel == NULL) { +- /* Use the default "accelerator", tcg */ +- accel = "tcg"; ++ /* RHEL uses kvm as the default accelerator, fallback to tcg */ ++ accel = "kvm:tcg"; + } + + p = accel; +-- +1.8.3.1 + diff --git a/SOURCES/0007-seabios-paravirt-allow-more-than-1TB-in-x86-guest.patch b/SOURCES/0007-seabios-paravirt-allow-more-than-1TB-in-x86-guest.patch deleted file mode 100644 index 7cbce1d..0000000 --- a/SOURCES/0007-seabios-paravirt-allow-more-than-1TB-in-x86-guest.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 5bbfbb1394759b58edd32134cd5c43871938dac8 Mon Sep 17 00:00:00 2001 -From: Andrea Arcangeli -Date: Tue, 8 Oct 2013 17:05:45 +0200 -Subject: seabios paravirt: allow more than 1TB in x86 guest - -RH-Author: Andrea Arcangeli -Message-id: <1381251945-13402-2-git-send-email-aarcange@redhat.com> -Patchwork-id: 54784 -O-Subject: [RHEL-7.0 qemu-kvm PATCH] seabios paravirt: allow more than 1TB in x86 guest -Bugzilla: 989677 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Gleb Natapov -RH-Acked-by: Laszlo Ersek - -This patch should be applied to the qemu-kvm rpm package at the same -time of the other one for seabios, so qemu will forward the ram_size -bits over 40 to seabios without losing them. - -Signed-off-by: Andrea Arcangeli -(cherry picked from commit 85123a6939a536f81470ad2e8afa5a7c72584dc0) ---- - hw/i386/pc.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/hw/i386/pc.c b/hw/i386/pc.c -index c568777..ae23fc4 100644 ---- a/hw/i386/pc.c -+++ b/hw/i386/pc.c -@@ -474,6 +474,7 @@ void pc_cmos_init(PCMachineState *pcms, - rtc_set_memory(s, 0x5b, val); - rtc_set_memory(s, 0x5c, val >> 8); - rtc_set_memory(s, 0x5d, val >> 16); -+ rtc_set_memory(s, 0x5e, val >> 24); - - object_property_add_link(OBJECT(pcms), "rtc_state", - TYPE_ISA_DEVICE, --- -1.8.3.1 - diff --git a/SOURCES/0008-add-qxl_screendump-monitor-command.patch b/SOURCES/0008-add-qxl_screendump-monitor-command.patch new file mode 100644 index 0000000..bf69df2 --- /dev/null +++ b/SOURCES/0008-add-qxl_screendump-monitor-command.patch @@ -0,0 +1,196 @@ +From 24fd80b15ac39339607e43f9dca80f645b436557 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Tue, 14 Mar 2017 13:21:06 +0100 +Subject: add qxl_screendump monitor command + +RH-Author: Gerd Hoffmann +Message-id: <1375866764-17766-2-git-send-email-kraxel@redhat.com> +Patchwork-id: 53033 +O-Subject: [RHEL-7 qemu-kvm PATCH 1/1] add qxl_screendump monitor command +Bugzilla: 903910 +RH-Acked-by: Hans de Goede +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michal Novotny + +This patch ports the rhel-6 specific qxl_screendump command to rhel-7. +qxl_screendump takes the device id as additional argument and thus can +be used to take screenshots from non-primary displays. + +The plan to get that functionality upstream in time failed, so we go for +plan b and carry forward the rhel-6 specific qxl_screendump command. +Thanks to the major console subsystem cleanups which made it upstream +the implementation is (a) alot less hackier than the rhel-6 one and (b) +not qxl-specific any more. Given that qxl is the only graphic device +which can work as secondary vga card the later is only a theoretical +benefit though ;) + +RHEL-6 commit: 1c6074d107dff93c7c7b0edfb5da871504802946 + +bugzilla: #903910 - RHEL7 does not have equivalent functionality for +__com.redhat_qxl_screendump + +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 211321c693f46d283205830c6c49b54d7250e98c) + +Rebase notes (2.12.0): +- added prototype before definition + +Rebase notes (2.9.0): +- documentation moved to qapi schema + +Rebase notes (2.8.0): +- qmp-commands.hx replaced by docs/qmp-commands.txt (commit bd6092e) +- mhandler.cmd attribute renamed to cmd (commit 2b9e357) + +Rebase notes (2.4.0): +- replace QERR_DEVICE_NOT_FOUND with ERROR_CLASS_DEVICE_NOT_FOUND + +Merged patches (2.9.0): +- a3b59c0 HMP: Fix user manual typo of __com.redhat_qxl_screendump + +Merged patches (2.6.0): +- f12846f __com.redhat_qxl_screendump: add docs + +(cherry picked from commit 9ff701a5129653d6bd27c0b3cc249691cb6ce6a7) +(cherry picked from commit fd2ce5e462ee97f4538981f50e9bebc222fbe157) +(cherry picked from commit da2738aa88ba79de34abf9ce7de88920d0089fb3) +(cherry picked from commit 61fc62e6b6f217da00376b486c8927a5586c27b8) +(cherry picked from commit 4092812ff2d7a7dc7f2f62d49fa3a568ba78781f) +--- + hmp-commands.hx | 14 ++++++++++++++ + hmp.c | 10 ++++++++++ + hmp.h | 1 + + qapi/misc.json | 22 ++++++++++++++++++++++ + ui/console.c | 25 +++++++++++++++++++++++++ + 5 files changed, 72 insertions(+) + +diff --git a/hmp-commands.hx b/hmp-commands.hx +index 3918831..01dcbb2 100644 +--- a/hmp-commands.hx ++++ b/hmp-commands.hx +@@ -272,6 +272,20 @@ Save screen into PPM image @var{filename}. + ETEXI + + { ++ .name = "__com.redhat_qxl_screendump", ++ .args_type = "id:s,filename:F", ++ .params = "id filename", ++ .help = "save screen from qxl device 'id' into PPM image 'filename'", ++ .cmd = hmp___com_redhat_qxl_screen_dump, ++ }, ++ ++STEXI ++@item __com.redhat_qxl_screendump @var{id} @var{filename} ++@findex __com.redhat_qxl_screendump ++Save screen from qxl device @var{id} into PPM image @var{filename}. ++ETEXI ++ ++ { + .name = "logfile", + .args_type = "filename:F", + .params = "filename", +diff --git a/hmp.c b/hmp.c +index 6c92198..7a53e63 100644 +--- a/hmp.c ++++ b/hmp.c +@@ -2160,6 +2160,16 @@ void hmp_screendump(Monitor *mon, const QDict *qdict) + hmp_handle_error(mon, &err); + } + ++void hmp___com_redhat_qxl_screen_dump(Monitor *mon, const QDict *qdict) ++{ ++ const char *id = qdict_get_str(qdict, "id"); ++ const char *filename = qdict_get_str(qdict, "filename"); ++ Error *err = NULL; ++ ++ qmp___com_redhat_qxl_screendump(id, filename, &err); ++ hmp_handle_error(mon, &err); ++} ++ + void hmp_nbd_server_start(Monitor *mon, const QDict *qdict) + { + const char *uri = qdict_get_str(qdict, "uri"); +diff --git a/hmp.h b/hmp.h +index 4e2ec37..f85318c 100644 +--- a/hmp.h ++++ b/hmp.h +@@ -97,6 +97,7 @@ void hmp_getfd(Monitor *mon, const QDict *qdict); + void hmp_closefd(Monitor *mon, const QDict *qdict); + void hmp_sendkey(Monitor *mon, const QDict *qdict); + void hmp_screendump(Monitor *mon, const QDict *qdict); ++void hmp___com_redhat_qxl_screen_dump(Monitor *mon, const QDict *qdict); + void hmp_nbd_server_start(Monitor *mon, const QDict *qdict); + void hmp_nbd_server_add(Monitor *mon, const QDict *qdict); + void hmp_nbd_server_remove(Monitor *mon, const QDict *qdict); +diff --git a/qapi/misc.json b/qapi/misc.json +index 5636f4a..045eb7c 100644 +--- a/qapi/misc.json ++++ b/qapi/misc.json +@@ -2445,6 +2445,28 @@ + { 'command': 'query-fdsets', 'returns': ['FdsetInfo'] } + + ## ++# @__com.redhat_qxl_screendump: ++# ++# Write a PPM of secondary qxl devices to a file. ++# ++# @id: qxl device id ++# @filename: the path of a new PPM file to store the image ++# ++# Returns: Nothing on success ++# ++# Since: never (rhel-only, not upstream) ++# ++# Example: ++# ++# -> { "execute": "__com.redhat_qxl_screendump", ++# "arguments": { "id": video1", "filename": "v1.ppm" } } ++# <- { "return": {} } ++# ++## ++{ 'command': '__com.redhat_qxl_screendump', 'data': { 'id' : 'str', ++ 'filename': 'str' } } ++ ++## + # @TargetInfo: + # + # Information describing the QEMU target. +diff --git a/ui/console.c b/ui/console.c +index 3fb2f4e..73b2d3c 100644 +--- a/ui/console.c ++++ b/ui/console.c +@@ -373,6 +373,31 @@ void qmp_screendump(const char *filename, bool has_device, const char *device, + ppm_save(filename, surface, errp); + } + ++void qmp___com_redhat_qxl_screendump(const char *id, const char *filename, Error **errp); ++void qmp___com_redhat_qxl_screendump(const char *id, const char *filename, Error **errp) ++{ ++ DeviceState *dev; ++ QemuConsole *con; ++ DisplaySurface *surface; ++ ++ dev = qdev_find_recursive(sysbus_get_default(), id); ++ if (NULL == dev) { ++ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, ++ "Device '%s' not found", id); ++ return; ++ } ++ ++ con = qemu_console_lookup_by_device(dev, 0); ++ if (con == NULL) { ++ error_setg(errp, "Device %s has no QemuConsole attached to it.", id); ++ return; ++ } ++ ++ graphic_hw_update(con); ++ surface = qemu_console_surface(con); ++ ppm_save(filename, surface, errp); ++} ++ + void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata) + { + if (!con) { +-- +1.8.3.1 + diff --git a/SOURCES/0008-monitor-Remove-usb_add-del-commands-for-Red-Hat-Ente.patch b/SOURCES/0008-monitor-Remove-usb_add-del-commands-for-Red-Hat-Ente.patch deleted file mode 100644 index 233bde0..0000000 --- a/SOURCES/0008-monitor-Remove-usb_add-del-commands-for-Red-Hat-Ente.patch +++ /dev/null @@ -1,55 +0,0 @@ -From d0bc2e633e1ec0b84e437605e974bd511241a130 Mon Sep 17 00:00:00 2001 -From: Miroslav Rezanina -Date: Wed, 6 Nov 2013 12:36:03 +0100 -Subject: monitor: Remove usb_add/del commands for Red Hat Enterprise Linux - -RH-Author: Miroslav Rezanina -Message-id: -Patchwork-id: 55520 -O-Subject: [RHEL7 qemu-kvm PATCH v2 3/4] monitor: Remove usb_add/del commands for Red Hat Enterprise Linux -Bugzilla: 1010858 -RH-Acked-by: Michal Novotny -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Orit Wasserman -RH-Acked-by: Eric Blake - -From: Miroslav Rezanina - -This is forwardport of RHEL-6 commit 754e6292b4ab41c8848171555af830ab7284f4d3: - - monitor: Remove usb_add/del commands for Red Hat Enterprise Linux - - The usb_add/del commands have been obsoleted by the device_add/del - commands. - - Signed-off-by: Amit Shah - -Signed-off-by: Miroslav Rezanina -(cherry picked from commit 23698561a70052b5d3cd376d66ec5889605e0559) ---- - hmp-commands.hx | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/hmp-commands.hx b/hmp-commands.hx -index cb00a3e..91477c5 100644 ---- a/hmp-commands.hx -+++ b/hmp-commands.hx -@@ -683,6 +683,7 @@ STEXI - Compute the checksum of a memory region. - ETEXI - -+#if 0 /* Disabled for Red Hat Enterprise Linux */ - { - .name = "usb_add", - .args_type = "devname:s", -@@ -715,6 +716,7 @@ hub. @var{devname} has the syntax @code{bus.addr}. Use the monitor - command @code{info usb} to see the devices you can remove. This - command is deprecated, please use @code{device_del} instead. - ETEXI -+#endif - - { - .name = "device_add", --- -1.8.3.1 - diff --git a/SOURCES/0009-monitor-Remove-host_net_add-remove-for-Red-Hat-Enter.patch b/SOURCES/0009-monitor-Remove-host_net_add-remove-for-Red-Hat-Enter.patch deleted file mode 100644 index 82e4c89..0000000 --- a/SOURCES/0009-monitor-Remove-host_net_add-remove-for-Red-Hat-Enter.patch +++ /dev/null @@ -1,55 +0,0 @@ -From ce335250360779414304856efa3488cb30393109 Mon Sep 17 00:00:00 2001 -From: Miroslav Rezanina -Date: Wed, 6 Nov 2013 12:36:04 +0100 -Subject: monitor: Remove host_net_add/remove for Red Hat Enterprise Linux - -RH-Author: Miroslav Rezanina -Message-id: -Patchwork-id: 55519 -O-Subject: [RHEL7 qemu-kvm PATCH v2 4/4] monitor: Remove host_net_add/remove for Red Hat Enterprise Linux -Bugzilla: 1010858 -RH-Acked-by: Michal Novotny -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Orit Wasserman -RH-Acked-by: Eric Blake - -From: Miroslav Rezanina - -This is forwardport of RHEL-6 commit dd94505bd1b826db0c7e155ccee5c24f77987f16: - - monitor: Remove host_net_add/remove for Red Hat Enterprise Linux - - The host_net_add/remove commands are replaced by netdev_add/del. Remove - them. - - Signed-off-by: Amit Shah - -Signed-off-by: Miroslav Rezanina -(cherry picked from commit c9963b7cbcc5a0148ce8c29dfa4c473b27f2fd71) ---- - hmp-commands.hx | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/hmp-commands.hx b/hmp-commands.hx -index 91477c5..3cd63be 100644 ---- a/hmp-commands.hx -+++ b/hmp-commands.hx -@@ -1338,6 +1338,7 @@ STEXI - Inject PCIe AER error - ETEXI - -+#if 0 /* Disabled for Red Hat Enterprise Linux */ - { - .name = "host_net_add", - .args_type = "device:s,opts:s?", -@@ -1367,6 +1368,7 @@ STEXI - @findex host_net_remove - Remove host VLAN client. Deprecated, please use @code{netdev_del} instead. - ETEXI -+#endif - - { - .name = "netdev_add", --- -1.8.3.1 - diff --git a/SOURCES/0009-seabios-paravirt-allow-more-than-1TB-in-x86-guest.patch b/SOURCES/0009-seabios-paravirt-allow-more-than-1TB-in-x86-guest.patch new file mode 100644 index 0000000..01bfaff --- /dev/null +++ b/SOURCES/0009-seabios-paravirt-allow-more-than-1TB-in-x86-guest.patch @@ -0,0 +1,43 @@ +From 0a103b3e40c37d33a57442ab41882e9f776ca8e7 Mon Sep 17 00:00:00 2001 +From: Andrea Arcangeli +Date: Tue, 8 Oct 2013 17:05:45 +0200 +Subject: seabios paravirt: allow more than 1TB in x86 guest + +RH-Author: Andrea Arcangeli +Message-id: <1381251945-13402-2-git-send-email-aarcange@redhat.com> +Patchwork-id: 54784 +O-Subject: [RHEL-7.0 qemu-kvm PATCH] seabios paravirt: allow more than 1TB in x86 guest +Bugzilla: 989677 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Gleb Natapov +RH-Acked-by: Laszlo Ersek + +This patch should be applied to the qemu-kvm rpm package at the same +time of the other one for seabios, so qemu will forward the ram_size +bits over 40 to seabios without losing them. + +Signed-off-by: Andrea Arcangeli +(cherry picked from commit 85123a6939a536f81470ad2e8afa5a7c72584dc0) +(cherry picked from commit 5bbfbb1394759b58edd32134cd5c43871938dac8) +(cherry picked from commit 506774310f8e4238a93dbd6be0e8d2a725b7305f) +(cherry picked from commit fa79d5440dd3e237f186963c5609f203737e68fc) +(cherry picked from commit 0d289939196d2ea236c11e3a2363f09077fa20f0) +--- + hw/i386/pc.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/i386/pc.c b/hw/i386/pc.c +index d38a328..265decf 100644 +--- a/hw/i386/pc.c ++++ b/hw/i386/pc.c +@@ -479,6 +479,7 @@ void pc_cmos_init(PCMachineState *pcms, + rtc_set_memory(s, 0x5b, val); + rtc_set_memory(s, 0x5c, val >> 8); + rtc_set_memory(s, 0x5d, val >> 16); ++ rtc_set_memory(s, 0x5e, val >> 24); + + object_property_add_link(OBJECT(pcms), "rtc_state", + TYPE_ISA_DEVICE, +-- +1.8.3.1 + diff --git a/SOURCES/0010-vfio-cap-number-of-devices-that-can-be-assigned.patch b/SOURCES/0010-vfio-cap-number-of-devices-that-can-be-assigned.patch index 53fc2c2..e0ae0ef 100644 --- a/SOURCES/0010-vfio-cap-number-of-devices-that-can-be-assigned.patch +++ b/SOURCES/0010-vfio-cap-number-of-devices-that-can-be-assigned.patch @@ -1,4 +1,4 @@ -From 3cb35556dc7d994f203d732fe952f95fcdb03c0a Mon Sep 17 00:00:00 2001 +From dcf1c9f485cefd4dad8040efb9555f33a118074b Mon Sep 17 00:00:00 2001 From: Bandan Das Date: Tue, 3 Dec 2013 20:05:13 +0100 Subject: vfio: cap number of devices that can be assigned @@ -31,15 +31,19 @@ Merged patches (2.9.0): - 17eb774 vfio: Use error_setg when reporting max assigned device overshoot (cherry picked from commit 9fa3c9fc6dfcde76d80db1aa601b2d577f72ceec) +(cherry picked from commit 3cb35556dc7d994f203d732fe952f95fcdb03c0a) +(cherry picked from commit 17e46c50515e8935c0f99a868fe07bd3c92a4586) +(cherry picked from commit 726bd82965a9e1a58065a3226597b3c2bafdbf68) +(cherry picked from commit efd8c5d78242c2e0892e165b75d2c8f1afb172a6) --- hw/vfio/pci.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c -index 31e1edf..f3f1ce6 100644 +index b9bc6cd..34b9d19 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c -@@ -34,6 +34,7 @@ +@@ -35,6 +35,7 @@ #include "qapi/error.h" #define MSIX_CAP_LENGTH 12 @@ -47,7 +51,7 @@ index 31e1edf..f3f1ce6 100644 static void vfio_disable_interrupts(VFIOPCIDevice *vdev); static void vfio_mmap_set_enabled(VFIOPCIDevice *vdev, bool enabled); -@@ -2639,7 +2640,19 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) +@@ -2807,7 +2808,19 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) ssize_t len; struct stat st; int groupid; diff --git a/SOURCES/0011-QMP-Forward-port-__com.redhat_drive_del-from-RHEL-6.patch b/SOURCES/0011-QMP-Forward-port-__com.redhat_drive_del-from-RHEL-6.patch index be47b67..2f603b1 100644 --- a/SOURCES/0011-QMP-Forward-port-__com.redhat_drive_del-from-RHEL-6.patch +++ b/SOURCES/0011-QMP-Forward-port-__com.redhat_drive_del-from-RHEL-6.patch @@ -1,4 +1,4 @@ -From 60b62c9d02e5e19e4cfa6eaeb6652339d4c4ede5 Mon Sep 17 00:00:00 2001 +From 0c3a08560e7aecb443e2f4a70d909aef413ca66f Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 14 Mar 2017 14:03:39 +0100 Subject: QMP: Forward-port __com.redhat_drive_del from RHEL-6 @@ -44,6 +44,9 @@ Rebase notes (2.4.0): - use traditional cmd for qmp - remove user_print +Merged patches (2.11.0): +- bacc223630 blockdev: Report proper error class in __com.redhat.drive_del + Merged patches (2.9.0): - 4831182 QMP: Fix forward port of __com.redhat_drive_del @@ -51,16 +54,20 @@ Merged patches (2.7.0): - 85786e0 Fix crash with __com.redhat_drive_del (cherry picked from commit b7a0cafd6494cd3855fe10934314b6b1d2df5d2d) +(cherry picked from commit 60b62c9d02e5e19e4cfa6eaeb6652339d4c4ede5) +(cherry picked from commit 9534cde84567c6e83bf925911781737b4c15b145) +(cherry picked from commit a5aa34fcd3f532e91535a4c568c66e30671120ca) +(cherry picked from commit 26bcd54a059c1949d6f1f2d72cd04794776446e1) --- - blockdev.c | 28 ++++++++++++++++------------ + blockdev.c | 29 +++++++++++++++++------------ qapi/block.json | 23 +++++++++++++++++++++++ - 2 files changed, 39 insertions(+), 12 deletions(-) + 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/blockdev.c b/blockdev.c -index 02cd69b..d5e8ee3 100644 +index c31bf3d..f65d37c 100644 --- a/blockdev.c +++ b/blockdev.c -@@ -2854,32 +2854,27 @@ BlockDirtyBitmapSha256 *qmp_x_debug_block_dirty_bitmap_sha256(const char *node, +@@ -2948,32 +2948,28 @@ BlockDirtyBitmapSha256 *qmp_x_debug_block_dirty_bitmap_sha256(const char *node, return ret; } @@ -86,7 +93,8 @@ index 02cd69b..d5e8ee3 100644 blk = blk_by_name(id); if (!blk) { - error_report("Device '%s' not found", id); -+ error_setg(errp, "Device '%s' not found", id); ++ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, ++ "Device '%s' not found", id); return; } @@ -98,7 +106,7 @@ index 02cd69b..d5e8ee3 100644 return; } -@@ -2888,8 +2883,7 @@ void hmp_drive_del(Monitor *mon, const QDict *qdict) +@@ -2982,8 +2978,7 @@ void hmp_drive_del(Monitor *mon, const QDict *qdict) bs = blk_bs(blk); if (bs) { @@ -108,7 +116,7 @@ index 02cd69b..d5e8ee3 100644 aio_context_release(aio_context); return; } -@@ -2914,6 +2908,16 @@ void hmp_drive_del(Monitor *mon, const QDict *qdict) +@@ -3008,6 +3003,16 @@ void hmp_drive_del(Monitor *mon, const QDict *qdict) aio_context_release(aio_context); } @@ -126,10 +134,10 @@ index 02cd69b..d5e8ee3 100644 bool has_node_name, const char *node_name, int64_t size, Error **errp) diff --git a/qapi/block.json b/qapi/block.json -index 414b61b..03115d3 100644 +index c694524..e1fe18e 100644 --- a/qapi/block.json +++ b/qapi/block.json -@@ -189,6 +189,29 @@ +@@ -188,6 +188,29 @@ '*force': 'bool' } } ## @@ -143,7 +151,7 @@ index 414b61b..03115d3 100644 +# errors in the guest for applications that are reading/writing to the device. +# These errors are always reported to the guest, regardless of the drive's error +# actions (drive options rerror, werror). -+# ++# +# @id: the device's ID +# +# Example: diff --git a/SOURCES/0012-QMP-Forward-port-__com.redhat_drive_add-from-RHEL-6.patch b/SOURCES/0012-QMP-Forward-port-__com.redhat_drive_add-from-RHEL-6.patch index aafbb94..3f19da3 100644 --- a/SOURCES/0012-QMP-Forward-port-__com.redhat_drive_add-from-RHEL-6.patch +++ b/SOURCES/0012-QMP-Forward-port-__com.redhat_drive_add-from-RHEL-6.patch @@ -1,4 +1,4 @@ -From 5d293a214ca093a133011d0edc9039b1e71b4219 Mon Sep 17 00:00:00 2001 +From f8f33512aefd597c9664eeb26a97cafc12d958da Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 14 Mar 2017 14:16:45 +0100 Subject: QMP: Forward-port __com.redhat_drive_add from RHEL-6 @@ -52,22 +52,29 @@ Rebase notes (2.4.0): Merged patches (2.9.0): - 599ec5f QMP: Fix forward port of __com.redhat_drive_add +Merged patches (2.12.0): +- 8679189 qmp: Report __com.redhat_drive_add error to monitor + Merged patches (2.7.0): - 20af75a QMP: Relax __com.redhat_drive_add parameter checking (cherry picked from commit 6b8c0495aa317dfc5caa6d204373140811880d1a) +(cherry picked from commit 5d293a214ca093a133011d0edc9039b1e71b4219) +(cherry picked from commit 45f0a917e663aab47217bb8b6cc5bca3a8b1baac) +(cherry picked from commit e15f0bd3c4ccce535ae9a08156aebcd780c38132) +(cherry picked from commit c7ae434601e7439371012494cd026179369af330) --- - device-hotplug.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++ + device-hotplug.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++ include/sysemu/blockdev.h | 2 ++ monitor.c | 2 ++ qapi/block.json | 45 +++++++++++++++++++++++++++++++++ - 4 files changed, 113 insertions(+) + 4 files changed, 112 insertions(+) diff --git a/device-hotplug.c b/device-hotplug.c -index 126f73c..12c17e5 100644 +index 23fd665..5575eb7 100644 --- a/device-hotplug.c +++ b/device-hotplug.c -@@ -31,6 +31,10 @@ +@@ -33,6 +33,10 @@ #include "sysemu/sysemu.h" #include "monitor/monitor.h" #include "block/block_int.h" @@ -78,7 +85,7 @@ index 126f73c..12c17e5 100644 static DriveInfo *add_init_drive(const char *optstr) { -@@ -89,3 +93,63 @@ err: +@@ -91,3 +95,62 @@ err: blk_unref(blk); } } @@ -134,8 +141,7 @@ index 126f73c..12c17e5 100644 + mc = MACHINE_GET_CLASS(current_machine); + dinfo = drive_new(opts, mc->block_default_type); + if (!dinfo) { -+ error_report(QERR_DEVICE_INIT_FAILED, -+ qemu_opts_id(opts)); ++ error_setg(errp, QERR_DEVICE_INIT_FAILED, qemu_opts_id(opts)); + qemu_opts_del(opts); + return; + } @@ -154,10 +160,10 @@ index ac22f2a..3bda14c 100644 +void simple_drive_add(QDict *qdict, QObject **ret_data, Error **errp); #endif diff --git a/monitor.c b/monitor.c -index de0a70e..76b8605 100644 +index 1813d34..c587f21 100644 --- a/monitor.c +++ b/monitor.c -@@ -1034,6 +1034,8 @@ void monitor_init_qmp_commands(void) +@@ -1204,6 +1204,8 @@ static void monitor_init_qmp_commands(void) QCO_NO_OPTIONS); qmp_register_command(&qmp_commands, "netdev_add", qmp_netdev_add, QCO_NO_OPTIONS); @@ -167,10 +173,10 @@ index de0a70e..76b8605 100644 qmp_unregister_commands_hack(); diff --git a/qapi/block.json b/qapi/block.json -index 03115d3..2083bc7 100644 +index e1fe18e..48c732f 100644 --- a/qapi/block.json +++ b/qapi/block.json -@@ -212,6 +212,51 @@ +@@ -211,6 +211,51 @@ 'data': { 'id': 'str' } } ## diff --git a/SOURCES/0013-HMP-Forward-port-__com.redhat_drive_add-from-RHEL-6.patch b/SOURCES/0013-HMP-Forward-port-__com.redhat_drive_add-from-RHEL-6.patch index 4ad3e70..47b941f 100644 --- a/SOURCES/0013-HMP-Forward-port-__com.redhat_drive_add-from-RHEL-6.patch +++ b/SOURCES/0013-HMP-Forward-port-__com.redhat_drive_add-from-RHEL-6.patch @@ -1,4 +1,4 @@ -From 365e9ae133897df34817774c93b40ecee0821cf1 Mon Sep 17 00:00:00 2001 +From 4825ef2a732c3df196b681474a5aba44622da0a6 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 14 Mar 2017 14:25:44 +0100 Subject: HMP: Forward-port __com.redhat_drive_add from RHEL-6 @@ -32,6 +32,10 @@ Merged patches (2.7.0): - a28dcc5 Fix crash bug in rebase of__com.redhat_drive_add (cherry picked from commit 913177df4933b58f50ba55ad2e1205b03b61fc54) +(cherry picked from commit 365e9ae133897df34817774c93b40ecee0821cf1) +(cherry picked from commit d1b35add1a3e78f8b3fd321f251f8c2ab098a3a4) +(cherry picked from commit d208565cba99223f730bcf7fc3598d02d1746462) +(cherry picked from commit 8fae16b0f498343c87c1dd945936857b45ba9ee8) --- blockdev.c | 14 ++++++++++++++ device-hotplug.c | 12 +++++++++++- @@ -43,10 +47,10 @@ Merged patches (2.7.0): 7 files changed, 45 insertions(+), 3 deletions(-) diff --git a/blockdev.c b/blockdev.c -index d5e8ee3..e525ebf 100644 +index f65d37c..e941b99 100644 --- a/blockdev.c +++ b/blockdev.c -@@ -4132,3 +4132,17 @@ QemuOptsList qemu_drive_opts = { +@@ -4361,3 +4361,17 @@ QemuOptsList qemu_drive_opts = { { /* end of list */ } }, }; @@ -65,10 +69,10 @@ index d5e8ee3..e525ebf 100644 + } +}; diff --git a/device-hotplug.c b/device-hotplug.c -index 12c17e5..218f7b3 100644 +index 5575eb7..cff46ee 100644 --- a/device-hotplug.c +++ b/device-hotplug.c -@@ -117,7 +117,7 @@ static void check_parm(const char *key, QObject *obj, void *opaque) +@@ -119,7 +119,7 @@ static void check_parm(const char *key, QObject *obj, void *opaque) } } @@ -77,7 +81,7 @@ index 12c17e5..218f7b3 100644 { int stopped; Error *local_err = NULL; -@@ -153,3 +153,13 @@ void simple_drive_add(QDict *qdict, QObject **ret_data, Error **errp) +@@ -154,3 +154,13 @@ void simple_drive_add(QDict *qdict, QObject **ret_data, Error **errp) return; } @@ -92,10 +96,10 @@ index 12c17e5..218f7b3 100644 + } +} diff --git a/hmp-commands.hx b/hmp-commands.hx -index 3cd63be..5b4cf6b 100644 +index 01dcbb2..399e427 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx -@@ -1315,6 +1315,20 @@ Add drive to PCI storage controller. +@@ -1295,6 +1295,20 @@ Add drive to PCI storage controller. ETEXI { @@ -130,10 +134,10 @@ index 3bda14c..c19c36a 100644 + #endif diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h -index 9caaacf..54fdc4f 100644 +index 5832c38..5d8634b 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h -@@ -199,6 +199,7 @@ extern QemuOptsList qemu_legacy_drive_opts; +@@ -200,6 +200,7 @@ extern QemuOptsList qemu_legacy_drive_opts; extern QemuOptsList qemu_common_drive_opts; extern QemuOptsList qemu_drive_opts; extern QemuOptsList bdrv_runtime_opts; @@ -142,10 +146,10 @@ index 9caaacf..54fdc4f 100644 extern QemuOptsList qemu_device_opts; extern QemuOptsList qemu_netdev_opts; diff --git a/monitor.c b/monitor.c -index 76b8605..bade261 100644 +index c587f21..4f595ae 100644 --- a/monitor.c +++ b/monitor.c -@@ -1034,7 +1034,7 @@ void monitor_init_qmp_commands(void) +@@ -1204,7 +1204,7 @@ static void monitor_init_qmp_commands(void) QCO_NO_OPTIONS); qmp_register_command(&qmp_commands, "netdev_add", qmp_netdev_add, QCO_NO_OPTIONS); @@ -155,10 +159,10 @@ index 76b8605..bade261 100644 qmp_unregister_commands_hack(); diff --git a/vl.c b/vl.c -index a64b349..253da17 100644 +index 03950fc..8dee9d0 100644 --- a/vl.c +++ b/vl.c -@@ -3054,6 +3054,7 @@ int main(int argc, char **argv, char **envp) +@@ -3078,6 +3078,7 @@ int main(int argc, char **argv, char **envp) qemu_add_drive_opts(&qemu_common_drive_opts); qemu_add_drive_opts(&qemu_drive_opts); qemu_add_drive_opts(&bdrv_runtime_opts); diff --git a/SOURCES/0014-Add-support-statement-to-help-output.patch b/SOURCES/0014-Add-support-statement-to-help-output.patch index fa43fdc..a8a8e4c 100644 --- a/SOURCES/0014-Add-support-statement-to-help-output.patch +++ b/SOURCES/0014-Add-support-statement-to-help-output.patch @@ -1,4 +1,4 @@ -From 5dd2f4706e2fef945771949e59a8fcc1b5452de9 Mon Sep 17 00:00:00 2001 +From e93d5457df2dde297089b44d185f5fe5b608d744 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Wed, 4 Dec 2013 18:53:17 +0100 Subject: Add support statement to -help output @@ -17,15 +17,19 @@ as unsupported by Red Hat, and advising users to use libvirt instead. Signed-off-by: Eduardo Habkost (cherry picked from commit 2a07700936e39856cc9f149c6a6517f0715536a6) +(cherry picked from commit 5dd2f4706e2fef945771949e59a8fcc1b5452de9) +(cherry picked from commit d660aafa98635de49f7f7a416a4e910d99b10bce) +(cherry picked from commit 6a5d4b1f602318a5b6f4e49bed90624c67848629) +(cherry picked from commit 506816e81f899d3daa6202e50ef12a21dcee7b96) --- vl.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/vl.c b/vl.c -index 253da17..ff4e7f7 100644 +index 8dee9d0..7fce42d 100644 --- a/vl.c +++ b/vl.c -@@ -1927,9 +1927,17 @@ static void version(void) +@@ -1953,9 +1953,17 @@ static void version(void) QEMU_COPYRIGHT "\n"); } @@ -43,7 +47,7 @@ index 253da17..ff4e7f7 100644 printf("usage: %s [options] [disk_image]\n\n" "'disk_image' is a raw hard disk image for IDE hard disk 0\n\n", error_get_progname()); -@@ -1946,6 +1954,7 @@ static void help(int exitcode) +@@ -1972,6 +1980,7 @@ static void help(int exitcode) "\n" QEMU_HELP_BOTTOM "\n"); diff --git a/SOURCES/0015-vl-Round-memory-sizes-below-2MiB-up-to-2MiB.patch b/SOURCES/0015-vl-Round-memory-sizes-below-2MiB-up-to-2MiB.patch index 0b4caaf..3212d85 100644 --- a/SOURCES/0015-vl-Round-memory-sizes-below-2MiB-up-to-2MiB.patch +++ b/SOURCES/0015-vl-Round-memory-sizes-below-2MiB-up-to-2MiB.patch @@ -1,4 +1,4 @@ -From 29e44e4e1f10ac7d2f9ac824b928518f3a2ccc10 Mon Sep 17 00:00:00 2001 +From dd20dff28940349e9fdca87583c8878607ef3734 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 7 Jul 2014 10:28:38 +0200 Subject: vl: Round memory sizes below 2MiB up to 2MiB @@ -25,15 +25,19 @@ Not wanted upstream. Signed-off-by: Markus Armbruster (cherry picked from commit 5c401c750c8e52fe5c67b4e60143a862a0d584c1) +(cherry picked from commit 29e44e4e1f10ac7d2f9ac824b928518f3a2ccc10) +(cherry picked from commit 07a664c4bc80f9db8fa027a654214e7f09ee81e0) +(cherry picked from commit be20ffb392aae07927923f8377bc59fb6a5707aa) +(cherry picked from commit 91707a42f802c7bd20f37959849c127d94c71f75) --- vl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/vl.c b/vl.c -index ff4e7f7..59f515c 100644 +index 7fce42d..cbd6bcc 100644 --- a/vl.c +++ b/vl.c -@@ -2906,6 +2906,7 @@ static void set_memory_options(uint64_t *ram_slots, ram_addr_t *maxram_size, +@@ -2932,6 +2932,7 @@ static void set_memory_options(uint64_t *ram_slots, ram_addr_t *maxram_size, } sz = QEMU_ALIGN_UP(sz, 8192); diff --git a/SOURCES/0016-use-recommended-max-vcpu-count.patch b/SOURCES/0016-use-recommended-max-vcpu-count.patch index 308b729..7134dcd 100644 --- a/SOURCES/0016-use-recommended-max-vcpu-count.patch +++ b/SOURCES/0016-use-recommended-max-vcpu-count.patch @@ -1,4 +1,4 @@ -From a1f26d85171b4d554225150053700e93ba6eba10 Mon Sep 17 00:00:00 2001 +From 0abcd4ae8344b523f2b462a182fddf181d2b2fa5 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 21 Jan 2014 10:46:52 +0100 Subject: use recommended max vcpu count @@ -15,28 +15,101 @@ RH-Acked-by: Marcelo Tosatti The recommended vcpu max limit (KVM_CAP_NR_VCPUS) should be used instead of the actual max vcpu limit (KVM_CAP_MAX_VCPUS) to give an error. -This matches the limit tested by QE on RHEL6: 160. +This commit matches the limit to current KVM_CAP_NR_VCPUS value. + +Rebase notes (2.11.0): +- Update commit log + +Merged patches 2.12.0: +- 6553300 redhat: globally limit the maximum number of CPUs +- 8453db7 redhat: remove manual max_cpus limitations for ppc + +Merged patches (2.11.0): +- fdeef3c1c7 RHEL: Set vcpus hard limit to 240 for Power +- 0584216921 Match POWER max cpus to x86 Signed-off-by: Andrew Jones (cherry picked from commit a4ceb63bdc5cbac19f5f633ec761b9de0dedb55e) +(cherry picked from commit a1f26d85171b4d554225150053700e93ba6eba10) +(cherry picked from commit 00b09fb8ae2fa23abfaba4e89f7daa1ba0ef9ec5) +(cherry picked from commit bd420a814a24c56d1ff1564d92f36219106ef81b) +(cherry picked from commit 79b73eacc15f2c06587734c6259b49d911327369) --- - accel/kvm/kvm-all.c | 3 +++ - 1 file changed, 3 insertions(+) + accel/kvm/kvm-all.c | 12 ++++++++++++ + vl.c | 23 +++++++++++++++++++++++ + 2 files changed, 35 insertions(+) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c -index 46ce479..b42c56a 100644 +index ffee68e..3f1c06e 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c -@@ -1627,6 +1627,9 @@ static int kvm_init(MachineState *ms) +@@ -1587,6 +1587,18 @@ static int kvm_init(MachineState *ms) soft_vcpus_limit = kvm_recommended_vcpus(s); hard_vcpus_limit = kvm_max_vcpus(s); ++#ifdef HOST_PPC64 ++ /* ++ * On POWER, the kernel advertises a soft limit based on the ++ * number of CPU threads on the host. We want to allow exceeding ++ * this for testing purposes, so we don't want to set hard limit ++ * to soft limit as on x86. ++ */ ++#else + /* RHEL doesn't support nr_vcpus > soft_vcpus_limit */ + hard_vcpus_limit = soft_vcpus_limit; ++#endif + while (nc->name) { if (nc->num > soft_vcpus_limit) { - fprintf(stderr, + warn_report("Number of %s cpus requested (%d) exceeds " +diff --git a/vl.c b/vl.c +index cbd6bcc..f3acab3 100644 +--- a/vl.c ++++ b/vl.c +@@ -135,6 +135,12 @@ int main(int argc, char **argv) + #define MAX_VIRTIO_CONSOLES 1 + #define MAX_SCLP_CONSOLES 1 + ++#if defined(CONFIG_RHV) ++#define RHEL_MAX_CPUS 384 ++#else ++#define RHEL_MAX_CPUS 240 ++#endif ++ + static const char *data_dir[16]; + static int data_dir_idx; + const char *bios_name = NULL; +@@ -1520,6 +1526,20 @@ MachineClass *find_default_machine(void) + return mc; + } + ++/* Maximum number of CPUs limited for Red Hat Enterprise Linux */ ++static void limit_max_cpus_in_machines(void) ++{ ++ GSList *el, *machines = object_class_get_list(TYPE_MACHINE, false); ++ ++ for (el = machines; el; el = el->next) { ++ MachineClass *mc = el->data; ++ ++ if (mc->max_cpus > RHEL_MAX_CPUS) { ++ mc->max_cpus = RHEL_MAX_CPUS; ++ } ++ } ++} ++ + MachineInfoList *qmp_query_machines(Error **errp) + { + GSList *el, *machines = object_class_get_list(TYPE_MACHINE, false); +@@ -4084,6 +4104,9 @@ int main(int argc, char **argv, char **envp) + + replay_configure(icount_opts); + ++ /* Maximum number of CPUs limited for Red Hat Enterprise Linux */ ++ limit_max_cpus_in_machines(); ++ + machine_class = select_machine(); + + set_memory_options(&ram_slots, &maxram_size, machine_class); -- 1.8.3.1 diff --git a/SOURCES/0017-Add-support-for-simpletrace.patch b/SOURCES/0017-Add-support-for-simpletrace.patch index 0f76550..a89736f 100644 --- a/SOURCES/0017-Add-support-for-simpletrace.patch +++ b/SOURCES/0017-Add-support-for-simpletrace.patch @@ -1,4 +1,4 @@ -From 2fcb1e48dc05cd801a85b70972b0a0e7182fb522 Mon Sep 17 00:00:00 2001 +From 7fde5fc94f5007470c1f0dc985fd0e7f1a59cfe4 Mon Sep 17 00:00:00 2001 From: Miroslav Rezanina Date: Thu, 8 Oct 2015 09:50:17 +0200 Subject: Add support for simpletrace @@ -20,6 +20,9 @@ Merged patches (2.3.0): - 85c4c8f trace: add systemtap-initscript README file to RPM (cherry picked from commit bfc1d7f3628f2ffbabbae71d57a506cea6663ddf) +(cherry picked from commit 4aca5a1b194d1beb690daf4ca9d51b9f791dbf2e) +(cherry picked from commit f09ad4d02a20aa0d3060d0ff9933b74c78b45ea1) +(cherry picked from commit 4705eac2bb8026c929bc33c87fe691eeb3c7cffc) --- .gitignore | 2 ++ Makefile | 4 +++ @@ -33,10 +36,10 @@ Merged patches (2.3.0): create mode 100644 scripts/systemtap/script.d/qemu_kvm.stp diff --git a/Makefile b/Makefile -index 2cb2442..ba31124 100644 +index 2ffac2b..bdd8223 100644 --- a/Makefile +++ b/Makefile -@@ -629,6 +629,10 @@ endif +@@ -867,6 +867,10 @@ endif $(INSTALL_DATA) $(SRC_PATH)/pc-bios/keymaps/$$x "$(DESTDIR)$(qemu_datadir)/keymaps"; \ done $(INSTALL_DATA) $(BUILD_DIR)/trace-events-all "$(DESTDIR)$(qemu_datadir)/trace-events-all" diff --git a/SOURCES/0018-Use-qemu-kvm-in-documentation-instead-of-qemu-system.patch b/SOURCES/0018-Use-qemu-kvm-in-documentation-instead-of-qemu-system.patch index e3a55d6..6888a9b 100644 --- a/SOURCES/0018-Use-qemu-kvm-in-documentation-instead-of-qemu-system.patch +++ b/SOURCES/0018-Use-qemu-kvm-in-documentation-instead-of-qemu-system.patch @@ -1,4 +1,4 @@ -From dfa2037d390047a7d7c7b13f779443bfc6c3709d Mon Sep 17 00:00:00 2001 +From 28978c6f26cf430252237c9573c2d5d61908d826 Mon Sep 17 00:00:00 2001 From: Miroslav Rezanina Date: Fri, 14 Nov 2014 08:51:50 +0100 Subject: Use qemu-kvm in documentation instead of qemu-system- @@ -17,6 +17,12 @@ to reflect this change. Only architectures available in RHEL are updated. Signed-off-by: Miroslav Rezanina +Rebase Notes (2.12.0): +- Additional fixes included + +Rebase Notes (2.11.0): +- Fixing docs/qemu-block-drivers.texi + Rebase Notes (2.10.0): - Changed patch name and updated commit message. @@ -24,49 +30,90 @@ Rebase Notes (2.9.0): - fixed chunks missed on 2.8 rebase (cherry picked from commit 1c2dac56d5e710faebe25b7aa9cac594ec0f9d4b) +(cherry picked from commit dfa2037d390047a7d7c7b13f779443bfc6c3709d) + +Conflicts: + qemu-options.hx + +(cherry picked from commit c7985367ba8258c99526549ab94ef066ae52da14) + +Conflicts: + qemu-options.hx + +(cherry picked from commit e7dc2155506c1ead844f1faef85e5f71bc2adf9e) +(cherry picked from commit 834b4c22e11c86038ec0581a86a83920569dafbd) --- - qemu-doc.texi | 110 ++++++++++++++++++++--------------------- - qemu-options.hx | 148 ++++++++++++++++++++++++++++---------------------------- - 2 files changed, 129 insertions(+), 129 deletions(-) + docs/can.txt | 10 +-- + docs/pr-manager.rst | 4 +- + docs/qemu-block-drivers.texi | 70 ++++++++++----------- + docs/replay.txt | 4 +- + docs/specs/tpm.txt | 4 +- + qemu-doc.texi | 40 ++++++------ + qemu-options.hx | 144 ++++++++++++++++++++++--------------------- + 7 files changed, 140 insertions(+), 136 deletions(-) -diff --git a/qemu-doc.texi b/qemu-doc.texi -index 9811476..da0e513 100644 ---- a/qemu-doc.texi -+++ b/qemu-doc.texi -@@ -202,12 +202,12 @@ Note that, by default, GUS shares IRQ(7) with parallel ports and so - QEMU must be told to not have parallel ports to have working GUS. - - @example --qemu-system-i386 dos.img -soundhw gus -parallel none -+qemu-kvm dos.img -soundhw gus -parallel none - @end example - - Alternatively: - @example --qemu-system-i386 dos.img -device gus,irq=5 -+qemu-kvm dos.img -device gus,irq=5 - @end example - - Or some other unclaimed IRQ. -@@ -223,7 +223,7 @@ CS4231A is the chip used in Windows Sound System and GUSMAX products - Download and uncompress the linux image (@file{linux.img}) and type: - - @example --qemu-system-i386 linux.img -+qemu-kvm linux.img - @end example - - Linux should boot and give you a prompt. -@@ -233,7 +233,7 @@ Linux should boot and give you a prompt. - - @example - @c man begin SYNOPSIS --@command{qemu-system-i386} [@var{options}] [@var{disk_image}] -+@command{qemu-kvm} [@var{options}] [@var{disk_image}] - @c man end - @end example - -@@ -891,7 +891,7 @@ QEMU can automatically create a virtual FAT disk image from a +diff --git a/docs/can.txt b/docs/can.txt +index a357105..0c0fc11 100644 +--- a/docs/can.txt ++++ b/docs/can.txt +@@ -50,9 +50,9 @@ CAN boards can be selected + The ''kvaser_pci'' board/device model is compatible with and has been tested with + ''kvaser_pci'' driver included in mainline Linux kernel. + The tested setup was Linux 4.9 kernel on the host and guest side. +-Example for qemu-system-x86_64: ++Example for qemu-kvm (intel architecture): + +- qemu-system-x86_64 -enable-kvm -kernel /boot/vmlinuz-4.9.0-4-amd64 \ ++ qemu-kvm -enable-kvm -kernel /boot/vmlinuz-4.9.0-4-amd64 \ + -initrd ramdisk.cpio \ + -virtfs local,path=shareddir,security_model=none,mount_tag=shareddir \ + -object can-bus,id=canbus0 \ +@@ -60,9 +60,9 @@ Example for qemu-system-x86_64: + -device kvaser_pci,canbus=canbus0 \ + -nographic -append "console=ttyS0" + +-Example for qemu-system-arm: ++Example for qemu-kvm (arm architecture): + +- qemu-system-arm -cpu arm1176 -m 256 -M versatilepb \ ++ qemu-kvm -cpu arm1176 -m 256 -M versatilepb \ + -kernel kernel-qemu-arm1176-versatilepb \ + -hda rpi-wheezy-overlay \ + -append "console=ttyAMA0 root=/dev/sda2 ro init=/sbin/init-overlay" \ +@@ -104,4 +104,4 @@ Links to other resources + Slides + http://rtime.felk.cvut.cz/publications/public/rtlws2015-qemu-can-slides.pdf + (5) Linux SocketCAN utilities +- https://github.com/linux-can/can-utils/ +\ No newline at end of file ++ https://github.com/linux-can/can-utils/ +diff --git a/docs/pr-manager.rst b/docs/pr-manager.rst +index 9b1de19..45cb8be 100644 +--- a/docs/pr-manager.rst ++++ b/docs/pr-manager.rst +@@ -36,7 +36,7 @@ accepts the path to the helper program's Unix socket. For example, + the following command line defines a ``pr-manager-helper`` object and + attaches it to a SCSI passthrough device:: + +- $ qemu-system-x86_64 ++ $ qemu-kvm + -device virtio-scsi \ + -object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock + -drive if=none,id=hd,driver=raw,file.filename=/dev/sdb,file.pr-manager=helper0 +@@ -44,7 +44,7 @@ attaches it to a SCSI passthrough device:: + + Alternatively, using ``-blockdev``:: + +- $ qemu-system-x86_64 ++ $ qemu-kvm + -device virtio-scsi \ + -object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock + -blockdev node-name=hd,driver=raw,file.driver=host_device,file.filename=/dev/sdb,file.pr-manager=helper0 +diff --git a/docs/qemu-block-drivers.texi b/docs/qemu-block-drivers.texi +index f179369..e0d752a 100644 +--- a/docs/qemu-block-drivers.texi ++++ b/docs/qemu-block-drivers.texi +@@ -405,7 +405,7 @@ QEMU can automatically create a virtual FAT disk image from a directory tree. In order to use it, just type: @example @@ -75,7 +122,7 @@ index 9811476..da0e513 100644 @end example Then you access access to all the files in the @file{/my_directory} -@@ -901,14 +901,14 @@ them via SAMBA or NFS. The default access is @emph{read-only}. +@@ -415,14 +415,14 @@ them via SAMBA or NFS. The default access is @emph{read-only}. Floppies can be emulated with the @code{:floppy:} option: @example @@ -92,7 +139,7 @@ index 9811476..da0e513 100644 @end example What you should @emph{never} do: -@@ -926,14 +926,14 @@ QEMU can access directly to block device exported using the Network Block Device +@@ -440,14 +440,14 @@ QEMU can access directly to block device exported using the Network Block Device protocol. @example @@ -109,7 +156,7 @@ index 9811476..da0e513 100644 @end example In this case, the block device must be exported using qemu-nbd: -@@ -950,23 +950,23 @@ qemu-nbd --socket=/tmp/my_socket --share=2 my_disk.qcow2 +@@ -464,23 +464,23 @@ qemu-nbd --socket=/tmp/my_socket --share=2 my_disk.qcow2 @noindent and then you can use it with two guests: @example @@ -140,7 +187,7 @@ index 9811476..da0e513 100644 @end example @node disk_images_sheepdog -@@ -991,7 +991,7 @@ qemu-img convert @var{filename} sheepdog:///@var{image} +@@ -505,7 +505,7 @@ qemu-img convert @var{filename} sheepdog:///@var{image} You can boot from the Sheepdog disk image with the command: @example @@ -149,7 +196,7 @@ index 9811476..da0e513 100644 @end example You can also create a snapshot of the Sheepdog image like qcow2. -@@ -1003,7 +1003,7 @@ where @var{tag} is a tag name of the newly created snapshot. +@@ -517,7 +517,7 @@ where @var{tag} is a tag name of the newly created snapshot. To boot from the Sheepdog snapshot, specify the tag name of the snapshot. @example @@ -158,7 +205,7 @@ index 9811476..da0e513 100644 @end example You can create a cloned image from the existing snapshot. -@@ -1016,14 +1016,14 @@ is its tag name. +@@ -530,14 +530,14 @@ is its tag name. You can use an unix socket instead of an inet socket: @example @@ -175,16 +222,7 @@ index 9811476..da0e513 100644 @end example @node disk_images_iscsi -@@ -1065,7 +1065,7 @@ Various session related parameters can be set via special options, either - in a configuration file provided via '-readconfig' or directly on the - command line. - --If the initiator-name is not specified qemu will use a default name -+If the initiator-name is not specified qemu-kvm will use a default name - of 'iqn.2008-11.org.linux-kvm[:'] where is the name of the - virtual machine. - -@@ -1112,7 +1112,7 @@ cat >iscsi.conf <iscsi.conf < /sys/bus/pci/devices/0000:06:0d.0/driver/unbind + # echo 1102 0002 > /sys/bus/pci/drivers/vfio-pci/new_id + +-# qemu-system-x86_64 -drive file=nvme://@var{host}:@var{bus}:@var{slot}.@var{func}/@var{namespace} ++# qemu-kvm -drive file=nvme://@var{host}:@var{bus}:@var{slot}.@var{func}/@var{namespace} + @end example + + Alternative syntax using properties: + + @example +-qemu-system-x86_64 -drive file.driver=nvme,file.device=@var{host}:@var{bus}:@var{slot}.@var{func},file.namespace=@var{namespace} ++qemu-kvm -drive file.driver=nvme,file.device=@var{host}:@var{bus}:@var{slot}.@var{func},file.namespace=@var{namespace} + @end example + + @var{host}:@var{bus}:@var{slot}.@var{func} is the NVMe controller's PCI device +diff --git a/docs/replay.txt b/docs/replay.txt +index 2e21e9c..f1923e8 100644 +--- a/docs/replay.txt ++++ b/docs/replay.txt +@@ -25,7 +25,7 @@ Deterministic replay has the following features: + + Usage of the record/replay: + * First, record the execution with the following command line: +- qemu-system-i386 \ ++ qemu-kvm \ + -icount shift=7,rr=record,rrfile=replay.bin \ + -drive file=disk.qcow2,if=none,id=img-direct \ + -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay \ +@@ -33,7 +33,7 @@ Usage of the record/replay: + -netdev user,id=net1 -device rtl8139,netdev=net1 \ + -object filter-replay,id=replay,netdev=net1 + * After recording, you can replay it by using another command line: +- qemu-system-i386 \ ++ qemu-kvm \ + -icount shift=7,rr=replay,rrfile=replay.bin \ + -drive file=disk.qcow2,if=none,id=img-direct \ + -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay \ +diff --git a/docs/specs/tpm.txt b/docs/specs/tpm.txt +index d1d7157..897c300 100644 +--- a/docs/specs/tpm.txt ++++ b/docs/specs/tpm.txt +@@ -98,7 +98,7 @@ QEMU files related to the TPM passthrough device: + Command line to start QEMU with the TPM passthrough device using the host's + hardware TPM /dev/tpm0: + +-qemu-system-x86_64 -display sdl -enable-kvm \ ++qemu-kvm -display vnc -enable-kvm \ + -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ + -tpmdev passthrough,id=tpm0,path=/dev/tpm0 \ + -device tpm-tis,tpmdev=tpm0 test.img +@@ -164,7 +164,7 @@ swtpm socket --tpmstate dir=/tmp/mytpm1 \ + Command line to start QEMU with the TPM emulator device communicating with + the swtpm: + +-qemu-system-x86_64 -display sdl -enable-kvm \ ++qemu-kvm -display sdl -enable-kvm \ + -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ + -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ + -tpmdev emulator,id=tpm0,chardev=chrtpm \ +diff --git a/qemu-doc.texi b/qemu-doc.texi +index 5813d27..de5097a 100644 +--- a/qemu-doc.texi ++++ b/qemu-doc.texi +@@ -203,12 +203,12 @@ Note that, by default, GUS shares IRQ(7) with parallel ports and so + QEMU must be told to not have parallel ports to have working GUS. + + @example +-qemu-system-i386 dos.img -soundhw gus -parallel none ++qemu-kvm dos.img -soundhw gus -parallel none + @end example + + Alternatively: + @example +-qemu-system-i386 dos.img -device gus,irq=5 ++qemu-kvm dos.img -device gus,irq=5 + @end example + + Or some other unclaimed IRQ. +@@ -224,7 +224,7 @@ CS4231A is the chip used in Windows Sound System and GUSMAX products + Download and uncompress the linux image (@file{linux.img}) and type: + + @example +-qemu-system-i386 linux.img ++qemu-kvm linux.img + @end example + + Linux should boot and give you a prompt. +@@ -234,7 +234,7 @@ Linux should boot and give you a prompt. + + @example + @c man begin SYNOPSIS +-@command{qemu-system-i386} [@var{options}] [@var{disk_image}] ++@command{qemu-kvm} [@var{options}] [@var{disk_image}] + @c man end + @end example + +@@ -813,7 +813,7 @@ On Linux hosts, a shared memory device is available. The basic syntax is: @example @@ -275,7 +410,7 @@ index 9811476..da0e513 100644 @end example where @var{hostmem} names a host memory backend. For a POSIX shared -@@ -1393,7 +1393,7 @@ memory server is: +@@ -834,7 +834,7 @@ memory server is: ivshmem-server -p @var{pidfile} -S @var{path} -m @var{shm-name} -l @var{shm-size} -n @var{vectors} # Then start your qemu instances with matching arguments @@ -284,7 +419,7 @@ index 9811476..da0e513 100644 -chardev socket,path=@var{path},id=@var{id} @end example -@@ -1418,7 +1418,7 @@ Instead of specifying the using POSIX shm, you may specify +@@ -859,7 +859,7 @@ Instead of specifying the using POSIX shm, you may specify a memory backend that has hugepage support: @example @@ -293,7 +428,7 @@ index 9811476..da0e513 100644 -device ivshmem-plain,memdev=mb1 @end example -@@ -1434,7 +1434,7 @@ kernel testing. +@@ -875,7 +875,7 @@ kernel testing. The syntax is: @example @@ -302,7 +437,7 @@ index 9811476..da0e513 100644 @end example Use @option{-kernel} to provide the Linux kernel image and -@@ -1449,7 +1449,7 @@ If you do not need graphical output, you can disable it and redirect +@@ -890,7 +890,7 @@ If you do not need graphical output, you can disable it and redirect the virtual serial port and the QEMU monitor to the console with the @option{-nographic} option. The typical command line is: @example @@ -311,7 +446,7 @@ index 9811476..da0e513 100644 -append "root=/dev/hda console=ttyS0" -nographic @end example -@@ -1515,7 +1515,7 @@ Network adapter that supports CDC ethernet and RNDIS protocols. @var{id} +@@ -956,7 +956,7 @@ Network adapter that supports CDC ethernet and RNDIS protocols. @var{id} specifies a netdev defined with @code{-netdev @dots{},id=@var{id}}. For instance, user-mode networking can be used with @example @@ -320,7 +455,7 @@ index 9811476..da0e513 100644 @end example @item usb-ccid Smartcard reader device -@@ -1534,7 +1534,7 @@ no type is given, the HCI logic corresponds to @code{-bt hci,vlan=0}. +@@ -975,7 +975,7 @@ no type is given, the HCI logic corresponds to @code{-bt hci,vlan=0}. This USB device implements the USB Transport Layer of HCI. Example usage: @example @@ -329,7 +464,7 @@ index 9811476..da0e513 100644 @end example @end table -@@ -1612,7 +1612,7 @@ For this setup it is recommended to restrict it to listen on a UNIX domain +@@ -1052,7 +1052,7 @@ For this setup it is recommended to restrict it to listen on a UNIX domain socket only. For example @example @@ -338,7 +473,7 @@ index 9811476..da0e513 100644 @end example This ensures that only users on local box with read/write access to that -@@ -1635,7 +1635,7 @@ is running the password is set with the monitor. Until the monitor is used to +@@ -1075,7 +1075,7 @@ is running the password is set with the monitor. Until the monitor is used to set the password all clients will be rejected. @example @@ -347,7 +482,7 @@ index 9811476..da0e513 100644 (qemu) change vnc password Password: ******** (qemu) -@@ -1652,7 +1652,7 @@ support provides a secure session, but no authentication. This allows any +@@ -1092,7 +1092,7 @@ support provides a secure session, but no authentication. This allows any client to connect, and provides an encrypted session. @example @@ -356,7 +491,7 @@ index 9811476..da0e513 100644 @end example In the above example @code{/etc/pki/qemu} should contain at least three files, -@@ -1670,7 +1670,7 @@ then validate against the CA certificate. This is a good choice if deploying +@@ -1110,7 +1110,7 @@ then validate against the CA certificate. This is a good choice if deploying in an environment with a private internal certificate authority. @example @@ -365,7 +500,7 @@ index 9811476..da0e513 100644 @end example -@@ -1681,7 +1681,7 @@ Finally, the previous method can be combined with VNC password authentication +@@ -1121,7 +1121,7 @@ Finally, the previous method can be combined with VNC password authentication to provide two layers of authentication for clients. @example @@ -374,7 +509,7 @@ index 9811476..da0e513 100644 (qemu) change vnc password Password: ******** (qemu) -@@ -1704,7 +1704,7 @@ used for authentication, but assuming use of one supporting SSF, +@@ -1144,7 +1144,7 @@ used for authentication, but assuming use of one supporting SSF, then QEMU can be launched with: @example @@ -383,7 +518,7 @@ index 9811476..da0e513 100644 @end example @node vnc_sec_certificate_sasl -@@ -1718,7 +1718,7 @@ credentials. This can be enabled, by combining the 'sasl' option +@@ -1158,7 +1158,7 @@ credentials. This can be enabled, by combining the 'sasl' option with the aforementioned TLS + x509 options: @example @@ -391,8 +526,8 @@ index 9811476..da0e513 100644 +qemu-kvm [...OPTIONS...] -vnc :1,tls,x509,sasl -monitor stdio @end example - -@@ -1894,7 +1894,7 @@ QEMU has a primitive support to work with gdb, so that you can do + @node vnc_setup_sasl +@@ -1514,7 +1514,7 @@ QEMU has a primitive support to work with gdb, so that you can do In order to use gdb, launch QEMU with the '-s' option. It will wait for a gdb connection: @example @@ -401,16 +536,7 @@ index 9811476..da0e513 100644 -append "root=/dev/hda" Connected to host network interface: tun0 Waiting gdb connection on port 1234 -@@ -2076,7 +2076,7 @@ differences are mentioned in the following sections. - @section PowerPC System emulator - @cindex system emulation (PowerPC) - --Use the executable @file{qemu-system-ppc} to simulate a complete PREP -+Use the executable @file{qemu-kvm} to simulate a complete PREP - or PowerMac PowerPC system. - - QEMU emulates the following PowerMac peripherals: -@@ -2140,7 +2140,7 @@ Set the initial VGA graphic mode. The default is 800x600x32. +@@ -1760,7 +1760,7 @@ Set the initial VGA graphic mode. The default is 800x600x32. Set OpenBIOS variables in NVRAM, for example: @example @@ -420,10 +546,10 @@ index 9811476..da0e513 100644 -prom-env 'boot-args=conf=hd:2,\yaboot.conf' @end example diff --git a/qemu-options.hx b/qemu-options.hx -index 568fc7c..5220120 100644 +index 2042dba..43f10b1 100644 --- a/qemu-options.hx +++ b/qemu-options.hx -@@ -252,7 +252,7 @@ This option defines a free-form string that can be used to describe @var{fd}. +@@ -263,7 +263,7 @@ This option defines a free-form string that can be used to describe @var{fd}. You can open an image using pre-opened file descriptors from an fd set: @example @@ -432,7 +558,7 @@ index 568fc7c..5220120 100644 -add-fd fd=3,set=2,opaque="rdwr:/path/to/file" -add-fd fd=4,set=2,opaque="rdonly:/path/to/file" -drive file=/dev/fdset/2,index=0,media=disk -@@ -281,7 +281,7 @@ STEXI +@@ -292,7 +292,7 @@ STEXI Set default value of @var{driver}'s property @var{prop} to @var{value}, e.g.: @example @@ -440,17 +566,8 @@ index 568fc7c..5220120 100644 +qemu-kvm -global ide-hd.physical_block_size=4096 disk-image.img @end example - In particular, you can use this to set driver properties for devices which are -@@ -326,7 +326,7 @@ the recommended is 320x240, 640x480, 800x640. - - A timeout could be passed to bios, guest will pause for @var{rb_timeout} ms - when boot failed, then reboot. If @var{rb_timeout} is '-1', guest will not --reboot, qemu passes '-1' to bios by default. Currently Seabios for X86 -+reboot, qemu-kvm passes '-1' to bios by default. Currently Seabios for X86 - system support it. - - Do strict boot via @option{strict=on} as far as firmware/BIOS -@@ -335,11 +335,11 @@ bootindex options. The default is non-strict boot. + In particular, you can use this to set driver properties for devices which are +@@ -346,11 +346,11 @@ bootindex options. The default is non-strict boot. @example # try to boot from network first, then from hard disk @@ -465,7 +582,7 @@ index 568fc7c..5220120 100644 @end example Note: The legacy format '-boot @var{drives}' is still supported but its -@@ -368,7 +368,7 @@ For example, the following command-line sets the guest startup RAM size to +@@ -379,7 +379,7 @@ For example, the following command-line sets the guest startup RAM size to memory the guest can reach to 4GB: @example @@ -474,7 +591,7 @@ index 568fc7c..5220120 100644 @end example If @var{slots} and @var{maxmem} are not specified, memory hotplug won't -@@ -437,12 +437,12 @@ Enable audio and selected sound hardware. Use 'help' to print all +@@ -448,12 +448,12 @@ Enable audio and selected sound hardware. Use 'help' to print all available sound hardware. @example @@ -493,7 +610,7 @@ index 568fc7c..5220120 100644 @end example Note that Linux's i810_audio OSS kernel (for AC97) module might -@@ -934,21 +934,21 @@ is off. +@@ -946,21 +946,21 @@ is off. Instead of @option{-cdrom} you can use: @example @@ -521,7 +638,7 @@ index 568fc7c..5220120 100644 -add-fd fd=3,set=2,opaque="rdwr:/path/to/file" -add-fd fd=4,set=2,opaque="rdonly:/path/to/file" -drive file=/dev/fdset/2,index=0,media=disk -@@ -956,28 +956,28 @@ qemu-system-i386 +@@ -968,28 +968,28 @@ qemu-system-i386 You can connect a CDROM to the slave of ide0: @example @@ -556,66 +673,77 @@ index 568fc7c..5220120 100644 @end example ETEXI -@@ -2115,7 +2115,7 @@ can not be resolved. +@@ -2056,8 +2056,8 @@ The following two example do exactly the same, to show how @option{-nic} can + be used to shorten the command line length (note that the e1000 is the default + on i386, so the @option{model=e1000} parameter could even be omitted here, too): + @example +-qemu-system-i386 -netdev user,id=n1,ipv6=off -device e1000,netdev=n1,mac=52:54:98:76:54:32 +-qemu-system-i386 -nic user,ipv6=off,model=e1000,mac=52:54:98:76:54:32 ++qemu-kvm -netdev user,id=n1,ipv6=off -device e1000,netdev=n1,mac=52:54:98:76:54:32 ++qemu-kvm -nic user,ipv6=off,model=e1000,mac=52:54:98:76:54:32 + @end example + + @item -nic none +@@ -2128,7 +2128,7 @@ can not be resolved. Example: @example --qemu -net user,dnssearch=mgmt.example.org,dnssearch=example.org [...] -+qemu-kvm -net user,dnssearch=mgmt.example.org,dnssearch=example.org [...] +-qemu-system-i386 -nic user,dnssearch=mgmt.example.org,dnssearch=example.org ++qemu-kvm -nic user,dnssearch=mgmt.example.org,dnssearch=example.org @end example @item tftp=@var{dir} -@@ -2131,7 +2131,7 @@ a guest from a local directory. +@@ -2144,7 +2144,7 @@ a guest from a local directory. Example (using pxelinux): @example --qemu-system-i386 -hda linux.img -boot n -net user,tftp=/path/to/tftp/files,bootfile=/pxelinux.0 -+qemu-kvm -hda linux.img -boot n -net user,tftp=/path/to/tftp/files,bootfile=/pxelinux.0 +-qemu-system-i386 -hda linux.img -boot n -device e1000,netdev=n1 \ ++qemu-kvm -hda linux.img -boot n -device e1000,netdev=n1 \ + -netdev user,id=n1,tftp=/path/to/tftp/files,bootfile=/pxelinux.0 @end example - @item smb=@var{dir}[,smbserver=@var{addr}] -@@ -2166,7 +2166,7 @@ screen 0, use the following: +@@ -2178,7 +2178,7 @@ screen 0, use the following: @example # on the host --qemu-system-i386 -net user,hostfwd=tcp:127.0.0.1:6001-:6000 [...] -+qemu-kvm -net user,hostfwd=tcp:127.0.0.1:6001-:6000 [...] +-qemu-system-i386 -nic user,hostfwd=tcp:127.0.0.1:6001-:6000 ++qemu-kvm -nic user,hostfwd=tcp:127.0.0.1:6001-:6000 # this host xterm should open in the guest X11 server xterm -display :1 @end example -@@ -2176,7 +2176,7 @@ the guest, use the following: +@@ -2188,7 +2188,7 @@ the guest, use the following: @example # on the host --qemu-system-i386 -net user,hostfwd=tcp::5555-:23 [...] -+qemu-kvm -net user,hostfwd=tcp::5555-:23 [...] +-qemu-system-i386 -nic user,hostfwd=tcp::5555-:23 ++qemu-kvm -nic user,hostfwd=tcp::5555-:23 telnet localhost 5555 @end example -@@ -2195,7 +2195,7 @@ lifetime, like in the following example: +@@ -2207,7 +2207,7 @@ lifetime, like in the following example: @example # open 10.10.1.1:4321 on bootup, connect 10.0.2.100:1234 to it whenever # the guest accesses it --qemu -net user,guestfwd=tcp:10.0.2.100:1234-tcp:10.10.1.1:4321 [...] -+qemu-kvm -net user,guestfwd=tcp:10.0.2.100:1234-tcp:10.10.1.1:4321 [...] +-qemu-system-i386 -nic user,guestfwd=tcp:10.0.2.100:1234-tcp:10.10.1.1:4321 ++qemu-kvm -nic user,guestfwd=tcp:10.0.2.100:1234-tcp:10.10.1.1:4321 @end example Or you can execute a command on every TCP connection established by the guest, -@@ -2204,7 +2204,7 @@ so that QEMU behaves similar to an inetd process for that virtual server: +@@ -2216,7 +2216,7 @@ so that QEMU behaves similar to an inetd process for that virtual server: @example # call "netcat 10.10.1.1 4321" on every TCP connection to 10.0.2.100:1234 # and connect the TCP stream to its stdin/stdout --qemu -net 'user,guestfwd=tcp:10.0.2.100:1234-cmd:netcat 10.10.1.1 4321' -+qemu-kvm -net 'user,guestfwd=tcp:10.0.2.100:1234-cmd:netcat 10.10.1.1 4321' +-qemu-system-i386 -nic 'user,id=n1,guestfwd=tcp:10.0.2.100:1234-cmd:netcat 10.10.1.1 4321' ++qemu-kvm -nic 'user,id=n1,guestfwd=tcp:10.0.2.100:1234-cmd:netcat 10.10.1.1 4321' @end example @end table -@@ -2237,13 +2237,13 @@ Examples: +@@ -2248,21 +2248,22 @@ Examples: @example #launch a QEMU instance with the default network script --qemu-system-i386 linux.img -net nic -net tap -+qemu-kvm linux.img -net nic -net tap +-qemu-system-i386 linux.img -nic tap ++qemu-kvm linux.img -nic tap @end example @example @@ -623,105 +751,124 @@ index 568fc7c..5220120 100644 #to a TAP device -qemu-system-i386 linux.img \ +qemu-kvm linux.img \ - -net nic,vlan=0 -net tap,vlan=0,ifname=tap0 \ - -net nic,vlan=1 -net tap,vlan=1,ifname=tap1 + -netdev tap,id=nd0,ifname=tap0 -device e1000,netdev=nd0 \ + -netdev tap,id=nd1,ifname=tap1 -device rtl8139,netdev=nd1 ++ -net nic,vlan=1 -net tap,vlan=1,ifname=tap1 @end example -@@ -2251,7 +2251,7 @@ qemu-system-i386 linux.img \ + @example #launch a QEMU instance with the default network helper to #connect a TAP device to bridge br0 --qemu-system-i386 linux.img \ -+qemu-kvm linux.img \ - -net nic -net tap,"helper=/path/to/qemu-bridge-helper" +-qemu-system-i386 linux.img -device virtio-net-pci,netdev=n1 \ ++qemu-kvm linux.img -device virtio-net-pci,netdev=n1 \ + -netdev tap,id=n1,"helper=/path/to/qemu-bridge-helper" @end example -@@ -2269,13 +2269,13 @@ Examples: +@@ -2279,13 +2280,13 @@ Examples: @example #launch a QEMU instance with the default network helper to #connect a TAP device to bridge br0 --qemu-system-i386 linux.img -net bridge -net nic,model=virtio -+qemu-kvm linux.img -net bridge -net nic,model=virtio +-qemu-system-i386 linux.img -netdev bridge,id=n1 -device virtio-net,netdev=n1 ++qemu-kvm linux.img -netdev bridge,id=n1 -device virtio-net,netdev=n1 @end example @example #launch a QEMU instance with the default network helper to #connect a TAP device to bridge qemubr0 --qemu-system-i386 linux.img -net bridge,br=qemubr0 -net nic,model=virtio -+qemu-kvm linux.img -net bridge,br=qemubr0 -net nic,model=virtio +-qemu-system-i386 linux.img -netdev bridge,br=qemubr0,id=n1 -device virtio-net,netdev=n1 ++qemu-kvm linux.img -netdev bridge,br=qemubr0,id=n1 -device virtio-net,netdev=n1 @end example @item -netdev socket,id=@var{id}[,fd=@var{h}][,listen=[@var{host}]:@var{port}][,connect=@var{host}:@var{port}] -@@ -2291,12 +2291,12 @@ specifies an already opened TCP socket. +@@ -2300,13 +2301,13 @@ specifies an already opened TCP socket. Example: @example # launch a first QEMU instance -qemu-system-i386 linux.img \ +- -device e1000,netdev=n1,mac=52:54:00:12:34:56 \ +- -netdev socket,id=n1,listen=:1234 +qemu-kvm linux.img \ - -net nic,macaddr=52:54:00:12:34:56 \ - -net socket,listen=:1234 - # connect the VLAN 0 of this instance to the VLAN 0 - # of the first instance ++ -device e1000,netdev=n1,mac=52:54:00:12:34:56 \ ++ -netdev socket,id=n1,listen=:1234 + # connect the network of this instance to the network of the first instance -qemu-system-i386 linux.img \ +- -device e1000,netdev=n2,mac=52:54:00:12:34:57 \ +- -netdev socket,id=n2,connect=127.0.0.1:1234 +qemu-kvm linux.img \ - -net nic,macaddr=52:54:00:12:34:57 \ - -net socket,connect=127.0.0.1:1234 ++ -device e1000,netdev=n2,mac=52:54:00:12:34:57 \ ++ -netdev socket,id=n2,connect=127.0.0.1:1234 @end example -@@ -2322,15 +2322,15 @@ Use @option{fd=h} to specify an already opened UDP multicast socket. + + @item -netdev socket,id=@var{id}[,fd=@var{h}][,mcast=@var{maddr}:@var{port}[,localaddr=@var{addr}]] +@@ -2329,23 +2330,23 @@ Use @option{fd=h} to specify an already opened UDP multicast socket. Example: @example # launch one QEMU instance -qemu-system-i386 linux.img \ +- -device e1000,netdev=n1,mac=52:54:00:12:34:56 \ +- -netdev socket,id=n1,mcast=230.0.0.1:1234 +qemu-kvm linux.img \ - -net nic,macaddr=52:54:00:12:34:56 \ - -net socket,mcast=230.0.0.1:1234 ++ -device e1000,netdev=n1,mac=52:54:00:12:34:56 \ ++ -netdev socket,id=n1,mcast=230.0.0.1:1234 # launch another QEMU instance on same "bus" -qemu-system-i386 linux.img \ +- -device e1000,netdev=n2,mac=52:54:00:12:34:57 \ +- -netdev socket,id=n2,mcast=230.0.0.1:1234 +qemu-kvm linux.img \ - -net nic,macaddr=52:54:00:12:34:57 \ - -net socket,mcast=230.0.0.1:1234 ++ -device e1000,netdev=n2,mac=52:54:00:12:34:57 \ ++ -netdev socket,id=n2,mcast=230.0.0.1:1234 # launch yet another QEMU instance on same "bus" -qemu-system-i386 linux.img \ +- -device e1000,netdev=n3,macaddr=52:54:00:12:34:58 \ +- -netdev socket,id=n3,mcast=230.0.0.1:1234 +qemu-kvm linux.img \ - -net nic,macaddr=52:54:00:12:34:58 \ - -net socket,mcast=230.0.0.1:1234 ++ -device e1000,netdev=n3,macaddr=52:54:00:12:34:58 \ ++ -netdev socket,id=n3,mcast=230.0.0.1:1234 @end example -@@ -2339,7 +2339,7 @@ Example (User Mode Linux compat.): + + Example (User Mode Linux compat.): @example - # launch QEMU instance (note mcast address selected - # is UML's default) + # launch QEMU instance (note mcast address selected is UML's default) -qemu-system-i386 linux.img \ +qemu-kvm linux.img \ - -net nic,macaddr=52:54:00:12:34:56 \ - -net socket,mcast=239.192.168.1:1102 + -device e1000,netdev=n1,mac=52:54:00:12:34:56 \ + -netdev socket,id=n1,mcast=239.192.168.1:1102 # launch UML -@@ -2348,7 +2348,7 @@ qemu-system-i386 linux.img \ +@@ -2354,9 +2355,12 @@ qemu-system-i386 linux.img \ Example (send packets from host's 1.2.3.4): @example -qemu-system-i386 linux.img \ +- -device e1000,netdev=n1,mac=52:54:00:12:34:56 \ +- -netdev socket,id=n1,mcast=239.192.168.1:1102,localaddr=1.2.3.4 ++qemu-kvm linux.img \ ++ -device e1000,netdev=n1,mac=52:54:00:12:34:56 \ ++ -netdev socket,id=n1,mcast=239.192.168.1:1102,localaddr=1.2.3.4 +qemu-kvm linux.img \ - -net nic,macaddr=52:54:00:12:34:56 \ - -net socket,mcast=239.192.168.1:1102,localaddr=1.2.3.4 ++ -net nic,macaddr=52:54:00:12:34:56 \ ++ -net socket,mcast=239.192.168.1:1102,localaddr=1.2.3.4 @end example -@@ -2407,7 +2407,7 @@ brctl addif br-lan vmtunnel0 + + @item -netdev l2tpv3,id=@var{id},src=@var{srcaddr},dst=@var{dstaddr}[,srcport=@var{srcport}][,dstport=@var{dstport}],txsession=@var{txsession}[,rxsession=@var{rxsession}][,ipv6][,udp][,cookie64][,counter][,pincounter][,txcookie=@var{txcookie}][,rxcookie=@var{rxcookie}][,offset=@var{offset}] +@@ -2414,7 +2418,7 @@ brctl addif br-lan vmtunnel0 # on 4.3.2.1 # launch QEMU instance - if your network has reorder or is very lossy add ,pincounter --qemu-system-i386 linux.img -net nic -net l2tpv3,src=4.2.3.1,dst=1.2.3.4,udp,srcport=16384,dstport=16384,rxsession=0xffffffff,txsession=0xffffffff,counter -+qemu-kvm linux.img -net nic -net l2tpv3,src=4.2.3.1,dst=1.2.3.4,udp,srcport=16384,dstport=16384,rxsession=0xffffffff,txsession=0xffffffff,counter - +-qemu-system-i386 linux.img -device e1000,netdev=n1 \ ++qemu-kvm linux.img -device e1000,netdev=n1 \ + -netdev l2tpv3,id=n1,src=4.2.3.1,dst=1.2.3.4,udp,srcport=16384,dstport=16384,rxsession=0xffffffff,txsession=0xffffffff,counter @end example -@@ -2425,7 +2425,7 @@ Example: +@@ -2431,7 +2435,7 @@ Example: # launch vde switch vde_switch -F -sock /tmp/myswitch # launch QEMU instance --qemu-system-i386 linux.img -net nic -net vde,sock=/tmp/myswitch -+qemu-kvm linux.img -net nic -net vde,sock=/tmp/myswitch +-qemu-system-i386 linux.img -nic vde,sock=/tmp/myswitch ++qemu-kvm linux.img -nic vde,sock=/tmp/myswitch @end example - @item -netdev hubport,id=@var{id},hubid=@var{hubid} -@@ -2447,11 +2447,11 @@ be created for multiqueue vhost-user. + @item -netdev vhost-user,chardev=@var{id}[,vhostforce=on|off][,queues=n] +@@ -2445,11 +2449,11 @@ be created for multiqueue vhost-user. Example: @example @@ -737,134 +884,8 @@ index 568fc7c..5220120 100644 + -device virtio-net-pci,netdev=net0 @end example - @item -net dump[,vlan=@var{n}][,file=@var{file}][,len=@var{len}] -@@ -2819,7 +2819,7 @@ images for the guest storage. Both disk and cdrom images are supported. - Syntax for specifying iSCSI LUNs is - ``iscsi://[:]//'' - --By default qemu will use the iSCSI initiator-name -+By default qemu-kvm will use the iSCSI initiator-name - 'iqn.2008-11.org.linux-kvm[:]' but this can also be set from the command - line or a configuration file. - -@@ -2830,21 +2830,21 @@ is specified in seconds. The default is 0 which means no timeout. Libiscsi - - Example (without authentication): - @example --qemu-system-i386 -iscsi initiator-name=iqn.2001-04.com.example:my-initiator \ -+qemu-kvm -iscsi initiator-name=iqn.2001-04.com.example:my-initiator \ - -cdrom iscsi://192.0.2.1/iqn.2001-04.com.example/2 \ - -drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1 - @end example - - Example (CHAP username/password via URL): - @example --qemu-system-i386 -drive file=iscsi://user%password@@192.0.2.1/iqn.2001-04.com.example/1 -+qemu-kvm -drive file=iscsi://user%password@@192.0.2.1/iqn.2001-04.com.example/1 - @end example - - Example (CHAP username/password via environment variables): - @example - LIBISCSI_CHAP_USERNAME="user" \ - LIBISCSI_CHAP_PASSWORD="password" \ --qemu-system-i386 -drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1 -+qemu-kvm -drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1 - @end example - - iSCSI support is an optional feature of QEMU and only available when -@@ -2874,12 +2874,12 @@ Syntax for specifying a NBD device using Unix Domain Sockets - - Example for TCP - @example --qemu-system-i386 --drive file=nbd:192.0.2.1:30000 -+qemu-kvm --drive file=nbd:192.0.2.1:30000 - @end example - - Example for Unix Domain Sockets - @example --qemu-system-i386 --drive file=nbd:unix:/tmp/nbd-socket -+qemu-kvm --drive file=nbd:unix:/tmp/nbd-socket - @end example - - @item SSH -@@ -2887,8 +2887,8 @@ QEMU supports SSH (Secure Shell) access to remote disks. - - Examples: - @example --qemu-system-i386 -drive file=ssh://user@@host/path/to/disk.img --qemu-system-i386 -drive file.driver=ssh,file.user=user,file.host=host,file.port=22,file.path=/path/to/disk.img -+qemu-kvm -drive file=ssh://user@@host/path/to/disk.img -+qemu-kvm -drive file.driver=ssh,file.user=user,file.host=host,file.port=22,file.path=/path/to/disk.img - @end example - - Currently authentication must be done using ssh-agent. Other -@@ -2906,7 +2906,7 @@ sheepdog[+tcp|+unix]://[host:port]/vdiname[?socket=path][#snapid|#tag] - - Example - @example --qemu-system-i386 --drive file=sheepdog://192.0.2.1:30000/MyVirtualMachine -+qemu-kvm --drive file=sheepdog://192.0.2.1:30000/MyVirtualMachine - @end example - - See also @url{https://sheepdog.github.io/sheepdog/}. -@@ -2932,17 +2932,17 @@ JSON: - Example - @example - URI: --qemu-system-x86_64 --drive file=gluster://192.0.2.1/testvol/a.img, -+qemu-kvm --drive file=gluster://192.0.2.1/testvol/a.img, - @ file.debug=9,file.logfile=/var/log/qemu-gluster.log - - JSON: --qemu-system-x86_64 'json:@{"driver":"qcow2", -+qemu-kvm 'json:@{"driver":"qcow2", - @ "file":@{"driver":"gluster", - @ "volume":"testvol","path":"a.img", - @ "debug":9,"logfile":"/var/log/qemu-gluster.log", - @ "server":[@{"type":"tcp","host":"1.2.3.4","port":24007@}, - @ @{"type":"unix","socket":"/var/run/glusterd.socket"@}]@}@}' --qemu-system-x86_64 -drive driver=qcow2,file.driver=gluster,file.volume=testvol,file.path=/path/a.img, -+qemu-kvm -drive driver=qcow2,file.driver=gluster,file.volume=testvol,file.path=/path/a.img, - @ file.debug=9,file.logfile=/var/log/qemu-gluster.log, - @ file.server.0.type=tcp,file.server.0.host=1.2.3.4,file.server.0.port=24007, - @ file.server.1.type=unix,file.server.1.socket=/var/run/glusterd.socket -@@ -3002,14 +3002,14 @@ that CURL waits for a response from the remote server to get the size of the - image to be downloaded. If not set, the default timeout of 5 seconds is used. - @end table - --Note that when passing options to qemu explicitly, @option{driver} is the value -+Note that when passing options to qemu-kvm explicitly, @option{driver} is the value - of . - - Example: boot from a remote Fedora 20 live ISO image - @example --qemu-system-x86_64 --drive media=cdrom,file=http://dl.fedoraproject.org/pub/fedora/linux/releases/20/Live/x86_64/Fedora-Live-Desktop-x86_64-20-1.iso,readonly -+qemu-kvm --drive media=cdrom,file=http://dl.fedoraproject.org/pub/fedora/linux/releases/20/Live/x86_64/Fedora-Live-Desktop-x86_64-20-1.iso,readonly - --qemu-system-x86_64 --drive media=cdrom,file.driver=http,file.url=http://dl.fedoraproject.org/pub/fedora/linux/releases/20/Live/x86_64/Fedora-Live-Desktop-x86_64-20-1.iso,readonly -+qemu-kvm --drive media=cdrom,file.driver=http,file.url=http://dl.fedoraproject.org/pub/fedora/linux/releases/20/Live/x86_64/Fedora-Live-Desktop-x86_64-20-1.iso,readonly - @end example - - Example: boot from a remote Fedora 20 cloud image using a local overlay for -@@ -3017,7 +3017,7 @@ writes, copy-on-read, and a readahead of 64k - @example - qemu-img create -f qcow2 -o backing_file='json:@{"file.driver":"http",, "file.url":"https://dl.fedoraproject.org/pub/fedora/linux/releases/20/Images/x86_64/Fedora-x86_64-20-20131211.1-sda.qcow2",, "file.readahead":"64k"@}' /tmp/Fedora-x86_64-20-20131211.1-sda.qcow2 - --qemu-system-x86_64 -drive file=/tmp/Fedora-x86_64-20-20131211.1-sda.qcow2,copy-on-read=on -+qemu-kvm -drive file=/tmp/Fedora-x86_64-20-20131211.1-sda.qcow2,copy-on-read=on - @end example - - Example: boot from an image stored on a VMware vSphere server with a self-signed -@@ -3026,7 +3026,7 @@ of 10 seconds. - @example - qemu-img create -f qcow2 -o backing_file='json:@{"file.driver":"https",, "file.url":"https://user:password@@vsphere.example.com/folder/test/test-flat.vmdk?dcPath=Datacenter&dsName=datastore1",, "file.sslverify":"off",, "file.readahead":"64k",, "file.timeout":10@}' /tmp/test.qcow2 - --qemu-system-x86_64 -drive file=/tmp/test.qcow2 -+qemu-kvm -drive file=/tmp/test.qcow2 - @end example - ETEXI - -@@ -3090,7 +3090,7 @@ and communicate. Requires the Linux @code{vhci} driver installed. Can + @item -netdev hubport,id=@var{id},hubid=@var{hubid}[,netdev=@var{nd}] +@@ -2879,7 +2883,7 @@ and communicate. Requires the Linux @code{vhci} driver installed. Can be used as following: @example @@ -873,16 +894,7 @@ index 568fc7c..5220120 100644 @end example @item -bt device:@var{dev}[,vlan=@var{n}] -@@ -3136,7 +3136,7 @@ Options to each backend are described below. - - Use 'help' to print all available TPM backend types. - @example --qemu -tpmdev help -+qemu-kvm -tpmdev help - @end example - - @item -tpmdev passthrough, id=@var{id}, path=@var{path}, cancel-path=@var{cancel-path} -@@ -3504,14 +3504,14 @@ ETEXI +@@ -3310,14 +3314,14 @@ ETEXI DEF("realtime", HAS_ARG, QEMU_OPTION_realtime, "-realtime [mlock=on|off]\n" @@ -900,7 +912,7 @@ index 568fc7c..5220120 100644 (enabled by default). ETEXI -@@ -3525,7 +3525,7 @@ connections will likely be TCP-based, but also UDP, pseudo TTY, or even +@@ -3331,7 +3335,7 @@ connections will likely be TCP-based, but also UDP, pseudo TTY, or even stdio are reasonable use case. The latter is allowing to start QEMU from within gdb and establish the connection via a pipe: @example @@ -909,7 +921,7 @@ index 568fc7c..5220120 100644 @end example ETEXI -@@ -4340,7 +4340,7 @@ which specify the queue number of cryptodev backend, the default of +@@ -4251,7 +4255,7 @@ which specify the queue number of cryptodev backend, the default of @example @@ -918,6 +930,15 @@ index 568fc7c..5220120 100644 [...] \ -object cryptodev-backend-builtin,id=cryptodev0 \ -device virtio-crypto-pci,id=crypto0,cryptodev=cryptodev0 \ +@@ -4271,7 +4275,7 @@ of cryptodev backend for multiqueue vhost-user, the default of @var{queues} is 1 + + @example + +- # qemu-system-x86_64 \ ++ # qemu-kvm \ + [...] \ + -chardev socket,id=chardev0,path=/path/to/socket \ + -object cryptodev-vhost-user,id=cryptodev0,chardev=chardev0 \ -- 1.8.3.1 diff --git a/SOURCES/0019-qmp-add-__com.redhat_reason-to-the-BLOCK_IO_ERROR-ev.patch b/SOURCES/0019-qmp-add-__com.redhat_reason-to-the-BLOCK_IO_ERROR-ev.patch index 891eeec..7598393 100644 --- a/SOURCES/0019-qmp-add-__com.redhat_reason-to-the-BLOCK_IO_ERROR-ev.patch +++ b/SOURCES/0019-qmp-add-__com.redhat_reason-to-the-BLOCK_IO_ERROR-ev.patch @@ -1,4 +1,4 @@ -From e2bf476c86cf5697ef3ea6aab2249aa85b8be2cd Mon Sep 17 00:00:00 2001 +From 171f9db1f1217a217c7c13b3282b66eec7a165d1 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Wed, 15 Mar 2017 13:25:17 +0100 Subject: qmp: add __com.redhat_reason to the BLOCK_IO_ERROR event @@ -37,16 +37,20 @@ Rebase notes (2.9.0): - moved documentation to schema (cherry picked from commit 2f9487b60f700de33551208c543f5d3b4fa89236) +(cherry picked from commit e2bf476c86cf5697ef3ea6aab2249aa85b8be2cd) +(cherry picked from commit 025b8d9385cab3c7c00e0caf9af84722a9ac914c) +(cherry picked from commit 264ccd5fc938bc26362046a697ad0d535531e69b) +(cherry picked from commit 88802f4552223d31f0ea9cf6c943ad3b091120cd) --- block/block-backend.c | 27 +++++++++++++++++++++++---- qapi/block-core.json | 20 ++++++++++++++++++-- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/block/block-backend.c b/block/block-backend.c -index 1031742..0819b3a 100644 +index 681b240..fd342db 100644 --- a/block/block-backend.c +++ b/block/block-backend.c -@@ -1510,9 +1510,25 @@ BlockErrorAction blk_get_error_action(BlockBackend *blk, bool is_read, +@@ -1650,9 +1650,25 @@ BlockErrorAction blk_get_error_action(BlockBackend *blk, bool is_read, } } @@ -72,9 +76,9 @@ index 1031742..0819b3a 100644 + RHEL7BlockErrorReason res) { IoOperationType optype; - -@@ -1521,7 +1537,7 @@ static void send_qmp_error_event(BlockBackend *blk, - bdrv_get_node_name(blk_bs(blk)), optype, + BlockDriverState *bs = blk_bs(blk); +@@ -1662,7 +1678,7 @@ static void send_qmp_error_event(BlockBackend *blk, + bs ? bdrv_get_node_name(bs) : NULL, optype, action, blk_iostatus_is_enabled(blk), error == ENOSPC, strerror(error), - &error_abort); @@ -82,7 +86,7 @@ index 1031742..0819b3a 100644 } /* This is done by device models because, while the block layer knows -@@ -1531,7 +1547,10 @@ static void send_qmp_error_event(BlockBackend *blk, +@@ -1672,7 +1688,10 @@ static void send_qmp_error_event(BlockBackend *blk, void blk_error_action(BlockBackend *blk, BlockErrorAction action, bool is_read, int error) { @@ -93,7 +97,7 @@ index 1031742..0819b3a 100644 if (action == BLOCK_ERROR_ACTION_STOP) { /* First set the iostatus, so that "info block" returns an iostatus -@@ -1549,10 +1568,10 @@ void blk_error_action(BlockBackend *blk, BlockErrorAction action, +@@ -1690,10 +1709,10 @@ void blk_error_action(BlockBackend *blk, BlockErrorAction action, * also ensures that the STOP/RESUME pair of events is emitted. */ qemu_system_vmstop_request_prepare(); @@ -107,10 +111,10 @@ index 1031742..0819b3a 100644 } diff --git a/qapi/block-core.json b/qapi/block-core.json -index 833c602..8f5f105 100644 +index c50517b..b38d5d6 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json -@@ -3552,6 +3552,19 @@ +@@ -4404,6 +4404,19 @@ 'fatal' : 'bool' } } ## @@ -130,7 +134,7 @@ index 833c602..8f5f105 100644 # @BLOCK_IO_ERROR: # # Emitted when a disk I/O error occurs -@@ -3577,6 +3590,8 @@ +@@ -4430,6 +4443,8 @@ # (This field is a debugging aid for humans, it should not # be parsed by applications) (since: 2.2) # @@ -139,7 +143,7 @@ index 833c602..8f5f105 100644 # Note: If action is "stop", a STOP event will eventually follow the # BLOCK_IO_ERROR event # -@@ -3588,14 +3603,15 @@ +@@ -4441,7 +4456,8 @@ # "data": { "device": "ide0-hd1", # "node-name": "#block212", # "operation": "write", @@ -149,8 +153,9 @@ index 833c602..8f5f105 100644 # "timestamp": { "seconds": 1265044230, "microseconds": 450486 } } # ## - { 'event': 'BLOCK_IO_ERROR', - 'data': { 'device': 'str', 'node-name': 'str', 'operation': 'IoOperationType', +@@ -4449,7 +4465,7 @@ + 'data': { 'device': 'str', '*node-name': 'str', + 'operation': 'IoOperationType', 'action': 'BlockErrorAction', '*nospace': 'bool', - 'reason': 'str' } } + 'reason': 'str', '__com.redhat_reason': 'RHEL7BlockErrorReason' } } diff --git a/SOURCES/0020-Migration-compat-for-pckbd.patch b/SOURCES/0020-Migration-compat-for-pckbd.patch index daaee47..4ca6bb1 100644 --- a/SOURCES/0020-Migration-compat-for-pckbd.patch +++ b/SOURCES/0020-Migration-compat-for-pckbd.patch @@ -1,4 +1,4 @@ -From 583b819622f77c9e62bf3cd4f44b08de8aa46dcd Mon Sep 17 00:00:00 2001 +From a13b85a600a676b75777d71dd6f11c233a5d8849 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 25 Jun 2015 16:34:25 +0200 Subject: Migration compat for pckbd @@ -27,23 +27,31 @@ explicitly read the outport value it might get a more sensible reply. Signed-off-by: Dr. David Alan Gilbert Signed-off-by: Miroslav Rezanina (cherry picked from commit d2aba8a17b40c081f2ce29bc12b3945b7fb91d53) +(cherry picked from commit 583b819622f77c9e62bf3cd4f44b08de8aa46dcd) + +Conflicts: + hw/input/pckbd.c + +(cherry picked from commit b26d8202c6a76320865d3a9dad113e570f4e1bad) +(cherry picked from commit fd17a12528099d896cbdb032425f08d393fca145) +(cherry picked from commit 9fb05d3c53161d680e58dc44b3db75d4c9a43453) --- hw/input/pckbd.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/input/pckbd.c b/hw/input/pckbd.c -index 62678f3..7d43237 100644 +index 66adb83..bbd4112 100644 --- a/hw/input/pckbd.c +++ b/hw/input/pckbd.c -@@ -26,6 +26,7 @@ - #include "hw/isa/isa.h" +@@ -27,6 +27,7 @@ #include "hw/i386/pc.h" #include "hw/input/ps2.h" + #include "hw/input/i8042.h" +#include "migration/migration.h" #include "sysemu/sysemu.h" /* debug PC keyboard */ -@@ -389,6 +390,11 @@ static int kbd_outport_post_load(void *opaque, int version_id) +@@ -390,6 +391,11 @@ static int kbd_outport_post_load(void *opaque, int version_id) static bool kbd_outport_needed(void *opaque) { KBDState *s = opaque; diff --git a/SOURCES/0021-Migration-compat-for-fdc.patch b/SOURCES/0021-Migration-compat-for-fdc.patch index f852ee3..c1f3355 100644 --- a/SOURCES/0021-Migration-compat-for-fdc.patch +++ b/SOURCES/0021-Migration-compat-for-fdc.patch @@ -1,4 +1,4 @@ -From 50613448205a2e85e90a488be1c83d0f2b5f2d52 Mon Sep 17 00:00:00 2001 +From 81b63caf259fac3ec0906f6d7712a831206d0dd5 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Fri, 26 Jun 2015 16:19:47 +0200 Subject: Migration compat for fdc @@ -44,12 +44,16 @@ There are three pieces of data added to the migration: Signed-off-by: Dr. David Alan Gilbert Signed-off-by: Miroslav Rezanina (cherry picked from commit b18d89c56aa26e86fb6194f77a15a72244d5ff88) +(cherry picked from commit 50613448205a2e85e90a488be1c83d0f2b5f2d52) +(cherry picked from commit 5bdbc1fe6b4574c78c80e664c539c51d7719f84d) +(cherry picked from commit 069889e404721c5439ee7d69aa90f9d4580f4f21) +(cherry picked from commit fd31805201e8da37645c5a34f7990a281afce10f) --- hw/block/fdc.c | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/hw/block/fdc.c b/hw/block/fdc.c -index 90cd9a0..d3213cb 100644 +index 3964096..6943263 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -36,6 +36,7 @@ @@ -60,7 +64,7 @@ index 90cd9a0..d3213cb 100644 #include "sysemu/block-backend.h" #include "sysemu/blockdev.h" #include "sysemu/sysemu.h" -@@ -1042,6 +1043,10 @@ static bool fdrive_perpendicular_needed(void *opaque) +@@ -1036,6 +1037,10 @@ static bool fdrive_perpendicular_needed(void *opaque) { FDrive *drive = opaque; @@ -71,7 +75,7 @@ index 90cd9a0..d3213cb 100644 return drive->perpendicular != 0; } -@@ -1134,8 +1139,20 @@ static int fdc_post_load(void *opaque, int version_id) +@@ -1130,8 +1135,20 @@ static int fdc_post_load(void *opaque, int version_id) static bool fdc_reset_sensei_needed(void *opaque) { FDCtrl *s = opaque; @@ -93,7 +97,7 @@ index 90cd9a0..d3213cb 100644 } static const VMStateDescription vmstate_fdc_reset_sensei = { -@@ -1152,8 +1169,26 @@ static const VMStateDescription vmstate_fdc_reset_sensei = { +@@ -1148,8 +1165,26 @@ static const VMStateDescription vmstate_fdc_reset_sensei = { static bool fdc_result_timer_needed(void *opaque) { FDCtrl *s = opaque; diff --git a/SOURCES/0022-RHEL-Set-vcpus-hard-limit-to-240-for-Power.patch b/SOURCES/0022-RHEL-Set-vcpus-hard-limit-to-240-for-Power.patch deleted file mode 100644 index a58629a..0000000 --- a/SOURCES/0022-RHEL-Set-vcpus-hard-limit-to-240-for-Power.patch +++ /dev/null @@ -1,62 +0,0 @@ -From fdeef3c1c7926a5c8a5b732135ea0a80b177c103 Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Thu, 3 Sep 2015 04:09:04 +0200 -Subject: RHEL: Set vcpus hard limit to 240 for Power - -Patchwork-id: 67655 -O-Subject: [RHEL7.2 qemu-kvm-rhev PATCH] RHEL: Set vcpus hard limit to 240 for Power -Bugzilla: 1257781 -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth -RH-Acked-by: Laszlo Ersek - -On POWER, the kernel advertises a soft limit based on the number of CPU -threads on the host. We want to allow exceeding this for testing purposes, -so we don't want to set hard limit to soft limit as on x86. - -However the POWER hard limit advertised by the kernel is 2048 (== NR_CPUS) -but we only want to allow up to the number of vCPUs we actually test, so -we force the hard limit to 240. - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina -(cherry picked from commit 815a8be86930089767730c30cfb6b5373c138cf7) ---- - accel/kvm/kvm-all.c | 19 +++++++++++++++++++ - 1 file changed, 19 insertions(+) - -diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c -index b42c56a..80ab1c7 100644 ---- a/accel/kvm/kvm-all.c -+++ b/accel/kvm/kvm-all.c -@@ -1627,8 +1627,27 @@ static int kvm_init(MachineState *ms) - soft_vcpus_limit = kvm_recommended_vcpus(s); - hard_vcpus_limit = kvm_max_vcpus(s); - -+#ifdef HOST_PPC64 -+ /* -+ * RHEL hack: -+ * -+ * On POWER, the kernel advertises a soft limit based on the -+ * number of CPU threads on the host. We want to allow exceeding -+ * this for testing purposes, so we don't want to set hard limit -+ * to soft limit as on x86. -+ * -+ * However the POWER hard limit advertised by the kernel is 2048 -+ * (== NR_CPUS) but we only want to allow up to the number of -+ * vCPUs we actually test, so we force the hard limit to 240 -+ */ -+ hard_vcpus_limit = 240; -+ if (soft_vcpus_limit > hard_vcpus_limit) { -+ soft_vcpus_limit = hard_vcpus_limit; -+ } -+#else - /* RHEL doesn't support nr_vcpus > soft_vcpus_limit */ - hard_vcpus_limit = soft_vcpus_limit; -+#endif - - while (nc->name) { - if (nc->num > soft_vcpus_limit) { --- -1.8.3.1 - diff --git a/SOURCES/0022-spapr-Reduce-advertised-max-LUNs-for-spapr_vscsi.patch b/SOURCES/0022-spapr-Reduce-advertised-max-LUNs-for-spapr_vscsi.patch new file mode 100644 index 0000000..5793a1d --- /dev/null +++ b/SOURCES/0022-spapr-Reduce-advertised-max-LUNs-for-spapr_vscsi.patch @@ -0,0 +1,52 @@ +From ee04d835a5a44c7f2ca4cc42f5603879b64a9ebd Mon Sep 17 00:00:00 2001 +From: David Gibson +Date: Wed, 9 Sep 2015 02:03:04 +0200 +Subject: spapr: Reduce advertised max LUNs for spapr_vscsi + +Patchwork-id: 67711 +O-Subject: [RHEL7.2 qemu-kvm-rhev PATCH] spapr: Reduce advertised max LUNs for spapr_vscsi +Bugzilla: 1260464 +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: Laurent Vivier +RH-Acked-by: Thomas Huth + +The implementation of the PAPR paravirtual SCSI adapter currently +allows up to 32 LUNs (max_lun == 31). However the adapter isn't really +designed to support lots of devices - the PowerVM implementation only +ever puts one disk per vSCSI controller. + +More specifically, the Linux guest side vscsi driver (the only one we +really care about) is hardcoded to allow a maximum of 8 LUNs. + +So, reduce the number of LUNs on the qemu side to 8, so we don't +falsely advertise that more LUNs can work. + +Signed-off-by: David Gibson + +Signed-off-by: David Gibson +Signed-off-by: Miroslav Rezanina +(cherry picked from commit 6c166e382c232ba4e527b4fc5ca9fdea151498d9) +(cherry picked from commit 9eadef5817e22891efc509ff1af6f0d14545b2b0) +(cherry picked from commit dea0aabfbf919f28cf04db7343c42dc423fdf79b) +(cherry picked from commit 6aef4d0da0a410a8224dec70743c32d4e10eee8b) +(cherry picked from commit 50fdb5661adeeb0867bbaae8cd9ac55d71499231) +--- + hw/scsi/spapr_vscsi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c +index a9e49c7..3a06b2f 100644 +--- a/hw/scsi/spapr_vscsi.c ++++ b/hw/scsi/spapr_vscsi.c +@@ -1178,7 +1178,7 @@ static const struct SCSIBusInfo vscsi_scsi_info = { + .tcq = true, + .max_channel = 7, /* logical unit addressing format */ + .max_target = 63, +- .max_lun = 31, ++ .max_lun = 7, + + .transfer_data = vscsi_transfer_data, + .complete = vscsi_command_complete, +-- +1.8.3.1 + diff --git a/SOURCES/0023-RHEL-only-hw-char-pl011-fix-SBSA-reset.patch b/SOURCES/0023-RHEL-only-hw-char-pl011-fix-SBSA-reset.patch new file mode 100644 index 0000000..f3d422f --- /dev/null +++ b/SOURCES/0023-RHEL-only-hw-char-pl011-fix-SBSA-reset.patch @@ -0,0 +1,61 @@ +From 098bbd9ed847849834ff1f21766d23ea240c5bf0 Mon Sep 17 00:00:00 2001 +From: Andrew Jones +Date: Mon, 1 Aug 2016 14:27:09 +0200 +Subject: RHEL-only: hw/char/pl011: fix SBSA reset + +RH-Author: Andrew Jones +Message-id: <1470061629-6395-1-git-send-email-drjones@redhat.com> +Patchwork-id: 71697 +O-Subject: [AArch64 RHEL-7.3 qemu-kvm-rhev PATCH] RHEL-only: hw/char/pl011: fix SBSA reset +Bugzilla: 1266048 +RH-Acked-by: Auger Eric +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Wei Huang + +When booting Linux with an SBSA UART, e.g. when booting mach-virt +with ACPI, if the user types on the console during boot, then when +the login prompt appears she won't be able to log in. This is +because during boot the SBSA UART needs to be reset, but the SBSA +specification doesn't provide registers to enable/disable the FIFOs. +This patch observes a couple registers the SBSA UART does write to +in order to attempt to guess when a reset is needed, and then do it. +We risk losing some characters from the FIFO if the guess is wrong, +but the risk of that should be quite low. + +Signed-off-by: Andrew Jones +Signed-off-by: Miroslav Rezanina +(cherry picked from commit 15ee295534f654d6b6ba9499cdd380aa9c954920) +(cherry picked from commit 49be481336c227fdad2f7edc02fa088f3d88c9a2) +(cherry picked from commit 9fcede24f35378e2c9113440a692d2c96cc94865) +(cherry picked from commit b721e7ff2bdd42b0a786b8630c1ba8b1d3560da3) +(cherry picked from commit 88f3eb70f909b03ed18074aadd12f32f28ad8437) +--- + hw/char/pl011.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/hw/char/pl011.c b/hw/char/pl011.c +index 2aa277f..23fe047 100644 +--- a/hw/char/pl011.c ++++ b/hw/char/pl011.c +@@ -209,6 +209,18 @@ static void pl011_write(void *opaque, hwaddr offset, + pl011_update(s); + break; + case 17: /* UARTICR */ ++ /* ++ * RHEL-only, fixes BZ1266048 ++ * ++ * Look for the "signature" of a driver init or shutdown in ++ * order to know that we need to reset the SBSA UART. Yes, ++ * this is hacky, but as SBSA drivers aren't required to write ++ * UARTLCR_H or UARTCR, then we don't have much choice... ++ */ ++ if (s->int_enabled == 0 && value == 0xffff) { ++ s->read_count = 0; ++ s->read_pos = 0; ++ } + s->int_level &= ~value; + pl011_update(s); + break; +-- +1.8.3.1 + diff --git a/SOURCES/0023-spapr-Reduce-advertised-max-LUNs-for-spapr_vscsi.patch b/SOURCES/0023-spapr-Reduce-advertised-max-LUNs-for-spapr_vscsi.patch deleted file mode 100644 index 29d10b0..0000000 --- a/SOURCES/0023-spapr-Reduce-advertised-max-LUNs-for-spapr_vscsi.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 9eadef5817e22891efc509ff1af6f0d14545b2b0 Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Wed, 9 Sep 2015 02:03:04 +0200 -Subject: spapr: Reduce advertised max LUNs for spapr_vscsi - -Patchwork-id: 67711 -O-Subject: [RHEL7.2 qemu-kvm-rhev PATCH] spapr: Reduce advertised max LUNs for spapr_vscsi -Bugzilla: 1260464 -RH-Acked-by: Miroslav Rezanina -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth - -The implementation of the PAPR paravirtual SCSI adapter currently -allows up to 32 LUNs (max_lun == 31). However the adapter isn't really -designed to support lots of devices - the PowerVM implementation only -ever puts one disk per vSCSI controller. - -More specifically, the Linux guest side vscsi driver (the only one we -really care about) is hardcoded to allow a maximum of 8 LUNs. - -So, reduce the number of LUNs on the qemu side to 8, so we don't -falsely advertise that more LUNs can work. - -Signed-off-by: David Gibson - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina -(cherry picked from commit 6c166e382c232ba4e527b4fc5ca9fdea151498d9) ---- - hw/scsi/spapr_vscsi.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c -index 55ee48c..92a3de3 100644 ---- a/hw/scsi/spapr_vscsi.c -+++ b/hw/scsi/spapr_vscsi.c -@@ -1178,7 +1178,7 @@ static const struct SCSIBusInfo vscsi_scsi_info = { - .tcq = true, - .max_channel = 7, /* logical unit addressing format */ - .max_target = 63, -- .max_lun = 31, -+ .max_lun = 7, - - .transfer_data = vscsi_transfer_data, - .complete = vscsi_command_complete, --- -1.8.3.1 - diff --git a/SOURCES/0024-blockdev-ignore-cache-options-for-empty-CDROM-drives.patch b/SOURCES/0024-blockdev-ignore-cache-options-for-empty-CDROM-drives.patch new file mode 100644 index 0000000..4c5c575 --- /dev/null +++ b/SOURCES/0024-blockdev-ignore-cache-options-for-empty-CDROM-drives.patch @@ -0,0 +1,94 @@ +From 8d74e190054f8a2254f9da5a0eb2e17c66df94db Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 16 Sep 2016 22:06:28 +0200 +Subject: blockdev: ignore cache options for empty CDROM drives + +RH-Author: John Snow +Message-id: <1474063588-6370-2-git-send-email-jsnow@redhat.com> +Patchwork-id: 72377 +O-Subject: [RHEV-7.3 qemu-kvm-rhev PATCH 1/1] blockdev: ignore cache options for empty CDROM drives +Bugzilla: 1342999 +RH-Acked-by: Max Reitz +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi + +In qemu-kvm-rhev-2.3.0, QEMU will accept cache options for empty CDROM +devices, but silently ignore them as they will be overwritten when the +next CDROM is inserted. + +Libvirt and VMM are capable of generating XML configurations which +attempt to specify these cache options to QEMU, though they don't have +any effect. + +Upstream, a refactoring of cache option mechanisms means that we have +started rejecting invalid configurations where cache options are supplied +without any target to actually apply them to. + +This means that there are combinations of QEMU and libvirt that will fail +to start a VM if a user selects a cache option. + +This patch is a downstream-only workaround until libvirt can stop +supplying cache settings for empty CDROMs and/or until libvirt can take +advantage of the new QMP tray/medium manipulation mechanisms that will +allow proper cache specification for removable media. + +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +(cherry picked from commit 89b162019bfd202bbbd00563d03a030c2f7c1395) +(cherry picked from commit 454f60447bfea904d561ef282fc0446229484c02) +(cherry picked from commit 50e4b1d94ce41a9c83034d372caea6ed20d6fcfb) +(cherry picked from commit 54994db40273e0b4bec5f703459fdb71a453a373) +(cherry picked from commit 0f4f6f39126ba96a4b288bb13bcd0f13eb46fa35) +--- + blockdev.c | 28 +++++++++++++++++++++++++++- + 1 file changed, 27 insertions(+), 1 deletion(-) + +diff --git a/blockdev.c b/blockdev.c +index e941b99..cf10108 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -460,6 +460,32 @@ static void extract_common_blockdev_options(QemuOpts *opts, int *bdrv_flags, + } + } + ++/** ++ * libvirt expects to be able to pass cache options for CDROM drives without ++ * inserted media. Historically, QEMU eventually ignores these cache options as ++ * they are lost when media is inserted. Recently, QEMU started rejecting these ++ * configurations. Libvirt however still generates such configurations. ++ * ++ * To prevent QEMU from being unable to start, pretend there are no options ++ * present if the only options present are cache options for the BDS. ++ */ ++static bool __redhat_com_has_bs_opts(QDict *bs_opts) ++{ ++ size_t n, s; ++ s = qdict_size(bs_opts); ++ ++ if (s == 0) { ++ return false; ++ } else if (s > 2) { ++ return true; ++ } ++ ++ n = qdict_haskey(bs_opts, BDRV_OPT_CACHE_DIRECT); ++ n += qdict_haskey(bs_opts, BDRV_OPT_CACHE_NO_FLUSH); ++ ++ return s != n; ++} ++ + /* Takes the ownership of bs_opts */ + static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, + Error **errp) +@@ -567,7 +593,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, + read_only = qemu_opt_get_bool(opts, BDRV_OPT_READ_ONLY, false); + + /* init */ +- if ((!file || !*file) && !qdict_size(bs_opts)) { ++ if ((!file || !*file) && !__redhat_com_has_bs_opts(bs_opts)) { + BlockBackendRootState *blk_rs; + + blk = blk_new(0, BLK_PERM_ALL); +-- +1.8.3.1 + diff --git a/SOURCES/0024-qmp-Report-__com.redhat_drive_add-error-to-monitor.patch b/SOURCES/0024-qmp-Report-__com.redhat_drive_add-error-to-monitor.patch deleted file mode 100644 index 78a5095..0000000 --- a/SOURCES/0024-qmp-Report-__com.redhat_drive_add-error-to-monitor.patch +++ /dev/null @@ -1,52 +0,0 @@ -From d6db718295b53f11017aaba1dd8a0507c77d7a1e Mon Sep 17 00:00:00 2001 -From: Fam Zheng -Date: Thu, 19 May 2016 06:39:44 +0200 -Subject: qmp: Report __com.redhat_drive_add error to monitor - -RH-Author: Fam Zheng -Message-id: <1463639984-1165-1-git-send-email-famz@redhat.com> -Patchwork-id: 70412 -O-Subject: [RHEL-7.3 qemu-kvm-rhev PATCH] qmp: Report drive_add error to monitor -Bugzilla: 1337100 -RH-Acked-by: Markus Armbruster -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Kevin Wolf - -In other error cases of this function we use error_setg, the same should -be done with drive_new() failures. This is useful for libvirt to -correctly detect the failure and report proper error message when a -specified image is not available. - -This bug cames from the forward porting from qemu-kvm, at which point we -overlooked the difference in QMP reporting between qerror_report and -error_report. - -Signed-off-by: Fam Zheng -Signed-off-by: Miroslav Rezanina -(cherry picked from commit c5736179da1a310ddb384836fc025b2582f9e90d) - -Rebase notes (2.8.0): -- Changed patch name - -(cherry picked from commit 8a1f601ec13449e736c05789c4f5ae52ab34f3a7) ---- - device-hotplug.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/device-hotplug.c b/device-hotplug.c -index 218f7b3..29f9a64 100644 ---- a/device-hotplug.c -+++ b/device-hotplug.c -@@ -145,8 +145,7 @@ void qmp_simple_drive_add(QDict *qdict, QObject **ret_data, Error **errp) - mc = MACHINE_GET_CLASS(current_machine); - dinfo = drive_new(opts, mc->block_default_type); - if (!dinfo) { -- error_report(QERR_DEVICE_INIT_FAILED, -- qemu_opts_id(opts)); -+ error_setg(errp, QERR_DEVICE_INIT_FAILED, qemu_opts_id(opts)); - qemu_opts_del(opts); - return; - } --- -1.8.3.1 - diff --git a/SOURCES/0025-RHEL-only-hw-char-pl011-fix-SBSA-reset.patch b/SOURCES/0025-RHEL-only-hw-char-pl011-fix-SBSA-reset.patch deleted file mode 100644 index ab6d21b..0000000 --- a/SOURCES/0025-RHEL-only-hw-char-pl011-fix-SBSA-reset.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 49be481336c227fdad2f7edc02fa088f3d88c9a2 Mon Sep 17 00:00:00 2001 -From: Andrew Jones -Date: Mon, 1 Aug 2016 14:27:09 +0200 -Subject: RHEL-only: hw/char/pl011: fix SBSA reset - -RH-Author: Andrew Jones -Message-id: <1470061629-6395-1-git-send-email-drjones@redhat.com> -Patchwork-id: 71697 -O-Subject: [AArch64 RHEL-7.3 qemu-kvm-rhev PATCH] RHEL-only: hw/char/pl011: fix SBSA reset -Bugzilla: 1266048 -RH-Acked-by: Auger Eric -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Wei Huang - -When booting Linux with an SBSA UART, e.g. when booting mach-virt -with ACPI, if the user types on the console during boot, then when -the login prompt appears she won't be able to log in. This is -because during boot the SBSA UART needs to be reset, but the SBSA -specification doesn't provide registers to enable/disable the FIFOs. -This patch observes a couple registers the SBSA UART does write to -in order to attempt to guess when a reset is needed, and then do it. -We risk losing some characters from the FIFO if the guess is wrong, -but the risk of that should be quite low. - -Signed-off-by: Andrew Jones -Signed-off-by: Miroslav Rezanina -(cherry picked from commit 15ee295534f654d6b6ba9499cdd380aa9c954920) ---- - hw/char/pl011.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/hw/char/pl011.c b/hw/char/pl011.c -index 2aa277f..23fe047 100644 ---- a/hw/char/pl011.c -+++ b/hw/char/pl011.c -@@ -209,6 +209,18 @@ static void pl011_write(void *opaque, hwaddr offset, - pl011_update(s); - break; - case 17: /* UARTICR */ -+ /* -+ * RHEL-only, fixes BZ1266048 -+ * -+ * Look for the "signature" of a driver init or shutdown in -+ * order to know that we need to reset the SBSA UART. Yes, -+ * this is hacky, but as SBSA drivers aren't required to write -+ * UARTLCR_H or UARTCR, then we don't have much choice... -+ */ -+ if (s->int_enabled == 0 && value == 0xffff) { -+ s->read_count = 0; -+ s->read_pos = 0; -+ } - s->int_level &= ~value; - pl011_update(s); - break; --- -1.8.3.1 - diff --git a/SOURCES/0025-usb-xhci-Fix-PCI-capability-order.patch b/SOURCES/0025-usb-xhci-Fix-PCI-capability-order.patch new file mode 100644 index 0000000..0fc8c0d --- /dev/null +++ b/SOURCES/0025-usb-xhci-Fix-PCI-capability-order.patch @@ -0,0 +1,96 @@ +From 273826f0427e0e62be20ea42349dfb591dbcdf14 Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Fri, 5 May 2017 19:06:14 +0200 +Subject: usb-xhci: Fix PCI capability order + +RH-Author: Dr. David Alan Gilbert +Message-id: <20170505190614.15987-2-dgilbert@redhat.com> +Patchwork-id: 75038 +O-Subject: [RHEL-7.4 qemu-kvm-rhev PATCH 1/1] usb-xhci: Fix PCI capability order +Bugzilla: 1447874 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Juan Quintela + +From: "Dr. David Alan Gilbert" + +Upstream commit 1108b2f8a9 in 2.7.0 changed the order +of the PCI capability chain in the XHCI pci device in the case +where the device has the PCIe endpoint capability (i.e. only +older machine types, pc-i440fx-2.0 upstream, pc-i440fx-rhel7.0.0 +apparently for us). + +Changing the order breaks migration compatibility; fixing this +upstream would mean breaking the same case going from 2.7.0->current +that currently works 2.7.0->2.9.0 - so upstream it's a choice +of two breakages. + +Since we never released 2.7.0/2.8.0 we can fix this downstream. + +This reverts the order so that we create the capabilities in the +order: + PCIe + MSI + MSI-X + +The symptom is: +qemu-kvm: get_pci_config_device: Bad config data: i=0x71 read: a0 device: 0 cmask: ff wmask: 0 w1cmask:0 +qemu-kvm: Failed to load PCIDevice:config +qemu-kvm: Failed to load xhci:parent_obj +qemu-kvm: error while loading state for instance 0x0 of device '0000:00:0d.0/xhci' +qemu-kvm: load of migration failed: Invalid argument + +Signed-off-by: Dr. David Alan Gilbert +Signed-off-by: Miroslav Rezanina + +-- +Rebase notes (2.9.0): +- Change in assert condition (upstream) + +(cherry picked from commit aad727a5ecde1ad4935eb8427604d4df5a1f1f35) +(cherry picked from commit 2dd7402227e77d748a7375233ac9e7feab244bda) + +Conflicts: + hw/usb/hcd-xhci.c + +(cherry picked from commit a42f86dc906cc7d2c16d02bf125ed76847b469cb) +(cherry picked from commit 992ab2e4f6e15d3e51bc716763aa8d6f45c6d29d) +(cherry picked from commit 5b7b0303b6dd70c32bd03a9d8facd7eb7cf72be8) +--- + hw/usb/hcd-xhci.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index 883141f..181e803 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -3368,6 +3368,12 @@ static void usb_xhci_realize(struct PCIDevice *dev, Error **errp) + xhci->max_pstreams_mask = 0; + } + ++ if (pci_bus_is_express(pci_get_bus(dev)) || ++ xhci_get_flag(xhci, XHCI_FLAG_FORCE_PCIE_ENDCAP)) { ++ ret = pcie_endpoint_cap_init(dev, 0xa0); ++ assert(ret > 0); ++ } ++ + if (xhci->msi != ON_OFF_AUTO_OFF) { + ret = msi_init(dev, 0x70, xhci->numintrs, true, false, &err); + /* Any error other than -ENOTSUP(board's MSI support is broken) +@@ -3416,12 +3422,6 @@ static void usb_xhci_realize(struct PCIDevice *dev, Error **errp) + PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64, + &xhci->mem); + +- if (pci_bus_is_express(pci_get_bus(dev)) || +- xhci_get_flag(xhci, XHCI_FLAG_FORCE_PCIE_ENDCAP)) { +- ret = pcie_endpoint_cap_init(dev, 0xa0); +- assert(ret > 0); +- } +- + if (xhci->msix != ON_OFF_AUTO_OFF) { + /* TODO check for errors, and should fail when msix=on */ + msix_init(dev, xhci->numintrs, +-- +1.8.3.1 + diff --git a/SOURCES/0026-blockdev-ignore-aio-native-for-empty-drives.patch b/SOURCES/0026-blockdev-ignore-aio-native-for-empty-drives.patch new file mode 100644 index 0000000..e459de3 --- /dev/null +++ b/SOURCES/0026-blockdev-ignore-aio-native-for-empty-drives.patch @@ -0,0 +1,78 @@ +From d4fe1e7fd6002d201088870c1e019b607c168454 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Thu, 11 May 2017 20:53:51 +0200 +Subject: blockdev: ignore aio=native for empty drives + +RH-Author: John Snow +Message-id: <20170511205351.6337-2-jsnow@redhat.com> +Patchwork-id: 75070 +O-Subject: [RHV-7.4 qemu-kvm-rhev PATCH 1/1] blockdev: ignore aio=native for empty drives +Bugzilla: 1402645 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Eric Blake +RH-Acked-by: Max Reitz + +This is a bit of a gross one; Upstream QEMU changed the way it handles +cache options with regards to removable media, associating options more +with the medium instead of the device. As part of that, it became +impossible to specify cache options on empty drives. + +In the future, one would use blockdev-add instead to choose cache options +per-medium instead of per-device, but we're not there yet in libvirt so +we added a workaround downstream to simply ignore cache options on empty +CDROMs under the premise of "It actually never worked anyway." + +As fallout from this decision, it is now no longer possible to specify +aio=native on empty CDROM devices either, as that requires the use of a +cache option that you can no longer specify. As a bad, gross, disgusting +workaround, simply ignore aio=native on empty drives until such time that +libvirt stops providing such configurations. + +Signed-off-by: Miroslav Rezanina +(cherry picked from commit cda174ad842c9a61bc275315bf3155139ba19bc0) +(cherry picked from commit a72f1c0f7b02ea571ec2ce35dfbe8c17c4dfa6d9) +(cherry picked from commit 313ffb6aba9419fe620b898c9b4a5ab4b0bff205) +(cherry picked from commit fa1666d4f59412a324067a1bd9b4fed7ca8c71f2) +(cherry picked from commit 62a7f6391872a32c3fdcbce988e2b7b760fca0c9) +--- + blockdev.c | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) + +diff --git a/blockdev.c b/blockdev.c +index cf10108..60b37dc 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -486,6 +486,21 @@ static bool __redhat_com_has_bs_opts(QDict *bs_opts) + return s != n; + } + ++/** ++ * libvirt expects to be able to pass io driver options (aio=native) for CDROM ++ * drives without inserted media. While this has worked historically, given the ++ * above workaround and lack of a supported alternative in current versions of ++ * libvirt, certain options such as aio=native cannot be supported as it ++ * requires the use of an accompanying cache option, which we also ignore. ++ * Until libvirt learns how to supply cache options to inserted media, ignore ++ * the aio= preference on empty CDROMs with the understanding that un-tuned ++ * performance is preferable to being unable to use the CDROM at all. ++ */ ++static int __redhat_com_filter_flags(int flags) ++{ ++ return flags & ~BDRV_O_NATIVE_AIO; ++} ++ + /* Takes the ownership of bs_opts */ + static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, + Error **errp) +@@ -598,7 +613,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, + + blk = blk_new(0, BLK_PERM_ALL); + blk_rs = blk_get_root_state(blk); +- blk_rs->open_flags = bdrv_flags; ++ blk_rs->open_flags = __redhat_com_filter_flags(bdrv_flags); + blk_rs->read_only = read_only; + blk_rs->detect_zeroes = detect_zeroes; + +-- +1.8.3.1 + diff --git a/SOURCES/0026-blockdev-ignore-cache-options-for-empty-CDROM-drives.patch b/SOURCES/0026-blockdev-ignore-cache-options-for-empty-CDROM-drives.patch deleted file mode 100644 index c824be1..0000000 --- a/SOURCES/0026-blockdev-ignore-cache-options-for-empty-CDROM-drives.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 454f60447bfea904d561ef282fc0446229484c02 Mon Sep 17 00:00:00 2001 -From: John Snow -Date: Fri, 16 Sep 2016 22:06:28 +0200 -Subject: blockdev: ignore cache options for empty CDROM drives - -RH-Author: John Snow -Message-id: <1474063588-6370-2-git-send-email-jsnow@redhat.com> -Patchwork-id: 72377 -O-Subject: [RHEV-7.3 qemu-kvm-rhev PATCH 1/1] blockdev: ignore cache options for empty CDROM drives -Bugzilla: 1342999 -RH-Acked-by: Max Reitz -RH-Acked-by: Kevin Wolf -RH-Acked-by: Stefan Hajnoczi - -In qemu-kvm-rhev-2.3.0, QEMU will accept cache options for empty CDROM -devices, but silently ignore them as they will be overwritten when the -next CDROM is inserted. - -Libvirt and VMM are capable of generating XML configurations which -attempt to specify these cache options to QEMU, though they don't have -any effect. - -Upstream, a refactoring of cache option mechanisms means that we have -started rejecting invalid configurations where cache options are supplied -without any target to actually apply them to. - -This means that there are combinations of QEMU and libvirt that will fail -to start a VM if a user selects a cache option. - -This patch is a downstream-only workaround until libvirt can stop -supplying cache settings for empty CDROMs and/or until libvirt can take -advantage of the new QMP tray/medium manipulation mechanisms that will -allow proper cache specification for removable media. - -Signed-off-by: John Snow -Signed-off-by: Miroslav Rezanina -(cherry picked from commit 89b162019bfd202bbbd00563d03a030c2f7c1395) ---- - blockdev.c | 28 +++++++++++++++++++++++++++- - 1 file changed, 27 insertions(+), 1 deletion(-) - -diff --git a/blockdev.c b/blockdev.c -index e525ebf..6d4cb70 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -450,6 +450,32 @@ static void extract_common_blockdev_options(QemuOpts *opts, int *bdrv_flags, - } - } - -+/** -+ * libvirt expects to be able to pass cache options for CDROM drives without -+ * inserted media. Historically, QEMU eventually ignores these cache options as -+ * they are lost when media is inserted. Recently, QEMU started rejecting these -+ * configurations. Libvirt however still generates such configurations. -+ * -+ * To prevent QEMU from being unable to start, pretend there are no options -+ * present if the only options present are cache options for the BDS. -+ */ -+static bool __redhat_com_has_bs_opts(QDict *bs_opts) -+{ -+ size_t n, s; -+ s = qdict_size(bs_opts); -+ -+ if (s == 0) { -+ return false; -+ } else if (s > 2) { -+ return true; -+ } -+ -+ n = qdict_haskey(bs_opts, BDRV_OPT_CACHE_DIRECT); -+ n += qdict_haskey(bs_opts, BDRV_OPT_CACHE_NO_FLUSH); -+ -+ return s != n; -+} -+ - /* Takes the ownership of bs_opts */ - static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, - Error **errp) -@@ -557,7 +583,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, - read_only = qemu_opt_get_bool(opts, BDRV_OPT_READ_ONLY, false); - - /* init */ -- if ((!file || !*file) && !qdict_size(bs_opts)) { -+ if ((!file || !*file) && !__redhat_com_has_bs_opts(bs_opts)) { - BlockBackendRootState *blk_rs; - - blk = blk_new(0, BLK_PERM_ALL); --- -1.8.3.1 - diff --git a/SOURCES/0027-Revert-kvm_stat-Remove.patch b/SOURCES/0027-Revert-kvm_stat-Remove.patch deleted file mode 100644 index 39bcf2f..0000000 --- a/SOURCES/0027-Revert-kvm_stat-Remove.patch +++ /dev/null @@ -1,1262 +0,0 @@ -From e0425f69f136a05a59ee5cb7022409ed2be94a0b Mon Sep 17 00:00:00 2001 -From: "Danilo C. L. de Paula" -Date: Mon, 16 Jan 2017 11:52:49 +0100 -Subject: Revert "kvm_stat: Remove" - -RH-Author: ddepaula -Message-id: <1479302806-10135-2-git-send-email-ddepaula@redhat.com> -Patchwork-id: 72851 -O-Subject: [RHEV-7.4 qemu-kvm-rhev PATCH v3 1/3] Revert "kvm_stat: Remove" -Bugzilla: 1389238 -RH-Acked-by: John Snow -RH-Acked-by: David Hildenbrand -RH-Acked-by: Miroslav Rezanina - -kvm_stat script was removed in QEMU 2.7.0 as it become part of kernel -tree. However kvm_stat is shipped in qemu-kvm-tools package in RHEL. - -This reverts commit 60b412dd18362bd4ddc44ba7022aacb6af074b5d. - -Signed-off-by: Danilo Cesar Lemes de Paula -Signed-off-by: Miroslav Rezanina - -Merged patches (2.9.0): -- 1e69b1b Include kvm_stat in qemu-kvm.spec -- 7fcfc94 tools: kvm_stat: Powerpc related fixes -- 7f89136 tools: kvm_stat: Introduce pid monitoring -- c728a6b tools: kvm_stat: Add comments -- 27fb856 Package man page of "kvm_stat" tool - -(cherry picked from commit d4a8e35b84072816c79e23f5d0a69a2145217004) ---- - Makefile | 8 + - redhat/qemu-kvm.spec.template | 7 +- - scripts/kvm/kvm_stat | 1127 +++++++++++++++++++++++++++++++++++++++++ - scripts/kvm/kvm_stat.texi | 55 ++ - 4 files changed, 1196 insertions(+), 1 deletion(-) - create mode 100755 scripts/kvm/kvm_stat - create mode 100644 scripts/kvm/kvm_stat.texi - -diff --git a/Makefile b/Makefile -index ba31124..312ed5e 100644 ---- a/Makefile -+++ b/Makefile -@@ -209,6 +209,9 @@ ifdef BUILD_DOCS - DOCS=qemu-doc.html qemu-doc.txt qemu.1 qemu-img.1 qemu-nbd.8 qemu-ga.8 - DOCS+=docs/interop/qemu-qmp-ref.html docs/interop/qemu-qmp-ref.txt docs/interop/qemu-qmp-ref.7 - DOCS+=docs/interop/qemu-ga-ref.html docs/interop/qemu-ga-ref.txt docs/interop/qemu-ga-ref.7 -+ifdef CONFIG_LINUX -+DOCS+=kvm_stat.1 -+endif - ifdef CONFIG_VIRTFS - DOCS+=fsdev/virtfs-proxy-helper.1 - endif -@@ -727,6 +730,11 @@ html: qemu-doc.html docs/interop/qemu-qmp-ref.html docs/interop/qemu-ga-ref.html - info: qemu-doc.info docs/interop/qemu-qmp-ref.info docs/interop/qemu-ga-ref.info - pdf: qemu-doc.pdf docs/interop/qemu-qmp-ref.pdf docs/interop/qemu-ga-ref.pdf - txt: qemu-doc.txt docs/interop/qemu-qmp-ref.txt docs/interop/qemu-ga-ref.txt -+kvm_stat.1: scripts/kvm/kvm_stat.texi -+ $(call quiet-command, \ -+ perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< kvm_stat.pod && \ -+ $(POD2MAN) --section=1 --center=" " --release=" " kvm_stat.pod > $@, \ -+ " GEN $@") - - qemu-doc.html qemu-doc.info qemu-doc.pdf qemu-doc.txt: \ - qemu-img.texi qemu-nbd.texi qemu-options.texi qemu-option-trace.texi \ -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -new file mode 100755 -index 0000000..581278c ---- /dev/null -+++ b/scripts/kvm/kvm_stat -@@ -0,0 +1,1127 @@ -+#!/usr/bin/python -+# -+# top-like utility for displaying kvm statistics -+# -+# Copyright 2006-2008 Qumranet Technologies -+# Copyright 2008-2011 Red Hat, Inc. -+# -+# Authors: -+# Avi Kivity -+# -+# This work is licensed under the terms of the GNU GPL, version 2. See -+# the COPYING file in the top-level directory. -+"""The kvm_stat module outputs statistics about running KVM VMs -+ -+Three different ways of output formatting are available: -+- as a top-like text ui -+- in a key -> value format -+- in an all keys, all values format -+ -+The data is sampled from the KVM's debugfs entries and its perf events. -+""" -+ -+import curses -+import sys -+import os -+import time -+import optparse -+import ctypes -+import fcntl -+import resource -+import struct -+import re -+from collections import defaultdict -+from time import sleep -+ -+VMX_EXIT_REASONS = { -+ 'EXCEPTION_NMI': 0, -+ 'EXTERNAL_INTERRUPT': 1, -+ 'TRIPLE_FAULT': 2, -+ 'PENDING_INTERRUPT': 7, -+ 'NMI_WINDOW': 8, -+ 'TASK_SWITCH': 9, -+ 'CPUID': 10, -+ 'HLT': 12, -+ 'INVLPG': 14, -+ 'RDPMC': 15, -+ 'RDTSC': 16, -+ 'VMCALL': 18, -+ 'VMCLEAR': 19, -+ 'VMLAUNCH': 20, -+ 'VMPTRLD': 21, -+ 'VMPTRST': 22, -+ 'VMREAD': 23, -+ 'VMRESUME': 24, -+ 'VMWRITE': 25, -+ 'VMOFF': 26, -+ 'VMON': 27, -+ 'CR_ACCESS': 28, -+ 'DR_ACCESS': 29, -+ 'IO_INSTRUCTION': 30, -+ 'MSR_READ': 31, -+ 'MSR_WRITE': 32, -+ 'INVALID_STATE': 33, -+ 'MWAIT_INSTRUCTION': 36, -+ 'MONITOR_INSTRUCTION': 39, -+ 'PAUSE_INSTRUCTION': 40, -+ 'MCE_DURING_VMENTRY': 41, -+ 'TPR_BELOW_THRESHOLD': 43, -+ 'APIC_ACCESS': 44, -+ 'EPT_VIOLATION': 48, -+ 'EPT_MISCONFIG': 49, -+ 'WBINVD': 54, -+ 'XSETBV': 55, -+ 'APIC_WRITE': 56, -+ 'INVPCID': 58, -+} -+ -+SVM_EXIT_REASONS = { -+ 'READ_CR0': 0x000, -+ 'READ_CR3': 0x003, -+ 'READ_CR4': 0x004, -+ 'READ_CR8': 0x008, -+ 'WRITE_CR0': 0x010, -+ 'WRITE_CR3': 0x013, -+ 'WRITE_CR4': 0x014, -+ 'WRITE_CR8': 0x018, -+ 'READ_DR0': 0x020, -+ 'READ_DR1': 0x021, -+ 'READ_DR2': 0x022, -+ 'READ_DR3': 0x023, -+ 'READ_DR4': 0x024, -+ 'READ_DR5': 0x025, -+ 'READ_DR6': 0x026, -+ 'READ_DR7': 0x027, -+ 'WRITE_DR0': 0x030, -+ 'WRITE_DR1': 0x031, -+ 'WRITE_DR2': 0x032, -+ 'WRITE_DR3': 0x033, -+ 'WRITE_DR4': 0x034, -+ 'WRITE_DR5': 0x035, -+ 'WRITE_DR6': 0x036, -+ 'WRITE_DR7': 0x037, -+ 'EXCP_BASE': 0x040, -+ 'INTR': 0x060, -+ 'NMI': 0x061, -+ 'SMI': 0x062, -+ 'INIT': 0x063, -+ 'VINTR': 0x064, -+ 'CR0_SEL_WRITE': 0x065, -+ 'IDTR_READ': 0x066, -+ 'GDTR_READ': 0x067, -+ 'LDTR_READ': 0x068, -+ 'TR_READ': 0x069, -+ 'IDTR_WRITE': 0x06a, -+ 'GDTR_WRITE': 0x06b, -+ 'LDTR_WRITE': 0x06c, -+ 'TR_WRITE': 0x06d, -+ 'RDTSC': 0x06e, -+ 'RDPMC': 0x06f, -+ 'PUSHF': 0x070, -+ 'POPF': 0x071, -+ 'CPUID': 0x072, -+ 'RSM': 0x073, -+ 'IRET': 0x074, -+ 'SWINT': 0x075, -+ 'INVD': 0x076, -+ 'PAUSE': 0x077, -+ 'HLT': 0x078, -+ 'INVLPG': 0x079, -+ 'INVLPGA': 0x07a, -+ 'IOIO': 0x07b, -+ 'MSR': 0x07c, -+ 'TASK_SWITCH': 0x07d, -+ 'FERR_FREEZE': 0x07e, -+ 'SHUTDOWN': 0x07f, -+ 'VMRUN': 0x080, -+ 'VMMCALL': 0x081, -+ 'VMLOAD': 0x082, -+ 'VMSAVE': 0x083, -+ 'STGI': 0x084, -+ 'CLGI': 0x085, -+ 'SKINIT': 0x086, -+ 'RDTSCP': 0x087, -+ 'ICEBP': 0x088, -+ 'WBINVD': 0x089, -+ 'MONITOR': 0x08a, -+ 'MWAIT': 0x08b, -+ 'MWAIT_COND': 0x08c, -+ 'XSETBV': 0x08d, -+ 'NPF': 0x400, -+} -+ -+# EC definition of HSR (from arch/arm64/include/asm/kvm_arm.h) -+AARCH64_EXIT_REASONS = { -+ 'UNKNOWN': 0x00, -+ 'WFI': 0x01, -+ 'CP15_32': 0x03, -+ 'CP15_64': 0x04, -+ 'CP14_MR': 0x05, -+ 'CP14_LS': 0x06, -+ 'FP_ASIMD': 0x07, -+ 'CP10_ID': 0x08, -+ 'CP14_64': 0x0C, -+ 'ILL_ISS': 0x0E, -+ 'SVC32': 0x11, -+ 'HVC32': 0x12, -+ 'SMC32': 0x13, -+ 'SVC64': 0x15, -+ 'HVC64': 0x16, -+ 'SMC64': 0x17, -+ 'SYS64': 0x18, -+ 'IABT': 0x20, -+ 'IABT_HYP': 0x21, -+ 'PC_ALIGN': 0x22, -+ 'DABT': 0x24, -+ 'DABT_HYP': 0x25, -+ 'SP_ALIGN': 0x26, -+ 'FP_EXC32': 0x28, -+ 'FP_EXC64': 0x2C, -+ 'SERROR': 0x2F, -+ 'BREAKPT': 0x30, -+ 'BREAKPT_HYP': 0x31, -+ 'SOFTSTP': 0x32, -+ 'SOFTSTP_HYP': 0x33, -+ 'WATCHPT': 0x34, -+ 'WATCHPT_HYP': 0x35, -+ 'BKPT32': 0x38, -+ 'VECTOR32': 0x3A, -+ 'BRK64': 0x3C, -+} -+ -+# From include/uapi/linux/kvm.h, KVM_EXIT_xxx -+USERSPACE_EXIT_REASONS = { -+ 'UNKNOWN': 0, -+ 'EXCEPTION': 1, -+ 'IO': 2, -+ 'HYPERCALL': 3, -+ 'DEBUG': 4, -+ 'HLT': 5, -+ 'MMIO': 6, -+ 'IRQ_WINDOW_OPEN': 7, -+ 'SHUTDOWN': 8, -+ 'FAIL_ENTRY': 9, -+ 'INTR': 10, -+ 'SET_TPR': 11, -+ 'TPR_ACCESS': 12, -+ 'S390_SIEIC': 13, -+ 'S390_RESET': 14, -+ 'DCR': 15, -+ 'NMI': 16, -+ 'INTERNAL_ERROR': 17, -+ 'OSI': 18, -+ 'PAPR_HCALL': 19, -+ 'S390_UCONTROL': 20, -+ 'WATCHDOG': 21, -+ 'S390_TSCH': 22, -+ 'EPR': 23, -+ 'SYSTEM_EVENT': 24, -+} -+ -+IOCTL_NUMBERS = { -+ 'SET_FILTER': 0x40082406, -+ 'ENABLE': 0x00002400, -+ 'DISABLE': 0x00002401, -+ 'RESET': 0x00002403, -+} -+ -+class Arch(object): -+ """Encapsulates global architecture specific data. -+ -+ Contains the performance event open syscall and ioctl numbers, as -+ well as the VM exit reasons for the architecture it runs on. -+ -+ """ -+ @staticmethod -+ def get_arch(): -+ machine = os.uname()[4] -+ -+ if machine.startswith('ppc'): -+ return ArchPPC() -+ elif machine.startswith('aarch64'): -+ return ArchA64() -+ elif machine.startswith('s390'): -+ return ArchS390() -+ else: -+ # X86_64 -+ for line in open('/proc/cpuinfo'): -+ if not line.startswith('flags'): -+ continue -+ -+ flags = line.split() -+ if 'vmx' in flags: -+ return ArchX86(VMX_EXIT_REASONS) -+ if 'svm' in flags: -+ return ArchX86(SVM_EXIT_REASONS) -+ return -+ -+class ArchX86(Arch): -+ def __init__(self, exit_reasons): -+ self.sc_perf_evt_open = 298 -+ self.ioctl_numbers = IOCTL_NUMBERS -+ self.exit_reasons = exit_reasons -+ -+class ArchPPC(Arch): -+ def __init__(self): -+ self.sc_perf_evt_open = 319 -+ self.ioctl_numbers = IOCTL_NUMBERS -+ self.ioctl_numbers['ENABLE'] = 0x20002400 -+ self.ioctl_numbers['DISABLE'] = 0x20002401 -+ self.ioctl_numbers['RESET'] = 0x20002403 -+ -+ # PPC comes in 32 and 64 bit and some generated ioctl -+ # numbers depend on the wordsize. -+ char_ptr_size = ctypes.sizeof(ctypes.c_char_p) -+ self.ioctl_numbers['SET_FILTER'] = 0x80002406 | char_ptr_size << 16 -+ self.exit_reasons = {} -+ -+class ArchA64(Arch): -+ def __init__(self): -+ self.sc_perf_evt_open = 241 -+ self.ioctl_numbers = IOCTL_NUMBERS -+ self.exit_reasons = AARCH64_EXIT_REASONS -+ -+class ArchS390(Arch): -+ def __init__(self): -+ self.sc_perf_evt_open = 331 -+ self.ioctl_numbers = IOCTL_NUMBERS -+ self.exit_reasons = None -+ -+ARCH = Arch.get_arch() -+ -+ -+def walkdir(path): -+ """Returns os.walk() data for specified directory. -+ -+ As it is only a wrapper it returns the same 3-tuple of (dirpath, -+ dirnames, filenames). -+ """ -+ return next(os.walk(path)) -+ -+ -+def parse_int_list(list_string): -+ """Returns an int list from a string of comma separated integers and -+ integer ranges.""" -+ integers = [] -+ members = list_string.split(',') -+ -+ for member in members: -+ if '-' not in member: -+ integers.append(int(member)) -+ else: -+ int_range = member.split('-') -+ integers.extend(range(int(int_range[0]), -+ int(int_range[1]) + 1)) -+ -+ return integers -+ -+ -+def get_online_cpus(): -+ """Returns a list of cpu id integers.""" -+ with open('/sys/devices/system/cpu/online') as cpu_list: -+ cpu_string = cpu_list.readline() -+ return parse_int_list(cpu_string) -+ -+ -+def get_filters(): -+ """Returns a dict of trace events, their filter ids and -+ the values that can be filtered. -+ -+ Trace events can be filtered for special values by setting a -+ filter string via an ioctl. The string normally has the format -+ identifier==value. For each filter a new event will be created, to -+ be able to distinguish the events. -+ -+ """ -+ filters = {} -+ filters['kvm_userspace_exit'] = ('reason', USERSPACE_EXIT_REASONS) -+ if ARCH.exit_reasons: -+ filters['kvm_exit'] = ('exit_reason', ARCH.exit_reasons) -+ return filters -+ -+libc = ctypes.CDLL('libc.so.6', use_errno=True) -+syscall = libc.syscall -+ -+class perf_event_attr(ctypes.Structure): -+ """Struct that holds the necessary data to set up a trace event. -+ -+ For an extensive explanation see perf_event_open(2) and -+ include/uapi/linux/perf_event.h, struct perf_event_attr -+ -+ All fields that are not initialized in the constructor are 0. -+ -+ """ -+ _fields_ = [('type', ctypes.c_uint32), -+ ('size', ctypes.c_uint32), -+ ('config', ctypes.c_uint64), -+ ('sample_freq', ctypes.c_uint64), -+ ('sample_type', ctypes.c_uint64), -+ ('read_format', ctypes.c_uint64), -+ ('flags', ctypes.c_uint64), -+ ('wakeup_events', ctypes.c_uint32), -+ ('bp_type', ctypes.c_uint32), -+ ('bp_addr', ctypes.c_uint64), -+ ('bp_len', ctypes.c_uint64), -+ ] -+ -+ def __init__(self): -+ super(self.__class__, self).__init__() -+ self.type = PERF_TYPE_TRACEPOINT -+ self.size = ctypes.sizeof(self) -+ self.read_format = PERF_FORMAT_GROUP -+ -+def perf_event_open(attr, pid, cpu, group_fd, flags): -+ """Wrapper for the sys_perf_evt_open() syscall. -+ -+ Used to set up performance events, returns a file descriptor or -1 -+ on error. -+ -+ Attributes are: -+ - syscall number -+ - struct perf_event_attr * -+ - pid or -1 to monitor all pids -+ - cpu number or -1 to monitor all cpus -+ - The file descriptor of the group leader or -1 to create a group. -+ - flags -+ -+ """ -+ return syscall(ARCH.sc_perf_evt_open, ctypes.pointer(attr), -+ ctypes.c_int(pid), ctypes.c_int(cpu), -+ ctypes.c_int(group_fd), ctypes.c_long(flags)) -+ -+PERF_TYPE_TRACEPOINT = 2 -+PERF_FORMAT_GROUP = 1 << 3 -+ -+PATH_DEBUGFS_TRACING = '/sys/kernel/debug/tracing' -+PATH_DEBUGFS_KVM = '/sys/kernel/debug/kvm' -+ -+class Group(object): -+ """Represents a perf event group.""" -+ -+ def __init__(self): -+ self.events = [] -+ -+ def add_event(self, event): -+ self.events.append(event) -+ -+ def read(self): -+ """Returns a dict with 'event name: value' for all events in the -+ group. -+ -+ Values are read by reading from the file descriptor of the -+ event that is the group leader. See perf_event_open(2) for -+ details. -+ -+ Read format for the used event configuration is: -+ struct read_format { -+ u64 nr; /* The number of events */ -+ struct { -+ u64 value; /* The value of the event */ -+ } values[nr]; -+ }; -+ -+ """ -+ length = 8 * (1 + len(self.events)) -+ read_format = 'xxxxxxxx' + 'Q' * len(self.events) -+ return dict(zip([event.name for event in self.events], -+ struct.unpack(read_format, -+ os.read(self.events[0].fd, length)))) -+ -+class Event(object): -+ """Represents a performance event and manages its life cycle.""" -+ def __init__(self, name, group, trace_cpu, trace_pid, trace_point, -+ trace_filter, trace_set='kvm'): -+ self.name = name -+ self.fd = None -+ self.setup_event(group, trace_cpu, trace_pid, trace_point, -+ trace_filter, trace_set) -+ -+ def __del__(self): -+ """Closes the event's file descriptor. -+ -+ As no python file object was created for the file descriptor, -+ python will not reference count the descriptor and will not -+ close it itself automatically, so we do it. -+ -+ """ -+ if self.fd: -+ os.close(self.fd) -+ -+ def setup_event_attribute(self, trace_set, trace_point): -+ """Returns an initialized ctype perf_event_attr struct.""" -+ -+ id_path = os.path.join(PATH_DEBUGFS_TRACING, 'events', trace_set, -+ trace_point, 'id') -+ -+ event_attr = perf_event_attr() -+ event_attr.config = int(open(id_path).read()) -+ return event_attr -+ -+ def setup_event(self, group, trace_cpu, trace_pid, trace_point, -+ trace_filter, trace_set): -+ """Sets up the perf event in Linux. -+ -+ Issues the syscall to register the event in the kernel and -+ then sets the optional filter. -+ -+ """ -+ -+ event_attr = self.setup_event_attribute(trace_set, trace_point) -+ -+ # First event will be group leader. -+ group_leader = -1 -+ -+ # All others have to pass the leader's descriptor instead. -+ if group.events: -+ group_leader = group.events[0].fd -+ -+ fd = perf_event_open(event_attr, trace_pid, -+ trace_cpu, group_leader, 0) -+ if fd == -1: -+ err = ctypes.get_errno() -+ raise OSError(err, os.strerror(err), -+ 'while calling sys_perf_event_open().') -+ -+ if trace_filter: -+ fcntl.ioctl(fd, ARCH.ioctl_numbers['SET_FILTER'], -+ trace_filter) -+ -+ self.fd = fd -+ -+ def enable(self): -+ """Enables the trace event in the kernel. -+ -+ Enabling the group leader makes reading counters from it and the -+ events under it possible. -+ -+ """ -+ fcntl.ioctl(self.fd, ARCH.ioctl_numbers['ENABLE'], 0) -+ -+ def disable(self): -+ """Disables the trace event in the kernel. -+ -+ Disabling the group leader makes reading all counters under it -+ impossible. -+ -+ """ -+ fcntl.ioctl(self.fd, ARCH.ioctl_numbers['DISABLE'], 0) -+ -+ def reset(self): -+ """Resets the count of the trace event in the kernel.""" -+ fcntl.ioctl(self.fd, ARCH.ioctl_numbers['RESET'], 0) -+ -+class TracepointProvider(object): -+ """Data provider for the stats class. -+ -+ Manages the events/groups from which it acquires its data. -+ -+ """ -+ def __init__(self): -+ self.group_leaders = [] -+ self.filters = get_filters() -+ self._fields = self.get_available_fields() -+ self._pid = 0 -+ -+ def get_available_fields(self): -+ """Returns a list of available event's of format 'event name(filter -+ name)'. -+ -+ All available events have directories under -+ /sys/kernel/debug/tracing/events/ which export information -+ about the specific event. Therefore, listing the dirs gives us -+ a list of all available events. -+ -+ Some events like the vm exit reasons can be filtered for -+ specific values. To take account for that, the routine below -+ creates special fields with the following format: -+ event name(filter name) -+ -+ """ -+ path = os.path.join(PATH_DEBUGFS_TRACING, 'events', 'kvm') -+ fields = walkdir(path)[1] -+ extra = [] -+ for field in fields: -+ if field in self.filters: -+ filter_name_, filter_dicts = self.filters[field] -+ for name in filter_dicts: -+ extra.append(field + '(' + name + ')') -+ fields += extra -+ return fields -+ -+ def setup_traces(self): -+ """Creates all event and group objects needed to be able to retrieve -+ data.""" -+ if self._pid > 0: -+ # Fetch list of all threads of the monitored pid, as qemu -+ # starts a thread for each vcpu. -+ path = os.path.join('/proc', str(self._pid), 'task') -+ groupids = walkdir(path)[1] -+ else: -+ groupids = get_online_cpus() -+ -+ # The constant is needed as a buffer for python libs, std -+ # streams and other files that the script opens. -+ newlim = len(groupids) * len(self._fields) + 50 -+ try: -+ softlim_, hardlim = resource.getrlimit(resource.RLIMIT_NOFILE) -+ -+ if hardlim < newlim: -+ # Now we need CAP_SYS_RESOURCE, to increase the hard limit. -+ resource.setrlimit(resource.RLIMIT_NOFILE, (newlim, newlim)) -+ else: -+ # Raising the soft limit is sufficient. -+ resource.setrlimit(resource.RLIMIT_NOFILE, (newlim, hardlim)) -+ -+ except ValueError: -+ sys.exit("NOFILE rlimit could not be raised to {0}".format(newlim)) -+ -+ for groupid in groupids: -+ group = Group() -+ for name in self._fields: -+ tracepoint = name -+ tracefilter = None -+ match = re.match(r'(.*)\((.*)\)', name) -+ if match: -+ tracepoint, sub = match.groups() -+ tracefilter = ('%s==%d\0' % -+ (self.filters[tracepoint][0], -+ self.filters[tracepoint][1][sub])) -+ -+ # From perf_event_open(2): -+ # pid > 0 and cpu == -1 -+ # This measures the specified process/thread on any CPU. -+ # -+ # pid == -1 and cpu >= 0 -+ # This measures all processes/threads on the specified CPU. -+ trace_cpu = groupid if self._pid == 0 else -1 -+ trace_pid = int(groupid) if self._pid != 0 else -1 -+ -+ group.add_event(Event(name=name, -+ group=group, -+ trace_cpu=trace_cpu, -+ trace_pid=trace_pid, -+ trace_point=tracepoint, -+ trace_filter=tracefilter)) -+ -+ self.group_leaders.append(group) -+ -+ def available_fields(self): -+ return self.get_available_fields() -+ -+ @property -+ def fields(self): -+ return self._fields -+ -+ @fields.setter -+ def fields(self, fields): -+ """Enables/disables the (un)wanted events""" -+ self._fields = fields -+ for group in self.group_leaders: -+ for index, event in enumerate(group.events): -+ if event.name in fields: -+ event.reset() -+ event.enable() -+ else: -+ # Do not disable the group leader. -+ # It would disable all of its events. -+ if index != 0: -+ event.disable() -+ -+ @property -+ def pid(self): -+ return self._pid -+ -+ @pid.setter -+ def pid(self, pid): -+ """Changes the monitored pid by setting new traces.""" -+ self._pid = pid -+ # The garbage collector will get rid of all Event/Group -+ # objects and open files after removing the references. -+ self.group_leaders = [] -+ self.setup_traces() -+ self.fields = self._fields -+ -+ def read(self): -+ """Returns 'event name: current value' for all enabled events.""" -+ ret = defaultdict(int) -+ for group in self.group_leaders: -+ for name, val in group.read().iteritems(): -+ if name in self._fields: -+ ret[name] += val -+ return ret -+ -+class DebugfsProvider(object): -+ """Provides data from the files that KVM creates in the kvm debugfs -+ folder.""" -+ def __init__(self): -+ self._fields = self.get_available_fields() -+ self._pid = 0 -+ self.do_read = True -+ -+ def get_available_fields(self): -+ """"Returns a list of available fields. -+ -+ The fields are all available KVM debugfs files -+ -+ """ -+ return walkdir(PATH_DEBUGFS_KVM)[2] -+ -+ @property -+ def fields(self): -+ return self._fields -+ -+ @fields.setter -+ def fields(self, fields): -+ self._fields = fields -+ -+ @property -+ def pid(self): -+ return self._pid -+ -+ @pid.setter -+ def pid(self, pid): -+ if pid != 0: -+ self._pid = pid -+ -+ vms = walkdir(PATH_DEBUGFS_KVM)[1] -+ if len(vms) == 0: -+ self.do_read = False -+ -+ self.paths = filter(lambda x: "{}-".format(pid) in x, vms) -+ -+ else: -+ self.paths = [''] -+ self.do_read = True -+ -+ def read(self): -+ """Returns a dict with format:'file name / field -> current value'.""" -+ results = {} -+ -+ # If no debugfs filtering support is available, then don't read. -+ if not self.do_read: -+ return results -+ -+ for path in self.paths: -+ for field in self._fields: -+ results[field] = results.get(field, 0) \ -+ + self.read_field(field, path) -+ -+ return results -+ -+ def read_field(self, field, path): -+ """Returns the value of a single field from a specific VM.""" -+ try: -+ return int(open(os.path.join(PATH_DEBUGFS_KVM, -+ path, -+ field)) -+ .read()) -+ except IOError: -+ return 0 -+ -+class Stats(object): -+ """Manages the data providers and the data they provide. -+ -+ It is used to set filters on the provider's data and collect all -+ provider data. -+ -+ """ -+ def __init__(self, providers, pid, fields=None): -+ self.providers = providers -+ self._pid_filter = pid -+ self._fields_filter = fields -+ self.values = {} -+ self.update_provider_pid() -+ self.update_provider_filters() -+ -+ def update_provider_filters(self): -+ """Propagates fields filters to providers.""" -+ def wanted(key): -+ if not self._fields_filter: -+ return True -+ return re.match(self._fields_filter, key) is not None -+ -+ # As we reset the counters when updating the fields we can -+ # also clear the cache of old values. -+ self.values = {} -+ for provider in self.providers: -+ provider_fields = [key for key in provider.get_available_fields() -+ if wanted(key)] -+ provider.fields = provider_fields -+ -+ def update_provider_pid(self): -+ """Propagates pid filters to providers.""" -+ for provider in self.providers: -+ provider.pid = self._pid_filter -+ -+ @property -+ def fields_filter(self): -+ return self._fields_filter -+ -+ @fields_filter.setter -+ def fields_filter(self, fields_filter): -+ self._fields_filter = fields_filter -+ self.update_provider_filters() -+ -+ @property -+ def pid_filter(self): -+ return self._pid_filter -+ -+ @pid_filter.setter -+ def pid_filter(self, pid): -+ self._pid_filter = pid -+ self.values = {} -+ self.update_provider_pid() -+ -+ def get(self): -+ """Returns a dict with field -> (value, delta to last value) of all -+ provider data.""" -+ for provider in self.providers: -+ new = provider.read() -+ for key in provider.fields: -+ oldval = self.values.get(key, (0, 0)) -+ newval = new.get(key, 0) -+ newdelta = None -+ if oldval is not None: -+ newdelta = newval - oldval[0] -+ self.values[key] = (newval, newdelta) -+ return self.values -+ -+LABEL_WIDTH = 40 -+NUMBER_WIDTH = 10 -+ -+class Tui(object): -+ """Instruments curses to draw a nice text ui.""" -+ def __init__(self, stats): -+ self.stats = stats -+ self.screen = None -+ self.drilldown = False -+ self.update_drilldown() -+ -+ def __enter__(self): -+ """Initialises curses for later use. Based on curses.wrapper -+ implementation from the Python standard library.""" -+ self.screen = curses.initscr() -+ curses.noecho() -+ curses.cbreak() -+ -+ # The try/catch works around a minor bit of -+ # over-conscientiousness in the curses module, the error -+ # return from C start_color() is ignorable. -+ try: -+ curses.start_color() -+ except: -+ pass -+ -+ curses.use_default_colors() -+ return self -+ -+ def __exit__(self, *exception): -+ """Resets the terminal to its normal state. Based on curses.wrappre -+ implementation from the Python standard library.""" -+ if self.screen: -+ self.screen.keypad(0) -+ curses.echo() -+ curses.nocbreak() -+ curses.endwin() -+ -+ def update_drilldown(self): -+ """Sets or removes a filter that only allows fields without braces.""" -+ if not self.stats.fields_filter: -+ self.stats.fields_filter = r'^[^\(]*$' -+ -+ elif self.stats.fields_filter == r'^[^\(]*$': -+ self.stats.fields_filter = None -+ -+ def update_pid(self, pid): -+ """Propagates pid selection to stats object.""" -+ self.stats.pid_filter = pid -+ -+ def refresh(self, sleeptime): -+ """Refreshes on-screen data.""" -+ self.screen.erase() -+ if self.stats.pid_filter > 0: -+ self.screen.addstr(0, 0, 'kvm statistics - pid {0}' -+ .format(self.stats.pid_filter), -+ curses.A_BOLD) -+ else: -+ self.screen.addstr(0, 0, 'kvm statistics - summary', curses.A_BOLD) -+ self.screen.addstr(2, 1, 'Event') -+ self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH - -+ len('Total'), 'Total') -+ self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH + 8 - -+ len('Current'), 'Current') -+ row = 3 -+ stats = self.stats.get() -+ def sortkey(x): -+ if stats[x][1]: -+ return (-stats[x][1], -stats[x][0]) -+ else: -+ return (0, -stats[x][0]) -+ for key in sorted(stats.keys(), key=sortkey): -+ -+ if row >= self.screen.getmaxyx()[0]: -+ break -+ values = stats[key] -+ if not values[0] and not values[1]: -+ break -+ col = 1 -+ self.screen.addstr(row, col, key) -+ col += LABEL_WIDTH -+ self.screen.addstr(row, col, '%10d' % (values[0],)) -+ col += NUMBER_WIDTH -+ if values[1] is not None: -+ self.screen.addstr(row, col, '%8d' % (values[1] / sleeptime,)) -+ row += 1 -+ self.screen.refresh() -+ -+ def show_filter_selection(self): -+ """Draws filter selection mask. -+ -+ Asks for a valid regex and sets the fields filter accordingly. -+ -+ """ -+ while True: -+ self.screen.erase() -+ self.screen.addstr(0, 0, -+ "Show statistics for events matching a regex.", -+ curses.A_BOLD) -+ self.screen.addstr(2, 0, -+ "Current regex: {0}" -+ .format(self.stats.fields_filter)) -+ self.screen.addstr(3, 0, "New regex: ") -+ curses.echo() -+ regex = self.screen.getstr() -+ curses.noecho() -+ if len(regex) == 0: -+ return -+ try: -+ re.compile(regex) -+ self.stats.fields_filter = regex -+ return -+ except re.error: -+ continue -+ -+ def show_vm_selection(self): -+ """Draws PID selection mask. -+ -+ Asks for a pid until a valid pid or 0 has been entered. -+ -+ """ -+ while True: -+ self.screen.erase() -+ self.screen.addstr(0, 0, -+ 'Show statistics for specific pid.', -+ curses.A_BOLD) -+ self.screen.addstr(1, 0, -+ 'This might limit the shown data to the trace ' -+ 'statistics.') -+ -+ curses.echo() -+ self.screen.addstr(3, 0, "Pid [0 or pid]: ") -+ pid = self.screen.getstr() -+ curses.noecho() -+ -+ try: -+ pid = int(pid) -+ -+ if pid == 0: -+ self.update_pid(pid) -+ break -+ else: -+ if not os.path.isdir(os.path.join('/proc/', str(pid))): -+ continue -+ else: -+ self.update_pid(pid) -+ break -+ -+ except ValueError: -+ continue -+ -+ def show_stats(self): -+ """Refreshes the screen and processes user input.""" -+ sleeptime = 0.25 -+ while True: -+ self.refresh(sleeptime) -+ curses.halfdelay(int(sleeptime * 10)) -+ sleeptime = 3 -+ try: -+ char = self.screen.getkey() -+ if char == 'x': -+ self.drilldown = not self.drilldown -+ self.update_drilldown() -+ if char == 'q': -+ break -+ if char == 'f': -+ self.show_filter_selection() -+ if char == 'p': -+ self.show_vm_selection() -+ except KeyboardInterrupt: -+ break -+ except curses.error: -+ continue -+ -+def batch(stats): -+ """Prints statistics in a key, value format.""" -+ s = stats.get() -+ time.sleep(1) -+ s = stats.get() -+ for key in sorted(s.keys()): -+ values = s[key] -+ print '%-42s%10d%10d' % (key, values[0], values[1]) -+ -+def log(stats): -+ """Prints statistics as reiterating key block, multiple value blocks.""" -+ keys = sorted(stats.get().iterkeys()) -+ def banner(): -+ for k in keys: -+ print '%s' % k, -+ print -+ def statline(): -+ s = stats.get() -+ for k in keys: -+ print ' %9d' % s[k][1], -+ print -+ line = 0 -+ banner_repeat = 20 -+ while True: -+ time.sleep(1) -+ if line % banner_repeat == 0: -+ banner() -+ statline() -+ line += 1 -+ -+def get_options(): -+ """Returns processed program arguments.""" -+ description_text = """ -+This script displays various statistics about VMs running under KVM. -+The statistics are gathered from the KVM debugfs entries and / or the -+currently available perf traces. -+ -+The monitoring takes additional cpu cycles and might affect the VM's -+performance. -+ -+Requirements: -+- Access to: -+ /sys/kernel/debug/kvm -+ /sys/kernel/debug/trace/events/* -+ /proc/pid/task -+- /proc/sys/kernel/perf_event_paranoid < 1 if user has no -+ CAP_SYS_ADMIN and perf events are used. -+- CAP_SYS_RESOURCE if the hard limit is not high enough to allow -+ the large number of files that are possibly opened. -+""" -+ -+ class PlainHelpFormatter(optparse.IndentedHelpFormatter): -+ def format_description(self, description): -+ if description: -+ return description + "\n" -+ else: -+ return "" -+ -+ optparser = optparse.OptionParser(description=description_text, -+ formatter=PlainHelpFormatter()) -+ optparser.add_option('-1', '--once', '--batch', -+ action='store_true', -+ default=False, -+ dest='once', -+ help='run in batch mode for one second', -+ ) -+ optparser.add_option('-l', '--log', -+ action='store_true', -+ default=False, -+ dest='log', -+ help='run in logging mode (like vmstat)', -+ ) -+ optparser.add_option('-t', '--tracepoints', -+ action='store_true', -+ default=False, -+ dest='tracepoints', -+ help='retrieve statistics from tracepoints', -+ ) -+ optparser.add_option('-d', '--debugfs', -+ action='store_true', -+ default=False, -+ dest='debugfs', -+ help='retrieve statistics from debugfs', -+ ) -+ optparser.add_option('-f', '--fields', -+ action='store', -+ default=None, -+ dest='fields', -+ help='fields to display (regex)', -+ ) -+ optparser.add_option('-p', '--pid', -+ action='store', -+ default=0, -+ type=int, -+ dest='pid', -+ help='restrict statistics to pid', -+ ) -+ (options, _) = optparser.parse_args(sys.argv) -+ return options -+ -+def get_providers(options): -+ """Returns a list of data providers depending on the passed options.""" -+ providers = [] -+ -+ if options.tracepoints: -+ providers.append(TracepointProvider()) -+ if options.debugfs: -+ providers.append(DebugfsProvider()) -+ if len(providers) == 0: -+ providers.append(TracepointProvider()) -+ -+ return providers -+ -+def check_access(options): -+ """Exits if the current user can't access all needed directories.""" -+ if not os.path.exists('/sys/kernel/debug'): -+ sys.stderr.write('Please enable CONFIG_DEBUG_FS in your kernel.') -+ sys.exit(1) -+ -+ if not os.path.exists(PATH_DEBUGFS_KVM): -+ sys.stderr.write("Please make sure, that debugfs is mounted and " -+ "readable by the current user:\n" -+ "('mount -t debugfs debugfs /sys/kernel/debug')\n" -+ "Also ensure, that the kvm modules are loaded.\n") -+ sys.exit(1) -+ -+ if not os.path.exists(PATH_DEBUGFS_TRACING) and (options.tracepoints -+ or not options.debugfs): -+ sys.stderr.write("Please enable CONFIG_TRACING in your kernel " -+ "when using the option -t (default).\n" -+ "If it is enabled, make {0} readable by the " -+ "current user.\n" -+ .format(PATH_DEBUGFS_TRACING)) -+ if options.tracepoints: -+ sys.exit(1) -+ -+ sys.stderr.write("Falling back to debugfs statistics!\n") -+ options.debugfs = True -+ sleep(5) -+ -+ return options -+ -+def main(): -+ options = get_options() -+ options = check_access(options) -+ -+ if (options.pid > 0 and -+ not os.path.isdir(os.path.join('/proc/', -+ str(options.pid)))): -+ sys.stderr.write('Did you use a (unsupported) tid instead of a pid?\n') -+ sys.exit('Specified pid does not exist.') -+ -+ providers = get_providers(options) -+ stats = Stats(providers, options.pid, fields=options.fields) -+ -+ if options.log: -+ log(stats) -+ elif not options.once: -+ with Tui(stats) as tui: -+ tui.show_stats() -+ else: -+ batch(stats) -+ -+if __name__ == "__main__": -+ main() -diff --git a/scripts/kvm/kvm_stat.texi b/scripts/kvm/kvm_stat.texi -new file mode 100644 -index 0000000..4faf1a6 ---- /dev/null -+++ b/scripts/kvm/kvm_stat.texi -@@ -0,0 +1,55 @@ -+@example -+@c man begin SYNOPSIS -+usage: kvm_stat [OPTION]... -+@c man end -+@end example -+ -+@c man begin DESCRIPTION -+ -+kvm_stat prints counts of KVM kernel module trace events. These events signify -+state transitions such as guest mode entry and exit. -+ -+This tool is useful for observing guest behavior from the host perspective. -+Often conclusions about performance or buggy behavior can be drawn from the -+output. -+ -+The set of KVM kernel module trace events may be specific to the kernel version -+or architecture. It is best to check the KVM kernel module source code for the -+meaning of events. -+ -+@c man end -+ -+@c man begin OPTIONS -+@table @option -+@item -1, --once, --batch -+ run in batch mode for one second -+@item -l, --log -+ run in logging mode (like vmstat) -+@item -t, --tracepoints -+ retrieve statistics from tracepoints -+@item -d, --debugfs -+ retrieve statistics from debugfs -+@item -p, --pid=@var{pid} -+ limit statistics to one virtual machine (pid) -+@item -f, --fields=@var{fields} -+ fields to display (regex) -+@item -h, --help -+ show help message -+@end table -+ -+@c man end -+ -+@ignore -+ -+@setfilename kvm_stat -+@settitle Report KVM kernel module event counters. -+ -+@c man begin AUTHOR -+Stefan Hajnoczi -+@c man end -+ -+@c man begin SEEALSO -+perf(1), trace-cmd(1) -+@c man end -+ -+@end ignore --- -1.8.3.1 - diff --git a/SOURCES/0027-virtio-scsi-Reject-scsi-cd-if-data-plane-enabled-RHE.patch b/SOURCES/0027-virtio-scsi-Reject-scsi-cd-if-data-plane-enabled-RHE.patch new file mode 100644 index 0000000..4d9b5f3 --- /dev/null +++ b/SOURCES/0027-virtio-scsi-Reject-scsi-cd-if-data-plane-enabled-RHE.patch @@ -0,0 +1,70 @@ +From db9aa5263282c293ffd22dd80a273590fcde92f2 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Wed, 14 Jun 2017 15:37:01 +0200 +Subject: virtio-scsi: Reject scsi-cd if data plane enabled [RHEL only] + +RH-Author: Fam Zheng +Message-id: <20170614153701.14757-1-famz@redhat.com> +Patchwork-id: 75613 +O-Subject: [RHV-7.4 qemu-kvm-rhev PATCH v3] virtio-scsi: Reject scsi-cd if data plane enabled [RHEL only] +Bugzilla: 1378816 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz + +We need a fix for RHEL 7.4 and 7.3.z, but unfortunately upstream isn't +ready. If it were, the changes will be too invasive. To have an idea: + +https://lists.gnu.org/archive/html/qemu-devel/2017-05/msg05400.html + +is an incomplete attempt to fix part of the issue, and the remaining +work unfortunately involve even more complex changes. + +As a band-aid, this partially reverts the effect of ef8875b +(virtio-scsi: Remove op blocker for dataplane, since v2.7). We cannot +simply revert that commit as a whole because we already shipped it in +qemu-kvm-rhev 7.3, since when, block jobs has been possible. We should +only block what has been broken. Also, faithfully reverting the above +commit means adding back the removed op blocker, but that is not enough, +because it still crashes when inserting media into an initially empty +scsi-cd. + +All in all, scsi-cd on virtio-scsi-dataplane has basically been unusable +unless the scsi-cd never enters an empty state, so, disable it +altogether. Otherwise it would be much more difficult to avoid +crashing. + +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +(cherry picked from commit b0caf00bbc35c7d89e02999bdce86e1f867728e8) +(cherry picked from commit c9c4f117d8b507c2f86035c282d537c0a327364f) +(cherry picked from commit be16f8328fe109bab1ebc8f17b16b604e6e139d8) +(cherry picked from commit 39884820a2d464918ea383df0519c2de0731b923) +(cherry picked from commit f1e2dabe06a7f4d0b5ef4c96e5ace53b9df14296) +--- + hw/scsi/virtio-scsi.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c +index 3aa9971..9f754c4 100644 +--- a/hw/scsi/virtio-scsi.c ++++ b/hw/scsi/virtio-scsi.c +@@ -790,6 +790,15 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev, + VirtIOSCSI *s = VIRTIO_SCSI(vdev); + SCSIDevice *sd = SCSI_DEVICE(dev); + ++ /* XXX: Remove this check once block backend is capable of handling ++ * AioContext change upon eject/insert. ++ * s->ctx is NULL if ioeventfd is off, s->ctx is qemu_get_aio_context() if ++ * data plane is not used, both cases are safe for scsi-cd. */ ++ if (s->ctx && s->ctx != qemu_get_aio_context() && ++ object_dynamic_cast(OBJECT(dev), "scsi-cd")) { ++ error_setg(errp, "scsi-cd is not supported by data plane"); ++ return; ++ } + if (s->ctx && !s->dataplane_fenced) { + if (blk_op_is_blocked(sd->conf.blk, BLOCK_OP_TYPE_DATAPLANE, errp)) { + return; +-- +1.8.3.1 + diff --git a/SOURCES/0028-migcompat-e1000e-Work-around-7.3-msi-intr_state-fiel.patch b/SOURCES/0028-migcompat-e1000e-Work-around-7.3-msi-intr_state-fiel.patch deleted file mode 100644 index 638b502..0000000 --- a/SOURCES/0028-migcompat-e1000e-Work-around-7.3-msi-intr_state-fiel.patch +++ /dev/null @@ -1,135 +0,0 @@ -From cc306393d79691b82c1f5f660a01bf00fe0775e9 Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Thu, 9 Feb 2017 13:06:18 +0100 -Subject: migcompat/e1000e: Work around 7.3 msi/intr_state field - -RH-Author: Dr. David Alan Gilbert -Message-id: <20170209130618.20328-1-dgilbert@redhat.com> -Patchwork-id: 73730 -O-Subject: [RHEL-7.4 qemu-kvm-rhev PATCH 1/1] migcompat/e1000e: Work around 7.3 msi/intr_state field -Bugzilla: 1420216 -RH-Acked-by: Thomas Huth -RH-Acked-by: Xiao Wang -RH-Acked-by: Miroslav Rezanina - -From: "Dr. David Alan Gilbert" - -bz: https://bugzilla.redhat.com/show_bug.cgi?id=1420216 -brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=12518741 -upstream: No, fixing downstream inconsistency - -Our 7.3 e1000e model has an 'intr_state' field that's used -only in the cleanup of msi & msix. - -e1000e was introducing in 2.7 but was backported to the 2.6 based -qemu-kvm-rhev 7.3 by backporting 6f3fbe4 and 103916. - -During the 2.7rc's the migration structure was changed by -e0af5a0e8 and 66bf7d but we never pulled those into 7.3 which -removed the 'intr_state' field. - -For compatibility add the field back (guarded by a property on 7.3) -and populate the values based on the source MSI state. -Since the flags were only used for cleanup I don't think -we need to pay attention to the value we receive. - -Signed-off-by: Dr. David Alan Gilbert -Signed-off-by: Miroslav Rezanina -(cherry picked from commit 7b3c2e676cd62e947e9b020bba9309a171e94c9e) ---- - hw/net/e1000e.c | 21 +++++++++++++++++++++ - include/hw/compat.h | 4 ++++ - 2 files changed, 25 insertions(+) - -diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c -index 2c91d07..d6ca464 100644 ---- a/hw/net/e1000e.c -+++ b/hw/net/e1000e.c -@@ -74,6 +74,11 @@ typedef struct E1000EState { - - E1000ECore core; - -+ /* 7.3 had the intr_state field that was in the original e1000e code -+ * but that was removed prior to 2.7's release -+ */ -+ bool redhat_7_3_intr_state_enable; -+ uint32_t redhat_7_3_intr_state; - } E1000EState; - - #define E1000E_MMIO_IDX 0 -@@ -89,6 +94,10 @@ typedef struct E1000EState { - #define E1000E_MSIX_TABLE (0x0000) - #define E1000E_MSIX_PBA (0x2000) - -+/* Values as in RHEL 7.3 build and original upstream */ -+#define RH_E1000E_USE_MSI BIT(0) -+#define RH_E1000E_USE_MSIX BIT(1) -+ - static uint64_t - e1000e_mmio_read(void *opaque, hwaddr addr, unsigned size) - { -@@ -300,6 +309,8 @@ e1000e_init_msix(E1000EState *s) - } else { - if (!e1000e_use_msix_vectors(s, E1000E_MSIX_VEC_NUM)) { - msix_uninit(d, &s->msix, &s->msix); -+ } else { -+ s->redhat_7_3_intr_state |= RH_E1000E_USE_MSIX; - } - } - } -@@ -471,6 +482,8 @@ static void e1000e_pci_realize(PCIDevice *pci_dev, Error **errp) - ret = msi_init(PCI_DEVICE(s), 0xD0, 1, true, false, NULL); - if (ret) { - trace_e1000e_msi_init_fail(ret); -+ } else { -+ s->redhat_7_3_intr_state |= RH_E1000E_USE_MSI; - } - - if (e1000e_add_pm_capability(pci_dev, e1000e_pmrb_offset, -@@ -592,6 +605,11 @@ static const VMStateDescription e1000e_vmstate_intr_timer = { - VMSTATE_STRUCT_ARRAY(_f, _s, _num, 0, \ - e1000e_vmstate_intr_timer, E1000IntrDelayTimer) - -+static bool rhel_7_3_check(void *opaque, int version_id) -+{ -+ return ((E1000EState *)opaque)->redhat_7_3_intr_state_enable; -+} -+ - static const VMStateDescription e1000e_vmstate = { - .name = "e1000e", - .version_id = 1, -@@ -603,6 +621,7 @@ static const VMStateDescription e1000e_vmstate = { - VMSTATE_MSIX(parent_obj, E1000EState), - - VMSTATE_UINT32(ioaddr, E1000EState), -+ VMSTATE_UINT32_TEST(redhat_7_3_intr_state, E1000EState, rhel_7_3_check), - VMSTATE_UINT32(core.rxbuf_min_shift, E1000EState), - VMSTATE_UINT8(core.rx_desc_len, E1000EState), - VMSTATE_UINT32_ARRAY(core.rxbuf_sizes, E1000EState, -@@ -651,6 +670,8 @@ static PropertyInfo e1000e_prop_disable_vnet, - - static Property e1000e_properties[] = { - DEFINE_NIC_PROPERTIES(E1000EState, conf), -+ DEFINE_PROP_BOOL("__redhat_e1000e_7_3_intr_state", E1000EState, -+ redhat_7_3_intr_state_enable, false), - DEFINE_PROP_SIGNED("disable_vnet_hdr", E1000EState, disable_vnet, false, - e1000e_prop_disable_vnet, bool), - DEFINE_PROP_SIGNED("subsys_ven", E1000EState, subsys_ven, -diff --git a/include/hw/compat.h b/include/hw/compat.h -index bb138cd..56cefc9 100644 ---- a/include/hw/compat.h -+++ b/include/hw/compat.h -@@ -407,6 +407,10 @@ - .driver = "virtio-pci",\ - .property = "x-pcie-pm-init",\ - .value = "off",\ -+ },{ /* HW_COMPAT_RHEL7_3 */ \ -+ .driver = "e1000e",\ -+ .property = "__redhat_e1000e_7_3_intr_state",\ -+ .value = "on",\ - }, - - #endif /* HW_COMPAT_H */ --- -1.8.3.1 - diff --git a/SOURCES/0028-osdep-Force-define-F_OFD_GETLK-RHEL-only.patch b/SOURCES/0028-osdep-Force-define-F_OFD_GETLK-RHEL-only.patch new file mode 100644 index 0000000..6337e92 --- /dev/null +++ b/SOURCES/0028-osdep-Force-define-F_OFD_GETLK-RHEL-only.patch @@ -0,0 +1,56 @@ +From 0901cd0ef66131ea6fe93654b0ceb1feaad9a0e5 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Thu, 12 Oct 2017 13:54:45 +0200 +Subject: osdep: Force define F_OFD_GETLK (RHEL only) + +RH-Author: Fam Zheng +Message-id: <20171012135445.4214-1-famz@redhat.com> +Patchwork-id: 77220 +O-Subject: [RHV7.5 qemu-kvm-ma PATCH] osdep: Force define F_OFD_GETLK (RHEL only) +Bugzilla: 1378241 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Thomas Huth + +BZ: 1378241 +Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=14254218 + +glibc is not ready yet (BZ 1461231, which is deferred to 7.6 due to +capacity), so the OFD constants are not defined in the system headers we +pull in. (They do exist in the headers of latest kernel-headers package, +but we don't want to include that anyway.) + +Actually the constants are all that are missing before we can call image +locking done in 7.5, so there is no reason to wait for glibc. + +This patch can be reverted once the new glibc headers are in place. + +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +(cherry picked from commit ac74b9067d079b03f3fe4236270f9eb34121009b) +(cherry picked from commit ae5b5b95b3a6ba4d1d9fb424cf95205e43f2ad67) +(cherry picked from commit f380fac7d927459c3675dabd125be8a379f43a2c) +(cherry picked from commit fb92cc1c98ff118afbc18ca1c22379ab3cf76f7a) +--- + util/osdep.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/util/osdep.c b/util/osdep.c +index a73de0e..0dbe6ec 100644 +--- a/util/osdep.c ++++ b/util/osdep.c +@@ -23,6 +23,11 @@ + */ + #include "qemu/osdep.h" + ++#ifndef F_OFD_SETLK ++#define F_OFD_GETLK 36 ++#define F_OFD_SETLK 37 ++#endif ++ + /* Needed early for CONFIG_BSD etc. */ + + #ifdef CONFIG_SOLARIS +-- +1.8.3.1 + diff --git a/SOURCES/0029-migcompat-rtl8139-Work-around-version-bump.patch b/SOURCES/0029-migcompat-rtl8139-Work-around-version-bump.patch deleted file mode 100644 index b794755..0000000 --- a/SOURCES/0029-migcompat-rtl8139-Work-around-version-bump.patch +++ /dev/null @@ -1,62 +0,0 @@ -From c4753f76a30a3e96c573d8e863587ba3e686348e Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Wed, 29 Mar 2017 10:57:23 +0200 -Subject: migcompat/rtl8139: Work around version bump - -RH-Author: Dr. David Alan Gilbert -Message-id: <20170329105723.7789-2-dgilbert@redhat.com> -Patchwork-id: 74581 -O-Subject: [RHEL-7.4 qemu-kvm-rhev PATCH v2 1/1] migcompat/rtl8139: Work around version bump -Bugzilla: 1420195 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Juan Quintela -RH-Acked-by: Laurent Vivier - -From: "Dr. David Alan Gilbert" - -commit 46fe8bef in 2.7 bumped the version number of the rtl8139 -vmstate, and added back a field that had been lost ~7 years ago -by 9d29cde in v0.11. - -To keep backwards compatibility we can't bump the version, so push -the version number back down and remove the field that was added. -The field doesn't seem to be that significant, especially since we've -survived for 7 years with out it. - -Signed-off-by: Dr. David Alan Gilbert -Signed-off-by: Miroslav Rezanina - -Rebase notes (2.9.0): -- Patch rewritten - -(cherry picked from commit 45ca263288bcbc98f36fae68c55e1a1b55e09221) ---- - hw/net/rtl8139.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c -index 450658c..80c62dc 100644 ---- a/hw/net/rtl8139.c -+++ b/hw/net/rtl8139.c -@@ -3206,7 +3206,7 @@ static void rtl8139_pre_save(void *opaque) - - static const VMStateDescription vmstate_rtl8139 = { - .name = "rtl8139", -- .version_id = 5, -+ .version_id = 4, - .minimum_version_id = 3, - .post_load = rtl8139_post_load, - .pre_save = rtl8139_pre_save, -@@ -3287,7 +3287,9 @@ static const VMStateDescription vmstate_rtl8139 = { - VMSTATE_UINT32(tally_counters.TxMCol, RTL8139State), - VMSTATE_UINT64(tally_counters.RxOkPhy, RTL8139State), - VMSTATE_UINT64(tally_counters.RxOkBrd, RTL8139State), -+#if 0 /* Disabled for Red Hat Enterprise Linux bz 1420195 */ - VMSTATE_UINT32_V(tally_counters.RxOkMul, RTL8139State, 5), -+#endif - VMSTATE_UINT16(tally_counters.TxAbt, RTL8139State), - VMSTATE_UINT16(tally_counters.TxUndrn, RTL8139State), - --- -1.8.3.1 - diff --git a/SOURCES/0029-spapr-disable-cpu-hot-remove.patch b/SOURCES/0029-spapr-disable-cpu-hot-remove.patch new file mode 100644 index 0000000..1779e45 --- /dev/null +++ b/SOURCES/0029-spapr-disable-cpu-hot-remove.patch @@ -0,0 +1,60 @@ +From 695c0b884eb5e6f35023b0e32928741c044b0498 Mon Sep 17 00:00:00 2001 +From: Igor Mammedov +Date: Thu, 19 Oct 2017 15:28:13 +0200 +Subject: spapr: disable cpu hot-remove + +RH-Author: Igor Mammedov +Message-id: <1508426893-172020-1-git-send-email-imammedo@redhat.com> +Patchwork-id: 77378 +O-Subject: [RHV7.5 qemu-kvm-ma PATCH v2] spapr: disable cpu hot-remove +Bugzilla: 1499320 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Thomas Huth +RH-Acked-by: David Gibson + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1499320 +Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=14301295 +Upstream: RHEL-only + +Rebase to 2.10 brought in cpu hot-remove with it, disable it +for qemu-kvm-ma variant of QEMU where it hasn't been supported. +Use CONFIG_RHV to switch unplug off only for qemu-kvm-ma and +not to affect RHEV variant built from the same source code. + +Signed-off-by: Igor Mammedov + +Conflicts: + hw/ppc/spapr.c + +(cherry picked from commit 56c058f25caa085fb22a92d89976afb529a391d8) +(cherry picked from commit c5448e8e407c2275d5b74e93fbf67eafb93b5a56) +(cherry picked from commit 7556463d8bfe3f357960962c6da2f6dc692b289f) +--- + hw/ppc/spapr.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c +index 3ea94de..f71a62e 100644 +--- a/hw/ppc/spapr.c ++++ b/hw/ppc/spapr.c +@@ -3315,6 +3315,7 @@ static + void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev, + Error **errp) + { ++#if defined(CONFIG_RHV) + sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev)); + int index; + sPAPRDRConnector *drc; +@@ -3337,6 +3338,9 @@ void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev, + spapr_drc_detach(drc); + + spapr_hotplug_req_remove_by_index(drc); ++#else ++ error_setg(errp, "this feature or command is not currently supported"); ++#endif /* CONFIG_RHV */ + } + + static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev, +-- +1.8.3.1 + diff --git a/SOURCES/0030-migration-Reenable-incoming-live-block-migration.patch b/SOURCES/0030-migration-Reenable-incoming-live-block-migration.patch new file mode 100644 index 0000000..be676f1 --- /dev/null +++ b/SOURCES/0030-migration-Reenable-incoming-live-block-migration.patch @@ -0,0 +1,92 @@ +From ed076b2838fb9c9b7e137352e72408d9267fd702 Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Wed, 22 Nov 2017 15:41:32 +0100 +Subject: migration: Reenable incoming live-block-migration + +RH-Author: Dr. David Alan Gilbert +Message-id: <20171122154132.15363-1-dgilbert@redhat.com> +Patchwork-id: 77779 +O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 1/1] migration: Reenable incoming live-block-migration +Bugzilla: 1515173 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Fam Zheng +RH-Acked-by: Juan Quintela + +From: "Dr. David Alan Gilbert" + +rhel7 has always disabled outgoing old-style live block migration +(but in -rhev enabled nbd block migration); however it allows +incoming old-style live block migration to allow reception of a stream +from rhel6. + +I added --disable-live-block-migration to upstream in ed1701c6a5a, +however that really did disable it completely. + +In the 7.5 world we've inherited the upstream version and lost the +incoming support. + +Reenable incoming support even when outgoing is disabled. + +Signed-off-by: Dr. David Alan Gilbert +Signed-off-by: Miroslav Rezanina +(cherry picked from commit e6f62c7eb81f164ad5aef99a4f7ff48200928938) +(cherry picked from commit d5fb1ed0bc8fe06f7f9ffa50df033f1be6a19335) +(cherry picked from commit d4f3d9c5f333b1b97e0eea3eff665988d92f7a24) +(cherry picked from commit 011f4eb1ad9f4a3b358a904348340b010cf54512) +--- + include/migration/misc.h | 7 +++---- + migration/Makefile.objs | 2 +- + migration/block.h | 6 +++++- + 3 files changed, 9 insertions(+), 6 deletions(-) + +diff --git a/include/migration/misc.h b/include/migration/misc.h +index 4ebf24c..10084e0 100644 +--- a/include/migration/misc.h ++++ b/include/migration/misc.h +@@ -22,11 +22,10 @@ void ram_mig_init(void); + + /* migration/block.c */ + +-#ifdef CONFIG_LIVE_BLOCK_MIGRATION ++/* RHEL7 allows incoming block migration even with ++ * --disable-live-block-migration to allow RHEL6->7 migration. ++ */ + void blk_mig_init(void); +-#else +-static inline void blk_mig_init(void) {} +-#endif + + #define SELF_ANNOUNCE_ROUNDS 5 + +diff --git a/migration/Makefile.objs b/migration/Makefile.objs +index c83ec47..5cb9fc0 100644 +--- a/migration/Makefile.objs ++++ b/migration/Makefile.objs +@@ -10,6 +10,6 @@ common-obj-y += block-dirty-bitmap.o + + common-obj-$(CONFIG_RDMA) += rdma.o + +-common-obj-$(CONFIG_LIVE_BLOCK_MIGRATION) += block.o ++common-obj-y += block.o + + rdma.o-libs := $(RDMA_LIBS) +diff --git a/migration/block.h b/migration/block.h +index 3178609..1cc81b0 100644 +--- a/migration/block.h ++++ b/migration/block.h +@@ -14,7 +14,11 @@ + #ifndef MIGRATION_BLOCK_H + #define MIGRATION_BLOCK_H + +-#ifdef CONFIG_LIVE_BLOCK_MIGRATION ++/* RHEL7: live block migration is still compiled in even ++ * with --disable-live-block-migration since we must ++ * allow inbound migration from RHEL6. ++ */ ++#if 1 /* CONFIG_LIVE_BLOCK_MIGRATION */ + int blk_mig_active(void); + int blk_mig_bulk_active(void); + uint64_t blk_mig_bytes_transferred(void); +-- +1.8.3.1 + diff --git a/SOURCES/0030-usb-xhci-Fix-PCI-capability-order.patch b/SOURCES/0030-usb-xhci-Fix-PCI-capability-order.patch deleted file mode 100644 index e722504..0000000 --- a/SOURCES/0030-usb-xhci-Fix-PCI-capability-order.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 2dd7402227e77d748a7375233ac9e7feab244bda Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Fri, 5 May 2017 19:06:14 +0200 -Subject: usb-xhci: Fix PCI capability order - -RH-Author: Dr. David Alan Gilbert -Message-id: <20170505190614.15987-2-dgilbert@redhat.com> -Patchwork-id: 75038 -O-Subject: [RHEL-7.4 qemu-kvm-rhev PATCH 1/1] usb-xhci: Fix PCI capability order -Bugzilla: 1447874 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Michael S. Tsirkin -RH-Acked-by: Gerd Hoffmann -RH-Acked-by: Juan Quintela - -From: "Dr. David Alan Gilbert" - -Upstream commit 1108b2f8a9 in 2.7.0 changed the order -of the PCI capability chain in the XHCI pci device in the case -where the device has the PCIe endpoint capability (i.e. only -older machine types, pc-i440fx-2.0 upstream, pc-i440fx-rhel7.0.0 -apparently for us). - -Changing the order breaks migration compatibility; fixing this -upstream would mean breaking the same case going from 2.7.0->current -that currently works 2.7.0->2.9.0 - so upstream it's a choice -of two breakages. - -Since we never released 2.7.0/2.8.0 we can fix this downstream. - -This reverts the order so that we create the capabilities in the -order: - PCIe - MSI - MSI-X - -The symptom is: -qemu-kvm: get_pci_config_device: Bad config data: i=0x71 read: a0 device: 0 cmask: ff wmask: 0 w1cmask:0 -qemu-kvm: Failed to load PCIDevice:config -qemu-kvm: Failed to load xhci:parent_obj -qemu-kvm: error while loading state for instance 0x0 of device '0000:00:0d.0/xhci' -qemu-kvm: load of migration failed: Invalid argument - -Signed-off-by: Dr. David Alan Gilbert -Signed-off-by: Miroslav Rezanina - --- -Rebase notes (2.9.0): -- Change in assert condition (upstream) - -(cherry picked from commit aad727a5ecde1ad4935eb8427604d4df5a1f1f35) ---- - hw/usb/hcd-xhci.c | 12 ++++++------ - 1 file changed, 6 insertions(+), 6 deletions(-) - -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index 10848db..53de805 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -3368,6 +3368,12 @@ static void usb_xhci_realize(struct PCIDevice *dev, Error **errp) - xhci->max_pstreams_mask = 0; - } - -+ if (pci_bus_is_express(dev->bus) || -+ xhci_get_flag(xhci, XHCI_FLAG_FORCE_PCIE_ENDCAP)) { -+ ret = pcie_endpoint_cap_init(dev, 0xa0); -+ assert(ret > 0); -+ } -+ - if (xhci->msi != ON_OFF_AUTO_OFF) { - ret = msi_init(dev, 0x70, xhci->numintrs, true, false, &err); - /* Any error other than -ENOTSUP(board's MSI support is broken) -@@ -3416,12 +3422,6 @@ static void usb_xhci_realize(struct PCIDevice *dev, Error **errp) - PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64, - &xhci->mem); - -- if (pci_bus_is_express(dev->bus) || -- xhci_get_flag(xhci, XHCI_FLAG_FORCE_PCIE_ENDCAP)) { -- ret = pcie_endpoint_cap_init(dev, 0xa0); -- assert(ret > 0); -- } -- - if (xhci->msix != ON_OFF_AUTO_OFF) { - /* TODO check for errors, and should fail when msix=on */ - msix_init(dev, xhci->numintrs, --- -1.8.3.1 - diff --git a/SOURCES/0031-block-vxhs-improve-error-message-for-missing-bad-vxh.patch b/SOURCES/0031-block-vxhs-improve-error-message-for-missing-bad-vxh.patch new file mode 100644 index 0000000..b5430bc --- /dev/null +++ b/SOURCES/0031-block-vxhs-improve-error-message-for-missing-bad-vxh.patch @@ -0,0 +1,65 @@ +From f2d1e27cdec37a9658bcb0262fb266ab3df4b695 Mon Sep 17 00:00:00 2001 +From: Jeffrey Cody +Date: Mon, 11 Dec 2017 22:38:12 +0100 +Subject: block/vxhs: improve error message for missing / bad vxhs module + +RH-Author: Jeffrey Cody +Message-id: <59af10d83125fff42beacd30dbca83d50409bbed.1513031708.git.jcody@redhat.com> +Patchwork-id: 78305 +O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 1/1] block/vxhs: improve error message for missing / bad vxhs module +Bugzilla: 1505654 +RH-Acked-by: Markus Armbruster +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Laszlo Ersek + +[Downstream only, as the module load of libvxhs is downstream only] + +In the case of missing libvxhs libraries, the original error message, +while technically accurate, may lead a user to think there is a QEMU bug +if trying to using the VXHS protocol. Update the message so that it is +clear that the likely issue is that the Veritas QEMU libvxhs RPM is not +installed (or not installed correctly, if there are permission or file +corruption issues, etc.). + +An example error message before this change: + +> qemu-img info vxhs://localhost/test +qemu-img: Could not open 'vxhs://localhost/test': \ + error loading libvxhs: /usr/lib64/qemu/libvxhs.so.1: \ + cannot open shared object file: No such file or directory + +An example error message after this change: + +> qemu-img info vxhs://localhost/test +qemu-img: Could not open 'vxhs://localhost/test': \ + The VXHS library from Veritas might not be installed correctly \ + (/usr/lib64/qemu/libvxhs.so.1: \ + cannot open shared object file: No such file or directory) + +Signed-off-by: Jeff Cody +Signed-off-by: Miroslav Rezanina +(cherry picked from commit 363bf9a1aea6d4af394df27fa4fcaba95b00af98) +(cherry picked from commit c7d20788c4b8a3b285a1cb7ddcee790b74c1621f) +(cherry picked from commit dc13bdde418c8447859f4630f01af680119c14bb) +--- + block/vxhs.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/block/vxhs.c b/block/vxhs.c +index a18154c..68edb51 100644 +--- a/block/vxhs.c ++++ b/block/vxhs.c +@@ -115,7 +115,8 @@ static void bdrv_vxhs_load_libs(Error **errp) + libvxhs_handle = g_module_open(LIBVXHS_FULL_PATHNAME, + G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); + if (!libvxhs_handle) { +- error_setg(errp, "error loading libvxhs: %s", g_module_error()); ++ error_setg(errp, "The VXHS library from Veritas might not be installed " ++ "correctly (%s)", g_module_error()); + return; + } + +-- +1.8.3.1 + diff --git a/SOURCES/0031-blockdev-ignore-aio-native-for-empty-drives.patch b/SOURCES/0031-blockdev-ignore-aio-native-for-empty-drives.patch deleted file mode 100644 index 000fea4..0000000 --- a/SOURCES/0031-blockdev-ignore-aio-native-for-empty-drives.patch +++ /dev/null @@ -1,74 +0,0 @@ -From a72f1c0f7b02ea571ec2ce35dfbe8c17c4dfa6d9 Mon Sep 17 00:00:00 2001 -From: John Snow -Date: Thu, 11 May 2017 20:53:51 +0200 -Subject: blockdev: ignore aio=native for empty drives - -RH-Author: John Snow -Message-id: <20170511205351.6337-2-jsnow@redhat.com> -Patchwork-id: 75070 -O-Subject: [RHV-7.4 qemu-kvm-rhev PATCH 1/1] blockdev: ignore aio=native for empty drives -Bugzilla: 1402645 -RH-Acked-by: Kevin Wolf -RH-Acked-by: Eric Blake -RH-Acked-by: Max Reitz - -This is a bit of a gross one; Upstream QEMU changed the way it handles -cache options with regards to removable media, associating options more -with the medium instead of the device. As part of that, it became -impossible to specify cache options on empty drives. - -In the future, one would use blockdev-add instead to choose cache options -per-medium instead of per-device, but we're not there yet in libvirt so -we added a workaround downstream to simply ignore cache options on empty -CDROMs under the premise of "It actually never worked anyway." - -As fallout from this decision, it is now no longer possible to specify -aio=native on empty CDROM devices either, as that requires the use of a -cache option that you can no longer specify. As a bad, gross, disgusting -workaround, simply ignore aio=native on empty drives until such time that -libvirt stops providing such configurations. - -Signed-off-by: Miroslav Rezanina -(cherry picked from commit cda174ad842c9a61bc275315bf3155139ba19bc0) ---- - blockdev.c | 17 ++++++++++++++++- - 1 file changed, 16 insertions(+), 1 deletion(-) - -diff --git a/blockdev.c b/blockdev.c -index 6d4cb70..d54ea6f 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -476,6 +476,21 @@ static bool __redhat_com_has_bs_opts(QDict *bs_opts) - return s != n; - } - -+/** -+ * libvirt expects to be able to pass io driver options (aio=native) for CDROM -+ * drives without inserted media. While this has worked historically, given the -+ * above workaround and lack of a supported alternative in current versions of -+ * libvirt, certain options such as aio=native cannot be supported as it -+ * requires the use of an accompanying cache option, which we also ignore. -+ * Until libvirt learns how to supply cache options to inserted media, ignore -+ * the aio= preference on empty CDROMs with the understanding that un-tuned -+ * performance is preferable to being unable to use the CDROM at all. -+ */ -+static int __redhat_com_filter_flags(int flags) -+{ -+ return flags & ~BDRV_O_NATIVE_AIO; -+} -+ - /* Takes the ownership of bs_opts */ - static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, - Error **errp) -@@ -588,7 +603,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, - - blk = blk_new(0, BLK_PERM_ALL); - blk_rs = blk_get_root_state(blk); -- blk_rs->open_flags = bdrv_flags; -+ blk_rs->open_flags = __redhat_com_filter_flags(bdrv_flags); - blk_rs->read_only = read_only; - blk_rs->detect_zeroes = detect_zeroes; - --- -1.8.3.1 - diff --git a/SOURCES/0032-scsi-Disable-deprecated-implicit-SCSI-HBA-creation-m.patch b/SOURCES/0032-scsi-Disable-deprecated-implicit-SCSI-HBA-creation-m.patch deleted file mode 100644 index 485f34d..0000000 --- a/SOURCES/0032-scsi-Disable-deprecated-implicit-SCSI-HBA-creation-m.patch +++ /dev/null @@ -1,122 +0,0 @@ -From 4c43abf1394c3711f93a4e0175ff5c10769f6480 Mon Sep 17 00:00:00 2001 -From: Markus Armbruster -Date: Fri, 28 Apr 2017 12:22:27 +0200 -Subject: scsi: Disable deprecated implicit SCSI HBA creation more cleanly - -RH-Author: Markus Armbruster -Message-id: <1493382147-23057-2-git-send-email-armbru@redhat.com> -Patchwork-id: 74946 -O-Subject: [RHV-7.4 qemu-kvm-rhev PATCH] scsi: Disable deprecated implicit SCSI HBA creation more cleanly -Bugzilla: 971799 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: John Snow -RH-Acked-by: Jeffrey Cody - -The PC machines (pc-q35-* pc-i440fx-* pc-* isapc xenfv) automatically -create lsi53c895a SCSI HBAs and SCSI devices to honor -drive if=scsi. -Deprecated upstream since commit f778a82, v2.9.0, not supported at all -in RHEL. The way it fails is rather ugly, though: - - $ qemu-kvm -nodefaults -S -drive if=scsi,media=cdrom - qemu-kvm: Unknown device 'lsi53c895a' for bus 'PCI' - Aborted (core dumped) - -Recent upstream work permit us to make this fail cleanly by commenting -out the code that tries to create lsi53c895a SCSI HBAs in -pc_pci_device_init(): - - qemu-kvm: -drive if=scsi,media=cdrom: machine type does not support if=scsi,bus=0,unit=0 - -However, by itself this would make another deprecated feature -available in RHEL: drives defined with if=scsi get picked up by SCSI -HBAs added with -device, unlike other interface types. Deprecated -upstream since commit a64aa57, v2.9.0. Comment out that code, too. -Bonus: that code can be rather slow with a large number of drives, so -good riddance. - -Signed-off-by: Markus Armbruster -Signed-off-by: Miroslav Rezanina -(cherry picked from commit 7977e603169c92da4b0ecd656c3346500a93897b) ---- - hw/i386/pc.c | 2 ++ - hw/scsi/scsi-bus.c | 7 +++++++ - vl.c | 2 ++ - 3 files changed, 11 insertions(+) - -diff --git a/hw/i386/pc.c b/hw/i386/pc.c -index ae23fc4..ccaa832 100644 ---- a/hw/i386/pc.c -+++ b/hw/i386/pc.c -@@ -1645,6 +1645,7 @@ void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus) - - void pc_pci_device_init(PCIBus *pci_bus) - { -+#if 0 /* Disabled for Red Hat Enterprise Linux */ - int max_bus; - int bus; - -@@ -1658,6 +1659,7 @@ void pc_pci_device_init(PCIBus *pci_bus) - * this usage is deprecated. - */ - } -+#endif - } - - void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name) -diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c -index e364410..309daaa 100644 ---- a/hw/scsi/scsi-bus.c -+++ b/hw/scsi/scsi-bus.c -@@ -265,6 +265,8 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk, - - void scsi_bus_legacy_handle_cmdline(SCSIBus *bus, bool deprecated) - { -+#if 0 /* Disabled for Red Hat Enterprise Linux */ -+ - Location loc; - DriveInfo *dinfo; - int unit; -@@ -291,8 +293,11 @@ void scsi_bus_legacy_handle_cmdline(SCSIBus *bus, bool deprecated) - unit, false, -1, NULL, &error_fatal); - } - loc_pop(&loc); -+#endif - } - -+#if 0 /* Disabled for Red Hat Enterprise Linux */ -+ - static bool is_scsi_hba_with_legacy_magic(Object *obj) - { - static const char *magic[] = { -@@ -329,6 +334,8 @@ void scsi_legacy_handle_cmdline(void) - scsi_legacy_handle_cmdline_cb, NULL); - } - -+#endif -+ - static int32_t scsi_invalid_field(SCSIRequest *req, uint8_t *buf) - { - scsi_req_build_sense(req, SENSE_CODE(INVALID_FIELD)); -diff --git a/vl.c b/vl.c -index 59f515c..183b7f7 100644 ---- a/vl.c -+++ b/vl.c -@@ -4676,6 +4676,7 @@ int main(int argc, char **argv, char **envp) - - rom_reset_order_override(); - -+#if 0 /* Disabled for Red Hat Enterprise Linux */ - /* - * Create frontends for -drive if=scsi leftovers. - * Normally, frontends for -drive get created by machine -@@ -4684,6 +4685,7 @@ int main(int argc, char **argv, char **envp) - * implementation accident, and deprecated. - */ - scsi_legacy_handle_cmdline(); -+#endif - - /* Did we create any drives that we failed to create a device for? */ - drive_check_orphaned(); --- -1.8.3.1 - diff --git a/SOURCES/0032-serial-always-transmit-send-receive-buffers-on-migra.patch b/SOURCES/0032-serial-always-transmit-send-receive-buffers-on-migra.patch new file mode 100644 index 0000000..613977f --- /dev/null +++ b/SOURCES/0032-serial-always-transmit-send-receive-buffers-on-migra.patch @@ -0,0 +1,95 @@ +From c782c6646a2806a95a953bcfdb7c4801edfe65a4 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Thu, 11 Jan 2018 13:56:44 +0100 +Subject: serial: always transmit send/receive buffers on migration + +RH-Author: Paolo Bonzini +Message-id: <20180111135644.16253-1-pbonzini@redhat.com> +Patchwork-id: 78551 +O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH v2] serial: always transmit send/receive buffers on migration +Bugzilla: 1459945 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Miroslav Rezanina + +When subsections were added in qemu 2.3, they were all disabled +for machine types that require pre-2.3 compatibility. The commit +message says "disabling these subsections on older machine types should +leave it no worse than existing qemu", but actually migrating from +new QEMU to new QEMU (but with old machine type) will detect an +inconsistent migration state and fail the migration: + + qemu-system-x86_64: inconsistent state in serial device (tsr not empty, tsr_retry=0 + qemu-system-x86_64: Failed to load serial:state + qemu-system-x86_64: error while loading state for instance 0x0 of device 'serial' + +In fact, this shows that migration from new source to old destination +might have also eaten the data in the FIFO or transmit/receive buffers. + +It's actually pretty easy to trigger the failure by connecting a console +to a hung-up reader (not a *disconnected* reader!). The fix is to +handle the subsections the same as we did in the qemu-kvm BZ1452067. +The data registers are migrated, which may indeed cause some more migrations +to fail to old qemu-kvm-rhev, but it will fix migration to new qemu-kvm-rhev. +Some subsections are still keyed on migrate_pre_2_2; from the commit message +of downstream commit 7d2e8f9662feb64c0b15b6fd53e06e3c56921f27: + + thr_ipending can be reconstructed fairly + reliably by serial_post_load. The others are features that are + unlikely to be used in RHEL, respectively receive timeout (Linux + does not even have the UART_IIR_CTI symbol in the driver) and + physical serial ports connected to a modem + +I consider this okay because nobody has yet complained about it for +qemu-kvm. It's also safer because the failure avoids serial data loss +on migration. This is consistent with the intended use of subsections. + +Signed-off-by: Paolo Bonzini +Signed-off-by: Miroslav Rezanina +(cherry picked from commit 10564d0bb819113f925e32b989b24fb26dca45ef) +(cherry picked from commit 9e1104c955c05c7b850cda3a02f69bf3e931c765) +(cherry picked from commit 04e1727ca5a6cef2e23d387cef32ad18f4f1b6a7) +--- + hw/char/serial.c | 12 ------------ + 1 file changed, 12 deletions(-) + +diff --git a/hw/char/serial.c b/hw/char/serial.c +index 7647fac..d6d9b18 100644 +--- a/hw/char/serial.c ++++ b/hw/char/serial.c +@@ -722,10 +722,6 @@ static const VMStateDescription vmstate_serial_thr_ipending = { + static bool serial_tsr_needed(void *opaque) + { + SerialState *s = (SerialState *)opaque; +- if (migrate_pre_2_2) { +- return false; +- } +- + return s->tsr_retry != 0; + } + +@@ -745,10 +741,6 @@ static const VMStateDescription vmstate_serial_tsr = { + static bool serial_recv_fifo_needed(void *opaque) + { + SerialState *s = (SerialState *)opaque; +- if (migrate_pre_2_2) { +- return false; +- } +- + return !fifo8_is_empty(&s->recv_fifo); + + } +@@ -767,10 +759,6 @@ static const VMStateDescription vmstate_serial_recv_fifo = { + static bool serial_xmit_fifo_needed(void *opaque) + { + SerialState *s = (SerialState *)opaque; +- if (migrate_pre_2_2) { +- return false; +- } +- + return !fifo8_is_empty(&s->xmit_fifo); + } + +-- +1.8.3.1 + diff --git a/SOURCES/0033-target-i386-sanitize-x86-MSR_PAT-loaded-from-another.patch b/SOURCES/0033-target-i386-sanitize-x86-MSR_PAT-loaded-from-another.patch new file mode 100644 index 0000000..88668ba --- /dev/null +++ b/SOURCES/0033-target-i386-sanitize-x86-MSR_PAT-loaded-from-another.patch @@ -0,0 +1,79 @@ +From ebba9a277c36df319d1ec59f25d8b8d596fb8ab4 Mon Sep 17 00:00:00 2001 +From: Wei Huang +Date: Wed, 17 Jan 2018 22:13:23 +0100 +Subject: target-i386: sanitize x86 MSR_PAT loaded from another source + +RH-Author: Wei Huang +Message-id: <20180117221323.1008-1-wei@redhat.com> +Patchwork-id: 78659 +O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 1/1] target-i386: sanitize x86 MSR_PAT loaded from another source +Bugzilla: 1529461 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Miroslav Rezanina + +The RHEL 7 downstream commit a94f33258 honors guest VM's writes of MSR_PAT +for SVM machines. But this cause a problem when an x86 VM is migrated from +an old host, such as RHEL 6.9. This is because older system doesn't save +the guest's PAT field during migration; Instead 0x0 is saved and migrated. +At the destination, it will use 0x0 as guest PAT because of a94f33258. +This causes the guest VM's performance to drop significatly. + +This patch solves the problem by sanitizing the PAT field. If it is zero, +we use the default MSR_PAT value (0x0007040600070406ULL) to prevent +performance drop. This solution should work with different types of +(old or new) VM sources. + +Signed-off-by: Wei Huang +Signed-off-by: Miroslav Rezanina +(cherry picked from commit 09fbed03321a5b7a2ecd55ba37bed53db552b0b9) +(cherry picked from commit e883fc66d38107233b26acc588fb7af9a2afc8a2) +(cherry picked from commit afd4296db6ae47e5f073a4dd07ea256b660f60de) +--- + target/i386/cpu.c | 2 +- + target/i386/cpu.h | 1 + + target/i386/machine.c | 3 +++ + 3 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index a9db495..0fc7fb0 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -3785,7 +3785,7 @@ static void x86_cpu_reset(CPUState *s) + /* All units are in INIT state. */ + env->xstate_bv = 0; + +- env->pat = 0x0007040600070406ULL; ++ env->pat = MSR_PAT_DEFAULT; + env->msr_ia32_misc_enable = MSR_IA32_MISC_ENABLE_DEFAULT; + + memset(env->dr, 0, sizeof(env->dr)); +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 1b219fa..0c7a3d6 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -401,6 +401,7 @@ typedef enum X86Seg { + #define MSR_MTRRfix4K_F8000 0x26f + + #define MSR_PAT 0x277 ++#define MSR_PAT_DEFAULT 0x0007040600070406ULL + + #define MSR_MTRRdefType 0x2ff + +diff --git a/target/i386/machine.c b/target/i386/machine.c +index c9a3b5c..f86abe7 100644 +--- a/target/i386/machine.c ++++ b/target/i386/machine.c +@@ -277,6 +277,9 @@ static int cpu_post_load(void *opaque, int version_id) + env->hflags &= ~HF_CPL_MASK; + env->hflags |= (env->segs[R_SS].flags >> DESC_DPL_SHIFT) & HF_CPL_MASK; + ++ if (!(env->pat)) ++ env->pat = MSR_PAT_DEFAULT; ++ + env->fpstt = (env->fpus_vmstate >> 11) & 7; + env->fpus = env->fpus_vmstate & ~0x3800; + env->fptag_vmstate ^= 0xff; +-- +1.8.3.1 + diff --git a/SOURCES/0033-virtio-scsi-Reject-scsi-cd-if-data-plane-enabled-RHE.patch b/SOURCES/0033-virtio-scsi-Reject-scsi-cd-if-data-plane-enabled-RHE.patch deleted file mode 100644 index 8b62881..0000000 --- a/SOURCES/0033-virtio-scsi-Reject-scsi-cd-if-data-plane-enabled-RHE.patch +++ /dev/null @@ -1,66 +0,0 @@ -From c9c4f117d8b507c2f86035c282d537c0a327364f Mon Sep 17 00:00:00 2001 -From: Fam Zheng -Date: Wed, 14 Jun 2017 15:37:01 +0200 -Subject: virtio-scsi: Reject scsi-cd if data plane enabled [RHEL only] - -RH-Author: Fam Zheng -Message-id: <20170614153701.14757-1-famz@redhat.com> -Patchwork-id: 75613 -O-Subject: [RHV-7.4 qemu-kvm-rhev PATCH v3] virtio-scsi: Reject scsi-cd if data plane enabled [RHEL only] -Bugzilla: 1378816 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Max Reitz - -We need a fix for RHEL 7.4 and 7.3.z, but unfortunately upstream isn't -ready. If it were, the changes will be too invasive. To have an idea: - -https://lists.gnu.org/archive/html/qemu-devel/2017-05/msg05400.html - -is an incomplete attempt to fix part of the issue, and the remaining -work unfortunately involve even more complex changes. - -As a band-aid, this partially reverts the effect of ef8875b -(virtio-scsi: Remove op blocker for dataplane, since v2.7). We cannot -simply revert that commit as a whole because we already shipped it in -qemu-kvm-rhev 7.3, since when, block jobs has been possible. We should -only block what has been broken. Also, faithfully reverting the above -commit means adding back the removed op blocker, but that is not enough, -because it still crashes when inserting media into an initially empty -scsi-cd. - -All in all, scsi-cd on virtio-scsi-dataplane has basically been unusable -unless the scsi-cd never enters an empty state, so, disable it -altogether. Otherwise it would be much more difficult to avoid -crashing. - -Signed-off-by: Fam Zheng -Signed-off-by: Miroslav Rezanina -(cherry picked from commit b0caf00bbc35c7d89e02999bdce86e1f867728e8) ---- - hw/scsi/virtio-scsi.c | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c -index eb63944..2635c38 100644 ---- a/hw/scsi/virtio-scsi.c -+++ b/hw/scsi/virtio-scsi.c -@@ -790,6 +790,15 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev, - VirtIOSCSI *s = VIRTIO_SCSI(vdev); - SCSIDevice *sd = SCSI_DEVICE(dev); - -+ /* XXX: Remove this check once block backend is capable of handling -+ * AioContext change upon eject/insert. -+ * s->ctx is NULL if ioeventfd is off, s->ctx is qemu_get_aio_context() if -+ * data plane is not used, both cases are safe for scsi-cd. */ -+ if (s->ctx && s->ctx != qemu_get_aio_context() && -+ object_dynamic_cast(OBJECT(dev), "scsi-cd")) { -+ error_setg(errp, "scsi-cd is not supported by data plane"); -+ return; -+ } - if (s->ctx && !s->dataplane_fenced) { - if (blk_op_is_blocked(sd->conf.blk, BLOCK_OP_TYPE_DATAPLANE, errp)) { - return; --- -1.8.3.1 - diff --git a/SOURCES/0034-hmp-fix-dump-quest-memory-segfault-ppc.patch b/SOURCES/0034-hmp-fix-dump-quest-memory-segfault-ppc.patch deleted file mode 100644 index d5431ac..0000000 --- a/SOURCES/0034-hmp-fix-dump-quest-memory-segfault-ppc.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 647e9ff9107bb3c1536b995281e8db905bcb4164 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Wed, 13 Sep 2017 16:20:33 +0200 -Subject: hmp: fix "dump-quest-memory" segfault (ppc) - -Running QEMU with - qemu-system-ppc64 -M none -nographic -m 256 -and executing - dump-guest-memory /dev/null 0 8192 -results in segfault - -Fix by checking if we have CPU, and exit with -error if there is no CPU: - - (qemu) dump-guest-memory /dev/null - this feature or command is not currently supported - -Signed-off-by: Laurent Vivier -Reviewed-by: Greg Kurz -Reviewed-by: Thomas Huth -Message-Id: <20170913142036.2469-2-lvivier@redhat.com> -Acked-by: David Gibson -Signed-off-by: Dr. David Alan Gilbert -(cherry picked from commit b1fde1ef5106c92dd12f1f0cfcb8c76e57d7f681) ---- - target/ppc/arch_dump.c | 11 +++++++++-- - 1 file changed, 9 insertions(+), 2 deletions(-) - -diff --git a/target/ppc/arch_dump.c b/target/ppc/arch_dump.c -index 8e9397a..95b9ab6 100644 ---- a/target/ppc/arch_dump.c -+++ b/target/ppc/arch_dump.c -@@ -224,8 +224,15 @@ typedef struct NoteFuncDescStruct NoteFuncDesc; - int cpu_get_dump_info(ArchDumpInfo *info, - const struct GuestPhysBlockList *guest_phys_blocks) - { -- PowerPCCPU *cpu = POWERPC_CPU(first_cpu); -- PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); -+ PowerPCCPU *cpu; -+ PowerPCCPUClass *pcc; -+ -+ if (first_cpu == NULL) { -+ return -1; -+ } -+ -+ cpu = POWERPC_CPU(first_cpu); -+ pcc = POWERPC_CPU_GET_CLASS(cpu); - - info->d_machine = PPC_ELF_MACHINE; - info->d_class = ELFCLASS; --- -1.8.3.1 - diff --git a/SOURCES/0034-spapr-disable-memory-hotplug.patch b/SOURCES/0034-spapr-disable-memory-hotplug.patch new file mode 100644 index 0000000..12a183a --- /dev/null +++ b/SOURCES/0034-spapr-disable-memory-hotplug.patch @@ -0,0 +1,82 @@ +From d3f4feea8023be7c0c3db09e4ea1a24a34f8c4a9 Mon Sep 17 00:00:00 2001 +From: Igor Mammedov +Date: Wed, 31 Jan 2018 10:44:31 +0100 +Subject: spapr: disable memory hotplug + +RH-Author: Igor Mammedov +Message-id: <1517395471-44118-1-git-send-email-imammedo@redhat.com> +Patchwork-id: 78748 +O-Subject: [RHV7.5 qemu-kvm-ma PATCH v3] spapr: disable memory hotplug +Bugzilla: 1535952 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Laurent Vivier +RH-Acked-by: Dr. David Alan Gilbert + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1535952 +Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=15146188 +Upstream: RHEL-only + +Disable memory hotplug for qemu-kvm-ma variant of QEMU where +shouldn't be supported. +Use CONFIG_RHV to switch feature off only for qemu-kvm-ma and +not to affect RHEV variant built from the same source code. + +PS: +Disable only (un)plug entry points from device_add/del and +leave the rest of hotplug hw intact so that -ma machine +could be migrated to -rhev. +Note: backward migration would be broken if source -rhev +machine used pc-dimm devices (either with -device/device_add) + +Signed-off-by: Igor Mammedov +Signed-off-by: Miroslav Rezanina +(cherry picked from commit bf05b668e4248781d24cfba88bfb9647ca6ca14e) +(cherry picked from commit dd0871512012fbbe343361bd3ff6fa21545c41d5) +(cherry picked from commit d42b9faa86dfd70e4ba6b8f2bf108d0e21a1a65d) +--- + hw/ppc/spapr.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c +index f71a62e..360a258 100644 +--- a/hw/ppc/spapr.c ++++ b/hw/ppc/spapr.c +@@ -3070,6 +3070,9 @@ out: + static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + Error **errp) + { ++#if !defined(CONFIG_RHV) ++ error_setg(errp, "Memory hotplug not supported for this machine"); ++#else + PCDIMMDevice *dimm = PC_DIMM(dev); + PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm); + MemoryRegion *mr; +@@ -3097,6 +3100,7 @@ static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + + out: + g_free(mem_dev); ++#endif + } + + struct sPAPRDIMMState { +@@ -3210,6 +3214,9 @@ void spapr_lmb_release(DeviceState *dev) + static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { ++#if !defined(CONFIG_RHV) ++ error_setg(errp, "Memory hot unplug not supported for this machine"); ++#else + sPAPRMachineState *spapr = SPAPR_MACHINE(hotplug_dev); + Error *local_err = NULL; + PCDIMMDevice *dimm = PC_DIMM(dev); +@@ -3264,6 +3271,7 @@ static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev, + nr_lmbs, spapr_drc_index(drc)); + out: + error_propagate(errp, local_err); ++#endif + } + + static void *spapr_populate_hotplug_cpu_dt(CPUState *cs, int *fdt_offset, +-- +1.8.3.1 + diff --git a/SOURCES/0035-hmp-fix-dump-quest-memory-segfault-arm.patch b/SOURCES/0035-hmp-fix-dump-quest-memory-segfault-arm.patch deleted file mode 100644 index 3b4403b..0000000 --- a/SOURCES/0035-hmp-fix-dump-quest-memory-segfault-arm.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 14dc40db1b710c64fbb2eeccde1afefa0a37cd1e Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Wed, 13 Sep 2017 16:20:34 +0200 -Subject: hmp: fix "dump-quest-memory" segfault (arm) - -Running QEMU with - qemu-system-aarch64 -M none -nographic -m 256 -and executing - dump-guest-memory /dev/null 0 8192 -results in segfault - -Fix by checking if we have CPU, and exit with -error if there is no CPU: - - (qemu) dump-guest-memory /dev/null - this feature or command is not currently supported - -Signed-off-by: Laurent Vivier -Reviewed-by: Thomas Huth -Reviewed-by: Greg Kurz -Message-Id: <20170913142036.2469-3-lvivier@redhat.com> -Reviewed-by: Eric Auger -Tested-by: Eric Auger -Signed-off-by: Dr. David Alan Gilbert -(cherry picked from commit 6dba634097d54db60017f10c160a052e46bdf60d) ---- - target/arm/arch_dump.c | 11 +++++++++-- - 1 file changed, 9 insertions(+), 2 deletions(-) - -diff --git a/target/arm/arch_dump.c b/target/arm/arch_dump.c -index 1a9861f..9e5b2fb 100644 ---- a/target/arm/arch_dump.c -+++ b/target/arm/arch_dump.c -@@ -273,11 +273,18 @@ int arm_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, - int cpu_get_dump_info(ArchDumpInfo *info, - const GuestPhysBlockList *guest_phys_blocks) - { -- ARMCPU *cpu = ARM_CPU(first_cpu); -- CPUARMState *env = &cpu->env; -+ ARMCPU *cpu; -+ CPUARMState *env; - GuestPhysBlock *block; - hwaddr lowest_addr = ULLONG_MAX; - -+ if (first_cpu == NULL) { -+ return -1; -+ } -+ -+ cpu = ARM_CPU(first_cpu); -+ env = &cpu->env; -+ - /* Take a best guess at the phys_base. If we get it wrong then crash - * will need '--machdep phys_offset=' added to its command - * line, which isn't any worse than assuming we can use zero, but being --- -1.8.3.1 - diff --git a/SOURCES/0036-dump-do-not-dump-non-existent-guest-memory.patch b/SOURCES/0036-dump-do-not-dump-non-existent-guest-memory.patch deleted file mode 100644 index da3d2c3..0000000 --- a/SOURCES/0036-dump-do-not-dump-non-existent-guest-memory.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 4fd31afb27446d33e659cb279691aa94270e6bfb Mon Sep 17 00:00:00 2001 -From: Cornelia Huck -Date: Wed, 13 Sep 2017 16:20:35 +0200 -Subject: dump: do not dump non-existent guest memory - -It does not really make sense to dump memory that is not there. - -Moreover, that fixes a segmentation fault when calling dump-guest-memory -with no filter for a machine with no memory defined. - -New behaviour is: - -(qemu) dump-guest-memory /dev/null -dump: no guest memory to dump -(qemu) dump-guest-memory /dev/null 0 4096 -dump: no guest memory to dump - -Signed-off-by: Cornelia Huck -Tested-by: Laurent Vivier -Reviewed-by: Laurent Vivier -Reviewed-by: Greg Kurz -Reviewed-by: Peter Xu -Message-Id: <20170913142036.2469-4-lvivier@redhat.com> -Signed-off-by: Laurent Vivier -Signed-off-by: Dr. David Alan Gilbert -(cherry picked from commit d1e6994abcd12c7f54aa73ff848fb6215c783898) ---- - dump.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/dump.c b/dump.c -index d9090a2..99117ba 100644 ---- a/dump.c -+++ b/dump.c -@@ -1536,6 +1536,12 @@ static void dump_init(DumpState *s, int fd, bool has_format, - fprintf(stderr, "DUMP: total memory to dump: %lu\n", s->total_size); - #endif - -+ /* it does not make sense to dump non-existent memory */ -+ if (!s->total_size) { -+ error_setg(errp, "dump: no guest memory to dump"); -+ goto cleanup; -+ } -+ - s->start = get_start_block(s); - if (s->start == -1) { - error_setg(errp, QERR_INVALID_PARAMETER, "begin"); --- -1.8.3.1 - diff --git a/SOURCES/0037-tests-hmp-test-none-machine-with-memory.patch b/SOURCES/0037-tests-hmp-test-none-machine-with-memory.patch deleted file mode 100644 index 13c2127..0000000 --- a/SOURCES/0037-tests-hmp-test-none-machine-with-memory.patch +++ /dev/null @@ -1,42 +0,0 @@ -From f4217185263cd9a3e2da574648b9bf72e65d9ad6 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Wed, 13 Sep 2017 16:20:36 +0200 -Subject: tests/hmp: test "none" machine with memory - -and add a test case of dump-guest-memory without -"[begin length]" parameters. - -Signed-off-by: Laurent Vivier -Reviewed-by: Thomas Huth -Reviewed-by: Cornelia Huck -Message-Id: <20170913142036.2469-5-lvivier@redhat.com> -Signed-off-by: Dr. David Alan Gilbert -(cherry picked from commit 4e5c3a3742adcf7514b73f4da1c005ee7b35e41b) ---- - tests/test-hmp.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/tests/test-hmp.c b/tests/test-hmp.c -index 729c033..d124e81 100644 ---- a/tests/test-hmp.c -+++ b/tests/test-hmp.c -@@ -35,6 +35,7 @@ static const char *hmp_cmds[] = { - "mouse_button 0", - "device_del mouse1", - "dump-guest-memory /dev/null 0 4096", -+ "dump-guest-memory /dev/null", - "gdbserver", - "host_net_add user id=net0", - "hostfwd_add tcp::43210-:43210", -@@ -159,5 +160,8 @@ int main(int argc, char **argv) - - qtest_cb_for_every_machine(add_machine_test_case); - -+ /* as none machine has no memory by default, add a test case with memory */ -+ qtest_add_data_func("hmp/none+2MB", g_strdup("none -m 2"), test_machine); -+ - return g_test_run(); - } --- -1.8.3.1 - diff --git a/SOURCES/0038-vfio-spapr-Fix-levels-calculation.patch b/SOURCES/0038-vfio-spapr-Fix-levels-calculation.patch deleted file mode 100644 index 7b7331b..0000000 --- a/SOURCES/0038-vfio-spapr-Fix-levels-calculation.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 6ef9f439f68181319e04b5fd6bfb1a2e36d4bbee Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Mon, 18 Sep 2017 00:20:08 +0100 -Subject: vfio, spapr: Fix levels calculation - -RH-Author: David Gibson -Message-id: <20170918002008.24430-1-dgibson@redhat.com> -Patchwork-id: 76404 -O-Subject: [Pegas-1.0 qemu-kvm PATCH] vfio, spapr: Fix levels calculation -Bugzilla: 1491749 -RH-Acked-by: Laurent Vivier -RH-Acked-by: Suraj Jitindar Singh -RH-Acked-by: Sam Bobroff - -From: Alexey Kardashevskiy - -The existing tries to round up the number of pages but @pages is always -calculated as the rounded up value minus one which makes ctz64() always -return 0 and have create.levels always set 1. - -This removes wrong "-1" and allows having more than 1 levels. This becomes -handy for >128GB guests with standard 64K pages as this requires blocks -with zone order 9 and the popular limit of CONFIG_FORCE_MAX_ZONEORDER=9 -means that only blocks up to order 8 are allowed. - -Signed-off-by: Alexey Kardashevskiy -Signed-off-by: David Gibson -(cherry picked from commit e100161b69f8cf56dae866912dfffe7dcd7140af) -Signed-off-by: David Gibson -Signed-off-by: Danilo C. L. de Paula -(cherry picked from commit b83a6ae1492fa004c6e0e34cfb3ac8efe21e7bd2) ---- - hw/vfio/spapr.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/vfio/spapr.c b/hw/vfio/spapr.c -index 32fd6a9..259397c 100644 ---- a/hw/vfio/spapr.c -+++ b/hw/vfio/spapr.c -@@ -163,7 +163,7 @@ int vfio_spapr_create_window(VFIOContainer *container, - */ - entries = create.window_size >> create.page_shift; - pages = MAX((entries * sizeof(uint64_t)) / getpagesize(), 1); -- pages = MAX(pow2ceil(pages) - 1, 1); /* Round up */ -+ pages = MAX(pow2ceil(pages), 1); /* Round up */ - create.levels = ctz64(pages) / 6 + 1; - - ret = ioctl(container->fd, VFIO_IOMMU_SPAPR_TCE_CREATE, &create); --- -1.8.3.1 - diff --git a/SOURCES/build_configure.sh b/SOURCES/build_configure.sh index 97f1c1f..a07c930 100755 --- a/SOURCES/build_configure.sh +++ b/SOURCES/build_configure.sh @@ -36,6 +36,8 @@ have_seccomp=$1 shift have_spice=$1 shift +have_opengl=$1 +shift have_usbredir=$1 shift have_tcmalloc=$1 @@ -50,6 +52,8 @@ have_vhost_user=$1 shift is_rhv=$1 shift +have_malloc_trim=$1 +shift if [ "$have_rbd" == "enable" ]; then rbd_driver=rbd, @@ -77,12 +81,13 @@ fi --localstatedir=${_localstatedir} \ --docdir=${qemudocdir} \ --libexecdir=${_libexecdir} \ + --firmwarepath=${_prefix}/share/qemu-firmware \ --extra-ldflags="$extraldflags -pie -Wl,-z,relro -Wl,-z,now" \ --extra-cflags="${optflags} -fPIE -DPIE" \ --with-pkgversion=${nvr} \ --with-confsuffix=/${pkgname} \ + --with-git=git \ --with-coroutine=ucontext \ - --with-system-pixman \ --tls-priority=NORMAL \ --disable-bluez \ --disable-brlapi \ @@ -102,7 +107,6 @@ fi --enable-linux-aio \ --disable-live-block-migration \ --enable-lzo \ - --disable-opengl \ --enable-pie \ --disable-qom-cast-debug \ --disable-sdl \ @@ -122,8 +126,8 @@ fi --disable-xen \ --disable-xfsctl \ --enable-gnutls \ - --disable-gcrypt \ - --enable-nettle \ + --enable-gcrypt \ + --disable-nettle \ --enable-attr \ --disable-bsd-user \ --disable-cocoa \ @@ -155,14 +159,24 @@ fi --${have_seccomp}-seccomp \ --${have_spice}-spice \ --${have_spice}-smartcard \ + --${have_opengl}-opengl \ --${have_usbredir}-usb-redir \ --${have_tcmalloc}-tcmalloc \ --${have_vxhs}-vxhs \ --${have_vtd}-vtd \ --${have_live_block_ops}-live-block-ops \ --${have_vhost_user}-vhost-user \ + --disable-sanitizers \ + --disable-hvf \ + --disable-whpx \ + --${have_malloc_trim}-malloc-trim \ + --disable-membarrier \ + --enable-vhost-crypto \ + --disable-libxml2 \ + --enable-capstone \ --audio-drv-list= \ - --block-drv-rw-whitelist=qcow2,raw,file,host_device,nbd,iscsi,${gluster_driver}${rbd_driver}${vxhs_driver}blkdebug,luks,null-co \ + --enable-git-update \ + --block-drv-rw-whitelist=qcow2,raw,file,host_device,nbd,iscsi,${gluster_driver}${rbd_driver}${vxhs_driver}blkdebug,luks,null-co,nvme,copy-on-read,throttle \ --block-drv-ro-whitelist=vmdk,vhdx,vpc,https,ssh \ --rhel-target=${rhel_target} \ "$@" diff --git a/SOURCES/kvm-AArch64-Add-virt-rhel7.6-machine-type.patch b/SOURCES/kvm-AArch64-Add-virt-rhel7.6-machine-type.patch new file mode 100644 index 0000000..eed9fc0 --- /dev/null +++ b/SOURCES/kvm-AArch64-Add-virt-rhel7.6-machine-type.patch @@ -0,0 +1,51 @@ +From a35c8f28c25c62d5b371a77156a5b810fa6455da Mon Sep 17 00:00:00 2001 +From: Wei Huang +Date: Wed, 28 Mar 2018 18:58:55 +0200 +Subject: [PATCH 01/13] AArch64: Add virt-rhel7.6 machine type + +RH-Author: Wei Huang +Message-id: <20180328185856.20056-2-wei@redhat.com> +Patchwork-id: 79427 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/2] AArch64: Add virt-rhel7.6 machine type +Bugzilla: 1558723 +RH-Acked-by: Andrew Jones +RH-Acked-by: Auger Eric +RH-Acked-by: Laszlo Ersek + +This patch adds "virt-rhel7.6" machine type. Because RHEL 7.5 virt-arm +was a preview product, we remove the "virt-rhel7.5" type to avoid the +legacy support burden. + +Signed-off-by: Wei Huang +Signed-off-by: Miroslav Rezanina +--- + hw/arm/virt.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 806eb1e..a4d0f52 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -1820,7 +1820,7 @@ static void rhel_machine_init(void) + } + type_init(rhel_machine_init); + +-static void rhel750_virt_instance_init(Object *obj) ++static void rhel760_virt_instance_init(Object *obj) + { + VirtMachineState *vms = VIRT_MACHINE(obj); + VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); +@@ -1862,8 +1862,8 @@ static void rhel750_virt_instance_init(Object *obj) + vms->irqmap=a15irqmap; + } + +-static void rhel750_virt_options(MachineClass *mc) ++static void rhel760_virt_options(MachineClass *mc) + { + SET_MACHINE_COMPAT(mc, ARM_RHEL_COMPAT); + } +-DEFINE_RHEL_MACHINE_AS_LATEST(7, 5, 0) ++DEFINE_RHEL_MACHINE_AS_LATEST(7, 6, 0) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-Acceptance-tests-add-Linux-kernel-boot-and-console-c.patch b/SOURCES/kvm-Acceptance-tests-add-Linux-kernel-boot-and-console-c.patch new file mode 100644 index 0000000..1f53c82 --- /dev/null +++ b/SOURCES/kvm-Acceptance-tests-add-Linux-kernel-boot-and-console-c.patch @@ -0,0 +1,102 @@ +From fd8563f0e3d4697334188aa25ff92f0655752602 Mon Sep 17 00:00:00 2001 +From: Yash Mankad +Date: Tue, 17 Jul 2018 23:38:08 +0200 +Subject: [PATCH 51/89] Acceptance tests: add Linux kernel boot and console + checking test + +RH-Author: Yash Mankad +Message-id: <3a22fbea648a71abf84257d69931075cafe3340e.1531870629.git.ymankad@redhat.com> +Patchwork-id: 81380 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 5/5] Acceptance tests: add Linux kernel boot and console checking test +Bugzilla: +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: John Snow +RH-Acked-by: Eduardo Habkost + +From: Cleber Rosa + +This test boots a Linux kernel, and checks that the given command +line was effective in two ways: + + * It makes the kernel use the set "console device" as a console + * The kernel records the command line as expected in the console + +Given that way too many error conditions may occur, and detecting the +kernel boot progress status may not be trivial, this test relies on a +timeout to handle unexpected situations. Also, it's *not* tagged as a +quick test for obvious reasons. + +It may be useful, while interactively running/debugging this test, or +tests similar to this one, to show some of the logging channels. +Example: + + $ avocado --show=QMP,console run boot_linux_console.py + +Signed-off-by: Cleber Rosa +Message-Id: <20180530184156.15634-6-crosa@redhat.com> +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Eduardo Habkost +(cherry picked from commit c1cc73f407b890c4e7ab5bf520c0637e0364e92a) +Signed-off-by: Yash Mankad +Signed-off-by: Miroslav Rezanina +--- + tests/acceptance/boot_linux_console.py | 47 ++++++++++++++++++++++++++++++++++ + 1 file changed, 47 insertions(+) + create mode 100644 tests/acceptance/boot_linux_console.py + +diff --git a/tests/acceptance/boot_linux_console.py b/tests/acceptance/boot_linux_console.py +new file mode 100644 +index 0000000..98324f7 +--- /dev/null ++++ b/tests/acceptance/boot_linux_console.py +@@ -0,0 +1,47 @@ ++# Functional test that boots a Linux kernel and checks the console ++# ++# Copyright (c) 2018 Red Hat, Inc. ++# ++# Author: ++# Cleber Rosa ++# ++# This work is licensed under the terms of the GNU GPL, version 2 or ++# later. See the COPYING file in the top-level directory. ++ ++import logging ++ ++from avocado_qemu import Test ++ ++ ++class BootLinuxConsole(Test): ++ """ ++ Boots a x86_64 Linux kernel and checks that the console is operational ++ and the kernel command line is properly passed from QEMU to the kernel ++ ++ :avocado: enable ++ :avocado: tags=x86_64 ++ """ ++ ++ timeout = 60 ++ ++ def test(self): ++ kernel_url = ('https://mirrors.kernel.org/fedora/releases/28/' ++ 'Everything/x86_64/os/images/pxeboot/vmlinuz') ++ kernel_hash = '238e083e114c48200f80d889f7e32eeb2793e02a' ++ kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) ++ ++ self.vm.set_machine('pc') ++ self.vm.set_console() ++ kernel_command_line = 'console=ttyS0' ++ self.vm.add_args('-kernel', kernel_path, ++ '-append', kernel_command_line) ++ self.vm.launch() ++ console = self.vm.console_socket.makefile() ++ console_logger = logging.getLogger('console') ++ while True: ++ msg = console.readline() ++ console_logger.debug(msg.strip()) ++ if 'Kernel command line: %s' % kernel_command_line in msg: ++ break ++ if 'Kernel panic - not syncing' in msg: ++ self.fail("Kernel panic reached") +-- +1.8.3.1 + diff --git a/SOURCES/kvm-Acceptance-tests-add-quick-VNC-tests.patch b/SOURCES/kvm-Acceptance-tests-add-quick-VNC-tests.patch new file mode 100644 index 0000000..46c3d24 --- /dev/null +++ b/SOURCES/kvm-Acceptance-tests-add-quick-VNC-tests.patch @@ -0,0 +1,104 @@ +From 6d28e6c096b3015387788dc1f140df0be3c28a6f Mon Sep 17 00:00:00 2001 +From: Yash Mankad +Date: Tue, 17 Jul 2018 23:38:06 +0200 +Subject: [PATCH 49/89] Acceptance tests: add quick VNC tests +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Yash Mankad +Message-id: <51cad6473c9d59a780befb5d96c8534affd938cf.1531870629.git.ymankad@redhat.com> +Patchwork-id: 81383 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 3/5] Acceptance tests: add quick VNC tests +Bugzilla: +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: John Snow +RH-Acked-by: Eduardo Habkost + +From: Cleber Rosa + +This patch adds a few simple behavior tests for VNC. + +Signed-off-by: Cleber Rosa +Reviewed-by: Stefan Hajnoczi +Message-Id: <20180530184156.15634-4-crosa@redhat.com> +Reviewed-by: Philippe Mathieu-Daudé +Tested-by: Philippe Mathieu-Daudé +Signed-off-by: Eduardo Habkost +(cherry picked from commit 7b1bd11cff0915a1266c34bdfb66d70f6372340d) +Signed-off-by: Yash Mankad +Signed-off-by: Miroslav Rezanina +--- + tests/acceptance/vnc.py | 60 +++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 60 insertions(+) + create mode 100644 tests/acceptance/vnc.py + +diff --git a/tests/acceptance/vnc.py b/tests/acceptance/vnc.py +new file mode 100644 +index 0000000..b1ef9d7 +--- /dev/null ++++ b/tests/acceptance/vnc.py +@@ -0,0 +1,60 @@ ++# Simple functional tests for VNC functionality ++# ++# Copyright (c) 2018 Red Hat, Inc. ++# ++# Author: ++# Cleber Rosa ++# ++# This work is licensed under the terms of the GNU GPL, version 2 or ++# later. See the COPYING file in the top-level directory. ++ ++from avocado_qemu import Test ++ ++ ++class Vnc(Test): ++ """ ++ :avocado: enable ++ :avocado: tags=vnc,quick ++ """ ++ def test_no_vnc(self): ++ self.vm.add_args('-nodefaults', '-S') ++ self.vm.launch() ++ self.assertFalse(self.vm.qmp('query-vnc')['return']['enabled']) ++ ++ def test_no_vnc_change_password(self): ++ self.vm.add_args('-nodefaults', '-S') ++ self.vm.launch() ++ self.assertFalse(self.vm.qmp('query-vnc')['return']['enabled']) ++ set_password_response = self.vm.qmp('change', ++ device='vnc', ++ target='password', ++ arg='new_password') ++ self.assertIn('error', set_password_response) ++ self.assertEqual(set_password_response['error']['class'], ++ 'GenericError') ++ self.assertEqual(set_password_response['error']['desc'], ++ 'Could not set password') ++ ++ def test_vnc_change_password_requires_a_password(self): ++ self.vm.add_args('-nodefaults', '-S', '-vnc', ':0') ++ self.vm.launch() ++ self.assertTrue(self.vm.qmp('query-vnc')['return']['enabled']) ++ set_password_response = self.vm.qmp('change', ++ device='vnc', ++ target='password', ++ arg='new_password') ++ self.assertIn('error', set_password_response) ++ self.assertEqual(set_password_response['error']['class'], ++ 'GenericError') ++ self.assertEqual(set_password_response['error']['desc'], ++ 'Could not set password') ++ ++ def test_vnc_change_password(self): ++ self.vm.add_args('-nodefaults', '-S', '-vnc', ':0,password') ++ self.vm.launch() ++ self.assertTrue(self.vm.qmp('query-vnc')['return']['enabled']) ++ set_password_response = self.vm.qmp('change', ++ device='vnc', ++ target='password', ++ arg='new_password') ++ self.assertEqual(set_password_response['return'], {}) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-Add-functional-acceptance-tests-infrastructure.patch b/SOURCES/kvm-Add-functional-acceptance-tests-infrastructure.patch new file mode 100644 index 0000000..b696dfc --- /dev/null +++ b/SOURCES/kvm-Add-functional-acceptance-tests-infrastructure.patch @@ -0,0 +1,359 @@ +From b041318485f538aa5bc9a34a010a629d45bbc73d Mon Sep 17 00:00:00 2001 +From: Yash Mankad +Date: Tue, 17 Jul 2018 23:38:04 +0200 +Subject: [PATCH 47/89] Add functional/acceptance tests infrastructure +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Yash Mankad +Message-id: +Patchwork-id: 81382 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 1/5] Add functional/acceptance tests infrastructure +Bugzilla: +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: John Snow +RH-Acked-by: Eduardo Habkost + +From: Cleber Rosa + +This patch adds the very minimum infrastructure necessary for writing +and running functional/acceptance tests, including: + + * Documentation + * The avocado_qemu.Test base test class + * One example tests (version.py) + +Additional functionality is expected to be added along the tests that +require them. + +Signed-off-by: Cleber Rosa +Message-Id: <20180530184156.15634-2-crosa@redhat.com> +Reviewed-by: Philippe Mathieu-Daudé +Tested-by: Philippe Mathieu-Daudé +[ehabkost: fix typo on testing.rst] +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Eduardo Habkost +(cherry picked from commit c3d7e8c90db208b1d876f8d6458c2dfca169137f) +Signed-off-by: Yash Mankad + +Signed-off-by: Miroslav Rezanina +--- + docs/devel/testing.rst | 192 ++++++++++++++++++++++++++++++ + tests/acceptance/README.rst | 10 ++ + tests/acceptance/avocado_qemu/__init__.py | 54 +++++++++ + tests/acceptance/version.py | 24 ++++ + 4 files changed, 280 insertions(+) + create mode 100644 tests/acceptance/README.rst + create mode 100644 tests/acceptance/avocado_qemu/__init__.py + create mode 100644 tests/acceptance/version.py + +diff --git a/docs/devel/testing.rst b/docs/devel/testing.rst +index 0ca1a2d..f33e5a8 100644 +--- a/docs/devel/testing.rst ++++ b/docs/devel/testing.rst +@@ -484,3 +484,195 @@ supported. To start the fuzzer, run + + Alternatively, some command different from "qemu-img info" can be tested, by + changing the ``-c`` option. ++ ++Acceptance tests using the Avocado Framework ++============================================ ++ ++The ``tests/acceptance`` directory hosts functional tests, also known ++as acceptance level tests. They're usually higher level tests, and ++may interact with external resources and with various guest operating ++systems. ++ ++These tests are written using the Avocado Testing Framework (which must ++be installed separately) in conjunction with a the ``avocado_qemu.Test`` ++class, implemented at ``tests/acceptance/avocado_qemu``. ++ ++Tests based on ``avocado_qemu.Test`` can easily: ++ ++ * Customize the command line arguments given to the convenience ++ ``self.vm`` attribute (a QEMUMachine instance) ++ ++ * Interact with the QEMU monitor, send QMP commands and check ++ their results ++ ++ * Interact with the guest OS, using the convenience console device ++ (which may be useful to assert the effectiveness and correctness of ++ command line arguments or QMP commands) ++ ++ * Interact with external data files that accompany the test itself ++ (see ``self.get_data()``) ++ ++ * Download (and cache) remote data files, such as firmware and kernel ++ images ++ ++ * Have access to a library of guest OS images (by means of the ++ ``avocado.utils.vmimage`` library) ++ ++ * Make use of various other test related utilities available at the ++ test class itself and at the utility library: ++ ++ - http://avocado-framework.readthedocs.io/en/latest/api/test/avocado.html#avocado.Test ++ - http://avocado-framework.readthedocs.io/en/latest/api/utils/avocado.utils.html ++ ++Installation ++------------ ++ ++To install Avocado and its dependencies, run: ++ ++.. code:: ++ ++ pip install --user avocado-framework ++ ++Alternatively, follow the instructions on this link: ++ ++ http://avocado-framework.readthedocs.io/en/latest/GetStartedGuide.html#installing-avocado ++ ++Overview ++-------- ++ ++This directory provides the ``avocado_qemu`` Python module, containing ++the ``avocado_qemu.Test`` class. Here's a simple usage example: ++ ++.. code:: ++ ++ from avocado_qemu import Test ++ ++ ++ class Version(Test): ++ """ ++ :avocado: enable ++ :avocado: tags=quick ++ """ ++ def test_qmp_human_info_version(self): ++ self.vm.launch() ++ res = self.vm.command('human-monitor-command', ++ command_line='info version') ++ self.assertRegexpMatches(res, r'^(\d+\.\d+\.\d)') ++ ++To execute your test, run: ++ ++.. code:: ++ ++ avocado run version.py ++ ++Tests may be classified according to a convention by using docstring ++directives such as ``:avocado: tags=TAG1,TAG2``. To run all tests ++in the current directory, tagged as "quick", run: ++ ++.. code:: ++ ++ avocado run -t quick . ++ ++The ``avocado_qemu.Test`` base test class ++----------------------------------------- ++ ++The ``avocado_qemu.Test`` class has a number of characteristics that ++are worth being mentioned right away. ++ ++First of all, it attempts to give each test a ready to use QEMUMachine ++instance, available at ``self.vm``. Because many tests will tweak the ++QEMU command line, launching the QEMUMachine (by using ``self.vm.launch()``) ++is left to the test writer. ++ ++At test "tear down", ``avocado_qemu.Test`` handles the QEMUMachine ++shutdown. ++ ++QEMUMachine ++~~~~~~~~~~~ ++ ++The QEMUMachine API is already widely used in the Python iotests, ++device-crash-test and other Python scripts. It's a wrapper around the ++execution of a QEMU binary, giving its users: ++ ++ * the ability to set command line arguments to be given to the QEMU ++ binary ++ ++ * a ready to use QMP connection and interface, which can be used to ++ send commands and inspect its results, as well as asynchronous ++ events ++ ++ * convenience methods to set commonly used command line arguments in ++ a more succinct and intuitive way ++ ++QEMU binary selection ++~~~~~~~~~~~~~~~~~~~~~ ++ ++The QEMU binary used for the ``self.vm`` QEMUMachine instance will ++primarily depend on the value of the ``qemu_bin`` parameter. If it's ++not explicitly set, its default value will be the result of a dynamic ++probe in the same source tree. A suitable binary will be one that ++targets the architecture matching host machine. ++ ++Based on this description, test writers will usually rely on one of ++the following approaches: ++ ++1) Set ``qemu_bin``, and use the given binary ++ ++2) Do not set ``qemu_bin``, and use a QEMU binary named like ++ "${arch}-softmmu/qemu-system-${arch}", either in the current ++ working directory, or in the current source tree. ++ ++The resulting ``qemu_bin`` value will be preserved in the ++``avocado_qemu.Test`` as an attribute with the same name. ++ ++Attribute reference ++------------------- ++ ++Besides the attributes and methods that are part of the base ++``avocado.Test`` class, the following attributes are available on any ++``avocado_qemu.Test`` instance. ++ ++vm ++~~ ++ ++A QEMUMachine instance, initially configured according to the given ++``qemu_bin`` parameter. ++ ++qemu_bin ++~~~~~~~~ ++ ++The preserved value of the ``qemu_bin`` parameter or the result of the ++dynamic probe for a QEMU binary in the current working directory or ++source tree. ++ ++Parameter reference ++------------------- ++ ++To understand how Avocado parameters are accessed by tests, and how ++they can be passed to tests, please refer to:: ++ ++ http://avocado-framework.readthedocs.io/en/latest/WritingTests.html#accessing-test-parameters ++ ++Parameter values can be easily seen in the log files, and will look ++like the following: ++ ++.. code:: ++ ++ PARAMS (key=qemu_bin, path=*, default=x86_64-softmmu/qemu-system-x86_64) => 'x86_64-softmmu/qemu-system-x86_64 ++ ++qemu_bin ++~~~~~~~~ ++ ++The exact QEMU binary to be used on QEMUMachine. ++ ++Uninstalling Avocado ++-------------------- ++ ++If you've followed the installation instructions above, you can easily ++uninstall Avocado. Start by listing the packages you have installed:: ++ ++ pip list --user ++ ++And remove any package you want with:: ++ ++ pip uninstall +diff --git a/tests/acceptance/README.rst b/tests/acceptance/README.rst +new file mode 100644 +index 0000000..89260fa +--- /dev/null ++++ b/tests/acceptance/README.rst +@@ -0,0 +1,10 @@ ++============================================ ++Acceptance tests using the Avocado Framework ++============================================ ++ ++This directory contains functional tests, also known as acceptance ++level tests. They're usually higher level, and may interact with ++external resources and with various guest operating systems. ++ ++For more information, please refer to ``docs/devel/testing.rst``, ++section "Acceptance tests using the Avocado Framework". +diff --git a/tests/acceptance/avocado_qemu/__init__.py b/tests/acceptance/avocado_qemu/__init__.py +new file mode 100644 +index 0000000..1e54fd5 +--- /dev/null ++++ b/tests/acceptance/avocado_qemu/__init__.py +@@ -0,0 +1,54 @@ ++# Test class and utilities for functional tests ++# ++# Copyright (c) 2018 Red Hat, Inc. ++# ++# Author: ++# Cleber Rosa ++# ++# This work is licensed under the terms of the GNU GPL, version 2 or ++# later. See the COPYING file in the top-level directory. ++ ++import os ++import sys ++ ++import avocado ++ ++SRC_ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) ++SRC_ROOT_DIR = os.path.abspath(os.path.dirname(SRC_ROOT_DIR)) ++sys.path.append(os.path.join(SRC_ROOT_DIR, 'scripts')) ++ ++from qemu import QEMUMachine ++ ++def is_readable_executable_file(path): ++ return os.path.isfile(path) and os.access(path, os.R_OK | os.X_OK) ++ ++ ++def pick_default_qemu_bin(): ++ """ ++ Picks the path of a QEMU binary, starting either in the current working ++ directory or in the source tree root directory. ++ """ ++ arch = os.uname()[4] ++ qemu_bin_relative_path = os.path.join("%s-softmmu" % arch, ++ "qemu-system-%s" % arch) ++ if is_readable_executable_file(qemu_bin_relative_path): ++ return qemu_bin_relative_path ++ ++ qemu_bin_from_src_dir_path = os.path.join(SRC_ROOT_DIR, ++ qemu_bin_relative_path) ++ if is_readable_executable_file(qemu_bin_from_src_dir_path): ++ return qemu_bin_from_src_dir_path ++ ++ ++class Test(avocado.Test): ++ def setUp(self): ++ self.vm = None ++ self.qemu_bin = self.params.get('qemu_bin', ++ default=pick_default_qemu_bin()) ++ if self.qemu_bin is None: ++ self.cancel("No QEMU binary defined or found in the source tree") ++ self.vm = QEMUMachine(self.qemu_bin) ++ ++ def tearDown(self): ++ if self.vm is not None: ++ self.vm.shutdown() +diff --git a/tests/acceptance/version.py b/tests/acceptance/version.py +new file mode 100644 +index 0000000..13b0a74 +--- /dev/null ++++ b/tests/acceptance/version.py +@@ -0,0 +1,24 @@ ++# Version check example test ++# ++# Copyright (c) 2018 Red Hat, Inc. ++# ++# Author: ++# Cleber Rosa ++# ++# This work is licensed under the terms of the GNU GPL, version 2 or ++# later. See the COPYING file in the top-level directory. ++ ++ ++from avocado_qemu import Test ++ ++ ++class Version(Test): ++ """ ++ :avocado: enable ++ :avocado: tags=quick ++ """ ++ def test_qmp_human_info_version(self): ++ self.vm.launch() ++ res = self.vm.command('human-monitor-command', ++ command_line='info version') ++ self.assertRegexpMatches(res, r'^(\d+\.\d+\.\d)') +-- +1.8.3.1 + diff --git a/SOURCES/kvm-BZ1513294-spapr-Include-pre-plugged-DIMMS-in-ram-siz.patch b/SOURCES/kvm-BZ1513294-spapr-Include-pre-plugged-DIMMS-in-ram-siz.patch deleted file mode 100644 index 50f4b40..0000000 --- a/SOURCES/kvm-BZ1513294-spapr-Include-pre-plugged-DIMMS-in-ram-siz.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 35dcc0b1cf6cf7e031f5e4f9bfd3eab9e98044dc Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Tue, 5 Dec 2017 04:18:21 +0100 -Subject: [PATCH 15/21] BZ1513294: spapr: Include "pre-plugged" DIMMS in ram - size calculation at reset - -RH-Author: David Gibson -Message-id: <20171205041821.28985-1-dgibson@redhat.com> -Patchwork-id: 78132 -O-Subject: [RHL-7.5 qemu-kvm-rhev PATCH] BZ1513294: spapr: Include "pre-plugged" DIMMS in ram size calculation at reset -Bugzilla: 1513294 -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier -RH-Acked-by: Igor Mammedov - -From: David Gibson - -At guest reset time, we allocate a hash page table (HPT) for the guest -based on the guest's RAM size. If dynamic HPT resizing is not available we -use the maximum RAM size, if it is we use the current RAM size. - -But the "current RAM size" calculation is incorrect - we just use the -"base" ram_size from the machine structure. This doesn't include any -pluggable DIMMs that are already plugged at reset time. - -This means that if you try to start a 'pseries' machine with a DIMM -specified on the command line that's much larger than the "base" RAM size, -then the guest will get a woefully inadequate HPT. This can lead to a -guest freeze during boot as it runs out of HPT space during initial MMU -setup. - -Signed-off-by: David Gibson -Reviewed-by: Greg Kurz -Tested-by: Greg Kurz -(cherry picked from commit 768a20f3a491ed4afce73ebb65347d55251c0ebd) - -Slightly modified logic downstream because we don't have the -get_plugged_memory_size() helper. - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index e3dce84..af7a3bb 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -1369,7 +1369,11 @@ void spapr_setup_hpt_and_vrma(sPAPRMachineState *spapr) - && !spapr_ovec_test(spapr->ov5_cas, OV5_HPT_RESIZE))) { - hpt_shift = spapr_hpt_shift_for_ramsize(MACHINE(spapr)->maxram_size); - } else { -- hpt_shift = spapr_hpt_shift_for_ramsize(MACHINE(spapr)->ram_size); -+ uint64_t current_ram_size; -+ -+ current_ram_size = MACHINE(spapr)->ram_size + -+ pc_existing_dimms_capacity(&error_fatal); -+ hpt_shift = spapr_hpt_shift_for_ramsize(current_ram_size); - } - spapr_reallocate_hpt(spapr, hpt_shift, &error_fatal); - --- -1.8.3.1 - diff --git a/SOURCES/kvm-Create-x86-7.5.0-machine-types.patch b/SOURCES/kvm-Create-x86-7.5.0-machine-types.patch deleted file mode 100644 index 6b24cfb..0000000 --- a/SOURCES/kvm-Create-x86-7.5.0-machine-types.patch +++ /dev/null @@ -1,127 +0,0 @@ -From 9b07271835af176f2f10c0c50b520701e0bfc6e4 Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Tue, 10 Oct 2017 10:36:01 +0200 -Subject: [PATCH 09/69] Create x86 7.5.0 machine types - -RH-Author: Dr. David Alan Gilbert -Message-id: <20171010103601.7723-2-dgilbert@redhat.com> -Patchwork-id: 77054 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 1/1] Create x86 7.5.0 machine types -Bugzilla: 1499011 -RH-Acked-by: Laurent Vivier -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Paolo Bonzini - -From: "Dr. David Alan Gilbert" - -Not that much change from 2.9.0 - -Signed-off-by: Dr. David Alan Gilbert -Signed-off-by: Miroslav Rezanina ---- - hw/i386/pc_piix.c | 21 ++++++++++++++++++++- - hw/i386/pc_q35.c | 19 ++++++++++++++++++- - include/hw/i386/pc.h | 9 +++++++++ - 3 files changed, 47 insertions(+), 2 deletions(-) - -diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c -index 7f12ce3..935391f 100644 ---- a/hw/i386/pc_piix.c -+++ b/hw/i386/pc_piix.c -@@ -1141,6 +1141,21 @@ static void pc_machine_rhel7_options(MachineClass *m) - m->is_default = 1; - } - -+static void pc_init_rhel750(MachineState *machine) -+{ -+ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \ -+ TYPE_I440FX_PCI_DEVICE); -+} -+ -+static void pc_machine_rhel750_options(MachineClass *m) -+{ -+ pc_machine_rhel7_options(m); -+ m->desc = "RHEL 7.5.0 PC (i440FX + PIIX, 1996)"; -+} -+ -+DEFINE_PC_MACHINE(rhel750, "pc-i440fx-rhel7.5.0", pc_init_rhel750, -+ pc_machine_rhel750_options); -+ - static void pc_init_rhel740(MachineState *machine) - { - pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \ -@@ -1149,8 +1164,12 @@ static void pc_init_rhel740(MachineState *machine) - - static void pc_machine_rhel740_options(MachineClass *m) - { -- pc_machine_rhel7_options(m); -+ pc_machine_rhel750_options(m); -+ m->alias = NULL; -+ m->is_default = 0; - m->desc = "RHEL 7.4.0 PC (i440FX + PIIX, 1996)"; -+ m->numa_auto_assign_ram = numa_legacy_auto_assign_ram; -+ SET_MACHINE_COMPAT(m, PC_RHEL7_4_COMPAT); - } - - DEFINE_PC_MACHINE(rhel740, "pc-i440fx-rhel7.4.0", pc_init_rhel740, -diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c -index 575d407..e73097b 100644 ---- a/hw/i386/pc_q35.c -+++ b/hw/i386/pc_q35.c -@@ -395,6 +395,20 @@ static void pc_q35_machine_rhel7_options(MachineClass *m) - SET_MACHINE_COMPAT(m, PC_RHEL_COMPAT); - } - -+static void pc_q35_init_rhel750(MachineState *machine) -+{ -+ pc_q35_init(machine); -+} -+ -+static void pc_q35_machine_rhel750_options(MachineClass *m) -+{ -+ pc_q35_machine_rhel7_options(m); -+ m->desc = "RHEL-7.5.0 PC (Q35 + ICH9, 2009)"; -+} -+ -+DEFINE_PC_MACHINE(q35_rhel750, "pc-q35-rhel7.5.0", pc_q35_init_rhel750, -+ pc_q35_machine_rhel750_options); -+ - static void pc_q35_init_rhel740(MachineState *machine) - { - pc_q35_init(machine); -@@ -402,8 +416,11 @@ static void pc_q35_init_rhel740(MachineState *machine) - - static void pc_q35_machine_rhel740_options(MachineClass *m) - { -- pc_q35_machine_rhel7_options(m); -+ pc_q35_machine_rhel750_options(m); -+ m->alias = NULL; - m->desc = "RHEL-7.4.0 PC (Q35 + ICH9, 2009)"; -+ m->numa_auto_assign_ram = numa_legacy_auto_assign_ram; -+ SET_MACHINE_COMPAT(m, PC_RHEL7_4_COMPAT); - } - - DEFINE_PC_MACHINE(q35_rhel740, "pc-q35-rhel7.4.0", pc_q35_init_rhel740, -diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h -index b808a9b..89bdaa4 100644 ---- a/include/hw/i386/pc.h -+++ b/include/hw/i386/pc.h -@@ -1001,6 +1001,15 @@ extern void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id); - .value = "on",\ - }, - -+#define PC_RHEL7_4_COMPAT \ -+ HW_COMPAT_RHEL7_4 \ -+ { /* PC_RHEL7_4_COMPAT from PC_COMPAT_2_9 */ \ -+ .driver = "mch",\ -+ .property = "extended-tseg-mbytes",\ -+ .value = stringify(0),\ -+ }, -+ -+ - #define PC_RHEL7_3_COMPAT \ - HW_COMPAT_RHEL7_3 \ - { /* PC_RHEL7_3_COMPAT from PC_COMPAT_2_8 */ \ --- -1.8.3.1 - diff --git a/SOURCES/kvm-Disable-AT24Cx-i2c-eeprom.patch b/SOURCES/kvm-Disable-AT24Cx-i2c-eeprom.patch new file mode 100644 index 0000000..a51edd4 --- /dev/null +++ b/SOURCES/kvm-Disable-AT24Cx-i2c-eeprom.patch @@ -0,0 +1,40 @@ +From 2cb498c245b670f98ee4d05c16766d95811ff2f3 Mon Sep 17 00:00:00 2001 +From: Miroslav Rezanina +Date: Thu, 7 Jun 2018 07:43:11 +0200 +Subject: [PATCH 03/15] Disable AT24Cx i2c eeprom + +RH-Author: Miroslav Rezanina +Message-id: +Patchwork-id: 80598 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 3/7] Disable AT24Cx i2c eeprom +Bugzilla: 1586357 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier +RH-Acked-by: Markus Armbruster + +From: Miroslav Rezanina + +We do not want to support new eeprom_at24c device. It is protected +by CONFIG_I2C option but we can't remove it as it cover other supported +devices. Manually remove module with the device. + +Signed-off-by: Miroslav Rezanina +--- + hw/nvram/Makefile.objs | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/nvram/Makefile.objs b/hw/nvram/Makefile.objs +index a912d25..cbc8bba 100644 +--- a/hw/nvram/Makefile.objs ++++ b/hw/nvram/Makefile.objs +@@ -1,6 +1,6 @@ + common-obj-$(CONFIG_DS1225Y) += ds1225y.o + common-obj-y += eeprom93xx.o +-common-obj-$(CONFIG_I2C) += eeprom_at24c.o ++#common-obj-$(CONFIG_I2C) += eeprom_at24c.o + common-obj-y += fw_cfg.o + common-obj-y += chrp_nvram.o + common-obj-$(CONFIG_MAC_NVRAM) += mac_nvram.o +-- +1.8.3.1 + diff --git a/SOURCES/kvm-Disable-CAN-bus-devices.patch b/SOURCES/kvm-Disable-CAN-bus-devices.patch new file mode 100644 index 0000000..cdac317 --- /dev/null +++ b/SOURCES/kvm-Disable-CAN-bus-devices.patch @@ -0,0 +1,40 @@ +From 354b15f627251bf85363350a529cface7eef208d Mon Sep 17 00:00:00 2001 +From: Miroslav Rezanina +Date: Thu, 7 Jun 2018 07:43:12 +0200 +Subject: [PATCH 04/15] Disable CAN bus devices + +RH-Author: Miroslav Rezanina +Message-id: <706a21b4d25946165513ff99619c0fed0852dc50.1528355911.git.mrezanin@redhat.com> +Patchwork-id: 80593 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 4/7] Disable CAN bus devices +Bugzilla: 1586357 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier +RH-Acked-by: Markus Armbruster + +From: Miroslav Rezanina + +We do not want to support new CAN devices (kvaser_pci, mioe3680_pci +and pcm3680_pci). + +Signed-off-by: Miroslav Rezanina +--- + default-configs/pci.mak | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/default-configs/pci.mak b/default-configs/pci.mak +index 4c8c296..25fc382 100644 +--- a/default-configs/pci.mak ++++ b/default-configs/pci.mak +@@ -33,7 +33,7 @@ CONFIG_SERIAL_ISA=y + CONFIG_SERIAL_PCI=y + CONFIG_CAN_BUS=y + CONFIG_CAN_SJA1000=y +-CONFIG_CAN_PCI=y ++#CONFIG_CAN_PCI=y + #CONFIG_IPACK=y + CONFIG_WDT_IB6300ESB=y + CONFIG_PCI_TESTDEV=y +-- +1.8.3.1 + diff --git a/SOURCES/kvm-Disable-GeForce-quirks-in-vfio-pci-for-RHEL-machines.patch b/SOURCES/kvm-Disable-GeForce-quirks-in-vfio-pci-for-RHEL-machines.patch deleted file mode 100644 index d6e735b..0000000 --- a/SOURCES/kvm-Disable-GeForce-quirks-in-vfio-pci-for-RHEL-machines.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 332f7a6f8dd4ee6fae95c87e717d4527ca9344a7 Mon Sep 17 00:00:00 2001 -From: Alex Williamson -Date: Tue, 13 Feb 2018 19:04:56 +0100 -Subject: [PATCH 15/15] Disable GeForce quirks in vfio-pci for RHEL machines - -RH-Author: Alex Williamson -Message-id: <20180213190456.27565.18217.stgit@gimli.home> -Patchwork-id: 78999 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH v2 2/2] [RHEL] Disable GeForce quirks in vfio-pci for RHEL machines -Bugzilla: 1508330 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Auger Eric -RH-Acked-by: Marcel Apfelbaum - -RHEL-ONLY - The GeForce quirks are primarily used to virtualize the -various ways the driver and VGA BIOS has available to access PCI -config space using alternate memory regions, ex. MMIO and I/O port. -Generally these quirks are benign and even where not required, do not -interfere with operation. However, NVIDIA has a strange MSI behavior -where the MSI interrupt will not re-trigger until the driver writes -back to specifc addresses in config space via the MMIO mirror. Since -we virtualize the mirror for GeForce, every MSI interrupt requires an -exit to QEMU to handle this MSI-ACK behavior. For very high interrupt -rate applications, such as NVIDIA's DolphinVS test program, this -virtualization causes enough overhead to degrade the performance. - -RHEL does not support GeForce assignment and supported configurations -using Quadro, GRID, or Tesla assignment, including NVIDIA vGPU, do not -require these quirks. We can therefore disable these quirks by -default, removing this overhead for supported configurations while -still allowing unsupported configurations access to re-enable them -via (equally unsupported) options. - -Upstream development is underway to mitigate this performance overhead -even for GeForce, but preliminary results show that we can only -achieve 95% of the performance of disabling the quirk entirely via an -ioeventfd approach. Obviously detecting GeForce vs Quadro would also -be a useful approach, but there's no clear way to do this aside from -scraping device descriptions from libpci. Therefore, disabling -GeForce quirks, with unsupported mechanisms to re-enable unsupported -configurations, seems like the best approach for RHEL/RHV. - -Signed-off-by: Alex Williamson -Signed-off-by: Miroslav Rezanina ---- - include/hw/i386/pc.h | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h -index d1b1320..2b35ed8 100644 ---- a/include/hw/i386/pc.h -+++ b/include/hw/i386/pc.h -@@ -1002,6 +1002,11 @@ extern void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id); - .driver = TYPE_X86_CPU,\ - .property = "host-phys-bits",\ - .value = "on",\ -+ },\ -+ { /* PC_RHEL_COMPAT bz 1508330 */ \ -+ .driver = "vfio-pci",\ -+ .property = "x-no-geforce-quirks",\ -+ .value = "on",\ - }, - - #define PC_RHEL7_4_COMPAT \ --- -1.8.3.1 - diff --git a/SOURCES/kvm-Disable-PCIe-to-PCI-bridge-device.patch b/SOURCES/kvm-Disable-PCIe-to-PCI-bridge-device.patch new file mode 100644 index 0000000..2525c64 --- /dev/null +++ b/SOURCES/kvm-Disable-PCIe-to-PCI-bridge-device.patch @@ -0,0 +1,38 @@ +From d496bec5b14df55d49658a283326ad720f974a0a Mon Sep 17 00:00:00 2001 +From: Miroslav Rezanina +Date: Thu, 7 Jun 2018 07:43:15 +0200 +Subject: [PATCH 07/15] Disable PCIe-to-PCI bridge device + +RH-Author: Miroslav Rezanina +Message-id: +Patchwork-id: 80594 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 7/7] Disable PCIe-to-PCI bridge device +Bugzilla: 1586357 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Laurent Vivier + +From: Miroslav Rezanina + +There's new pcie-to-pci device we do not want to support it. + +Signed-off-by: Miroslav Rezanina +--- + hw/pci-bridge/Makefile.objs | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/pci-bridge/Makefile.objs b/hw/pci-bridge/Makefile.objs +index 47065f8..68db0da 100644 +--- a/hw/pci-bridge/Makefile.objs ++++ b/hw/pci-bridge/Makefile.objs +@@ -1,5 +1,6 @@ + common-obj-y += pci_bridge_dev.o +-common-obj-$(CONFIG_PCIE_PORT) += pcie_root_port.o gen_pcie_root_port.o pcie_pci_bridge.o ++common-obj-$(CONFIG_PCIE_PORT) += pcie_root_port.o gen_pcie_root_port.o ++#common-obj-$(CONFIG_PCIE_PORT) += pcie_pci_bridge.o + common-obj-$(CONFIG_PXB) += pci_expander_bridge.o + common-obj-$(CONFIG_XIO3130) += xio3130_upstream.o xio3130_downstream.o + common-obj-$(CONFIG_IOH3420) += ioh3420.o +-- +1.8.3.1 + diff --git a/SOURCES/kvm-Disable-aarch64-devices-reappeared-after-2.12-rebase.patch b/SOURCES/kvm-Disable-aarch64-devices-reappeared-after-2.12-rebase.patch new file mode 100644 index 0000000..ff255f7 --- /dev/null +++ b/SOURCES/kvm-Disable-aarch64-devices-reappeared-after-2.12-rebase.patch @@ -0,0 +1,43 @@ +From db40ec43617c802b5dff4af43c095924bea17ac6 Mon Sep 17 00:00:00 2001 +From: Miroslav Rezanina +Date: Thu, 7 Jun 2018 07:43:09 +0200 +Subject: [PATCH 01/15] Disable aarch64 devices reappeared after 2.12 rebase + +RH-Author: Miroslav Rezanina +Message-id: +Patchwork-id: 80592 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/7] Disable aarch64 devices reappeared after 2.12 rebase +Bugzilla: 1586357 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Laurent Vivier + +From: Miroslav Rezanina + +Up to QEMU 2.11 we disabled aarch64 devices by removing files from +Makefile. +As default_config options were added, we use them to disable devices +since 2.12. However, we can't turn CONFIG_ARM_V7M (turning it off will +break build) so we have to manually remove armv7m module from Makefile. + +Signed-off-by: Miroslav Rezanina +--- + hw/arm/Makefile.objs | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs +index 2885e3e..3e8b167 100644 +--- a/hw/arm/Makefile.objs ++++ b/hw/arm/Makefile.objs +@@ -16,7 +16,7 @@ obj-$(CONFIG_STRONGARM) += collie.o + obj-$(CONFIG_VERSATILE) += vexpress.o versatilepb.o + obj-$(CONFIG_ZYNQ) += xilinx_zynq.o + +-obj-$(CONFIG_ARM_V7M) += armv7m.o ++#obj-$(CONFIG_ARM_V7M) += armv7m.o + obj-$(CONFIG_EXYNOS4) += exynos4210.o + obj-$(CONFIG_PXA2XX) += pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o + obj-$(CONFIG_DIGIC) += digic.o +-- +1.8.3.1 + diff --git a/SOURCES/kvm-Disable-new-pvrdma-device.patch b/SOURCES/kvm-Disable-new-pvrdma-device.patch new file mode 100644 index 0000000..b0ffdf3 --- /dev/null +++ b/SOURCES/kvm-Disable-new-pvrdma-device.patch @@ -0,0 +1,39 @@ +From dda389bad731375b9308e4fc6db7a44cdadc7b1d Mon Sep 17 00:00:00 2001 +From: Miroslav Rezanina +Date: Thu, 7 Jun 2018 07:43:14 +0200 +Subject: [PATCH 06/15] Disable new pvrdma device + +RH-Author: Miroslav Rezanina +Message-id: <5d290e25879e3ac42c247ff3c3a524001ceb0be1.1528355911.git.mrezanin@redhat.com> +Patchwork-id: 80597 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 6/7] Disable new pvrdma device +Bugzilla: 1586357 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier +RH-Acked-by: Markus Armbruster + +From: Miroslav Rezanina + +New pvrdma device was introduced in rebase to QEMU 2.12. We do not want to +support this device. + +Signed-off-by: Miroslav Rezanina +--- + hw/rdma/Makefile.objs | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/rdma/Makefile.objs b/hw/rdma/Makefile.objs +index 3504c39..02ca2a9 100644 +--- a/hw/rdma/Makefile.objs ++++ b/hw/rdma/Makefile.objs +@@ -1,5 +1,6 @@ + ifeq ($(CONFIG_RDMA),y) + obj-$(CONFIG_PCI) += rdma_utils.o rdma_backend.o rdma_rm.o + obj-$(CONFIG_PCI) += vmw/pvrdma_dev_ring.o vmw/pvrdma_cmd.o \ +- vmw/pvrdma_qp_ops.o vmw/pvrdma_main.o ++ vmw/pvrdma_qp_ops.o ++#obj-$(CONFIG_PCI) += vmw/pvrdma_main.o + endif +-- +1.8.3.1 + diff --git a/SOURCES/kvm-Disable-new-superio-devices.patch b/SOURCES/kvm-Disable-new-superio-devices.patch new file mode 100644 index 0000000..2936dec --- /dev/null +++ b/SOURCES/kvm-Disable-new-superio-devices.patch @@ -0,0 +1,38 @@ +From 5ce455e319c4e34fbe7fef78b72898d3dbc1c8c6 Mon Sep 17 00:00:00 2001 +From: Miroslav Rezanina +Date: Thu, 7 Jun 2018 07:43:13 +0200 +Subject: [PATCH 05/15] Disable new superio devices + +RH-Author: Miroslav Rezanina +Message-id: <51483d3f0091abc80d52485ab076581d4ca914c5.1528355911.git.mrezanin@redhat.com> +Patchwork-id: 80595 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 5/7] Disable new superio devices +Bugzilla: 1586357 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier +RH-Acked-by: Markus Armbruster + +From: Miroslav Rezanina + +We do not want to support new superio devices (fdc37m81x-superio and +smc37c669-superio). + +Signed-off-by: Miroslav Rezanina +--- + hw/isa/Makefile.objs | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/isa/Makefile.objs b/hw/isa/Makefile.objs +index 83e06f6..7de4f44 100644 +--- a/hw/isa/Makefile.objs ++++ b/hw/isa/Makefile.objs +@@ -1,5 +1,5 @@ + common-obj-$(CONFIG_ISA_BUS) += isa-bus.o +-common-obj-$(CONFIG_ISA_BUS) += isa-superio.o smc37c669-superio.o ++#common-obj-$(CONFIG_ISA_BUS) += isa-superio.o smc37c669-superio.o + common-obj-$(CONFIG_APM) += apm.o + common-obj-$(CONFIG_I82378) += i82378.o + common-obj-$(CONFIG_PC87312) += pc87312.o +-- +1.8.3.1 + diff --git a/SOURCES/kvm-Disable-sm501-and-sysbus-sm501-devices.patch b/SOURCES/kvm-Disable-sm501-and-sysbus-sm501-devices.patch deleted file mode 100644 index 6bdb2d3..0000000 --- a/SOURCES/kvm-Disable-sm501-and-sysbus-sm501-devices.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 28f294c02314ceaee4b5c8b4bd568c84b017546d Mon Sep 17 00:00:00 2001 -From: Miroslav Rezanina -Date: Fri, 13 Oct 2017 11:56:49 +0200 -Subject: [PATCH 18/69] Disable sm501 and sysbus-sm501 devices - -RH-Author: Miroslav Rezanina -Message-id: <20171013115649.20817-3-mrezanin@redhat.com> -Patchwork-id: 77261 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCHv2 2/2] Disable sm501 and sysbus-sm501 devices -Bugzilla: 1498496 -RH-Acked-by: Cornelia Huck -RH-Acked-by: Thomas Huth -RH-Acked-by: Laszlo Ersek - -From: Miroslav Rezanina - -We are not goint to support these devices so disable them. - -Signed-off-by: Miroslav Rezanina ---- - default-configs/ppc64-softmmu.mak | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak -index 46e356b..8de2149 100644 ---- a/default-configs/ppc64-softmmu.mak -+++ b/default-configs/ppc64-softmmu.mak -@@ -62,7 +62,7 @@ CONFIG_PSERIES=y - #CONFIG_PLATFORM_BUS=y - #CONFIG_ETSEC=y - CONFIG_LIBDECNUMBER=y --CONFIG_SM501=y -+#CONFIG_SM501=y - CONFIG_USB_OHCI=y - # For pSeries - CONFIG_XICS=$(CONFIG_PSERIES) --- -1.8.3.1 - diff --git a/SOURCES/kvm-Disable-split-irq-device.patch b/SOURCES/kvm-Disable-split-irq-device.patch new file mode 100644 index 0000000..4c36b39 --- /dev/null +++ b/SOURCES/kvm-Disable-split-irq-device.patch @@ -0,0 +1,40 @@ +From 1055193a52857bd42f7a3961f5f6dcf7edb14cef Mon Sep 17 00:00:00 2001 +From: Miroslav Rezanina +Date: Thu, 7 Jun 2018 07:43:10 +0200 +Subject: [PATCH 02/15] Disable split-irq device + +RH-Author: Miroslav Rezanina +Message-id: <63c6336171256528761f3b4aa22c058d472b048b.1528355911.git.mrezanin@redhat.com> +Patchwork-id: 80596 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 2/7] Disable split-irq device +Bugzilla: 1586357 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier +RH-Acked-by: Markus Armbruster + +From: Miroslav Rezanina + +There's new split-irq device introduced in QEMU 2.12. We do not want to +support this device. + +Signed-off-by: Miroslav Rezanina +--- + hw/core/Makefile.objs | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs +index 2b4491f..e967fb2 100644 +--- a/hw/core/Makefile.objs ++++ b/hw/core/Makefile.objs +@@ -20,7 +20,7 @@ common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o + # common-obj-$(CONFIG_SOFTMMU) += register.o + # obj-$(CONFIG_SOFTMMU) += generic-loader.o + # common-obj-$(CONFIG_SOFTMMU) += or-irq.o +-common-obj-$(CONFIG_SOFTMMU) += split-irq.o ++#common-obj-$(CONFIG_SOFTMMU) += split-irq.o + common-obj-$(CONFIG_PLATFORM_BUS) += platform-bus.o + + obj-$(CONFIG_SOFTMMU) += null-machine.o +-- +1.8.3.1 + diff --git a/SOURCES/kvm-Disable-vhost-user-scsi-and-vhost-user-scsi-pci.patch b/SOURCES/kvm-Disable-vhost-user-scsi-and-vhost-user-scsi-pci.patch deleted file mode 100644 index 5edd7a8..0000000 --- a/SOURCES/kvm-Disable-vhost-user-scsi-and-vhost-user-scsi-pci.patch +++ /dev/null @@ -1,96 +0,0 @@ -From b303e792c3084c0b5535ec58fbae84a5fd4b892b Mon Sep 17 00:00:00 2001 -From: Miroslav Rezanina -Date: Fri, 13 Oct 2017 11:56:48 +0200 -Subject: [PATCH 17/69] Disable vhost-user-scsi and vhost-user-scsi-pci - -RH-Author: Miroslav Rezanina -Message-id: <20171013115649.20817-2-mrezanin@redhat.com> -Patchwork-id: 77263 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCHv2 1/2] Disable vhost-user-scsi and vhost-user-scsi-pci -Bugzilla: 1498496 -RH-Acked-by: Cornelia Huck -RH-Acked-by: Thomas Huth -RH-Acked-by: Laszlo Ersek - -From: Miroslav Rezanina - -We are not going to support these new devices. CONFIG_VHOST_USER_SCSI option -removes only vhost-user-scsi so we have to manually disable -vhost-user-scsi-pci. - -Signed-off-by: Miroslav Rezanina ---- - default-configs/aarch64-softmmu.mak | 2 +- - default-configs/pci.mak | 2 +- - default-configs/ppc64-softmmu.mak | 2 +- - default-configs/s390x-softmmu.mak | 2 +- - hw/virtio/virtio-pci.c | 2 ++ - 5 files changed, 6 insertions(+), 4 deletions(-) - -diff --git a/default-configs/aarch64-softmmu.mak b/default-configs/aarch64-softmmu.mak -index 5d57303..a2d05f4 100644 ---- a/default-configs/aarch64-softmmu.mak -+++ b/default-configs/aarch64-softmmu.mak -@@ -22,7 +22,7 @@ CONFIG_SMBIOS=y - CONFIG_PL061=y - CONFIG_GPIO_KEY=y - CONFIG_ARM_V7M=y --CONFIG_VHOST_USER_SCSI=$(and $(CONFIG_VHOST_USER),$(CONFIG_LINUX)) -+#CONFIG_VHOST_USER_SCSI=$(and $(CONFIG_VHOST_USER),$(CONFIG_LINUX)) - CONFIG_PCIE_PORT=y - CONFIG_XIO3130=y - CONFIG_IOH3420=y -diff --git a/default-configs/pci.mak b/default-configs/pci.mak -index 9bd8452..8cf0b60 100644 ---- a/default-configs/pci.mak -+++ b/default-configs/pci.mak -@@ -43,4 +43,4 @@ CONFIG_VGA=y - CONFIG_VGA_PCI=y - CONFIG_IVSHMEM_DEVICE=$(CONFIG_IVSHMEM) - #CONFIG_ROCKER=y --CONFIG_VHOST_USER_SCSI=$(and $(CONFIG_VHOST_USER),$(CONFIG_LINUX)) -+#CONFIG_VHOST_USER_SCSI=$(and $(CONFIG_VHOST_USER),$(CONFIG_LINUX)) -diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak -index 31ef40c..46e356b 100644 ---- a/default-configs/ppc64-softmmu.mak -+++ b/default-configs/ppc64-softmmu.mak -@@ -8,7 +8,7 @@ CONFIG_USB_XHCI=y - CONFIG_USB_XHCI_NEC=y - CONFIG_WDT_IB6300ESB=y - CONFIG_PCI_TESTDEV=y --CONFIG_VHOST_USER_SCSI=$(and $(CONFIG_VHOST_USER),$(CONFIG_LINUX)) -+#CONFIG_VHOST_USER_SCSI=$(and $(CONFIG_VHOST_USER),$(CONFIG_LINUX)) - - include sound.mak - include usb.mak -diff --git a/default-configs/s390x-softmmu.mak b/default-configs/s390x-softmmu.mak -index 2846634..02f62de 100644 ---- a/default-configs/s390x-softmmu.mak -+++ b/default-configs/s390x-softmmu.mak -@@ -1,6 +1,6 @@ - CONFIG_PCI=y - #CONFIG_VIRTIO_PCI=y --CONFIG_VHOST_USER_SCSI=$(and $(CONFIG_VHOST_USER),$(CONFIG_LINUX)) -+#CONFIG_VHOST_USER_SCSI=$(and $(CONFIG_VHOST_USER),$(CONFIG_LINUX)) - CONFIG_VIRTIO=y - CONFIG_SCLPCONSOLE=y - # Disabled for Red Hat Enterprise Linux: -diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c -index eccf809..8208aa2 100644 ---- a/hw/virtio/virtio-pci.c -+++ b/hw/virtio/virtio-pci.c -@@ -2665,9 +2665,11 @@ static void virtio_pci_register_types(void) - #ifdef CONFIG_VHOST_SCSI - type_register_static(&vhost_scsi_pci_info); - #endif -+#if 0 /* Disabled for Red Hat Enterprise Linux */ - #if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX) - type_register_static(&vhost_user_scsi_pci_info); - #endif -+#endif - #ifdef CONFIG_VHOST_VSOCK - type_register_static(&vhost_vsock_pci_info); - #endif --- -1.8.3.1 - diff --git a/SOURCES/kvm-Drop-105th-key-from-en-us-keymap.patch b/SOURCES/kvm-Drop-105th-key-from-en-us-keymap.patch deleted file mode 100644 index 11d943c..0000000 --- a/SOURCES/kvm-Drop-105th-key-from-en-us-keymap.patch +++ /dev/null @@ -1,58 +0,0 @@ -From bfd55b42182f0c0c43ad0e251083a941f6af0a45 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Fri, 12 Jan 2018 10:45:52 +0100 -Subject: [PATCH 1/8] Drop 105th key from en-us keymap. - -RH-Author: Gerd Hoffmann -Message-id: <20180112104552.13782-2-kraxel@redhat.com> -Patchwork-id: 78561 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 1/1] Drop 105th key from en-us keymap. -Bugzilla: 1513870 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Thomas Huth -RH-Acked-by: Markus Armbruster - -Qemu keymap code has problems to deal with the case that multiple -keyscodes can generate the same keysym. In this specific case both -shift+comma and the 105th key map to "<". qemu picks the 105th key -instead of comma, the guest sees shift+105th key and interprets that -as ">". Oops. - -The correct fix for that is to use not only the keysym for the reverse -keycode lookup, but also the modifier state. So "<" with shift gets -mapped to shift+command and "<" without shift to the 105th key. That -requires some non-trivial changes in qemu though as right now the -reverse keymap can hold one entry per keysym only. - -Given that we are pretty late in the 7.5 cycle we take the shortcut to -simply remove the mappings for the 105th key (which isn't present anyway -on physical 104 key us keyboards, only 105 key intl keyboards running -with en-us keymap have that), to workaround this issue for the most -annonying case. - -Signed-off-by: Gerd Hoffmann -Signed-off-by: Miroslav Rezanina ---- - pc-bios/keymaps/en-us | 6 ------ - 1 file changed, 6 deletions(-) - -diff --git a/pc-bios/keymaps/en-us b/pc-bios/keymaps/en-us -index a70e03a..e518a9d 100644 ---- a/pc-bios/keymaps/en-us -+++ b/pc-bios/keymaps/en-us -@@ -343,12 +343,6 @@ KP_Decimal 0x53 numlock - - # evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) - --# evdev 86 (0x56), QKeyCode "less", number 0x56 --less 0x56 --greater 0x56 shift --bar 0x56 altgr --brokenbar 0x56 shift altgr -- - # evdev 87 (0x57), QKeyCode "f11", number 0x57 - F11 0x57 - --- -1.8.3.1 - diff --git a/SOURCES/kvm-Fix-permissions-for-iotest-218.patch b/SOURCES/kvm-Fix-permissions-for-iotest-218.patch new file mode 100644 index 0000000..94ea738 --- /dev/null +++ b/SOURCES/kvm-Fix-permissions-for-iotest-218.patch @@ -0,0 +1,16 @@ +From e19d458c0569611dee562575e03968844bea0252 Mon Sep 17 00:00:00 2001 +From: Miroslav Rezanina +Date: Wed, 27 Jun 2018 14:42:36 +0200 +Subject: [PATCH 01/89] Fix permissions for iotest 218 + +--- + tests/qemu-iotests/218 | 0 + 1 file changed, 0 insertions(+), 0 deletions(-) + mode change 100644 => 100755 tests/qemu-iotests/218 + +diff --git a/tests/qemu-iotests/218 b/tests/qemu-iotests/218 +old mode 100644 +new mode 100755 +-- +1.8.3.1 + diff --git a/SOURCES/kvm-Fix-x-hv-max-vps-compat-value-for-7.4-machine-type.patch b/SOURCES/kvm-Fix-x-hv-max-vps-compat-value-for-7.4-machine-type.patch new file mode 100644 index 0000000..c5672ce --- /dev/null +++ b/SOURCES/kvm-Fix-x-hv-max-vps-compat-value-for-7.4-machine-type.patch @@ -0,0 +1,60 @@ +From b6128137787bb3c5e05c41013cb4f6cf6c0edf6a Mon Sep 17 00:00:00 2001 +From: Miroslav Rezanina +Date: Thu, 31 May 2018 06:36:35 +0200 +Subject: [PATCH 1/9] Fix x-hv-max-vps compat value for 7.4 machine type + +RH-Author: Miroslav Rezanina +Message-id: <1527748595-28488-1-git-send-email-mrezanin@redhat.com> +Patchwork-id: 80541 +O-Subject: [RHEL qemu-kvm/qemu-kvm-rhev PATCH] Fix x-hv-max-vps compat value for 7.4 machine type +Bugzilla: 1583959 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Laszlo Ersek + +Commit b2f9f4fcaad9c64f4551ab1dbe9e474c3dc6b2b4 increased the limit of vcpus +for windows guest. In addition, it keep old limit for older machine types. +However, due to conflict was compatibility part incorrectly placed and +we keep this limit for 7.3 and older machine types instead of 7.4 and older. + +Moving the chunk to correct spot so we have correct limit. + +Signed-off-by: Miroslav Rezanina +--- + include/hw/i386/pc.h | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h +index e94424f..d5a0827 100644 +--- a/include/hw/i386/pc.h ++++ b/include/hw/i386/pc.h +@@ -1003,9 +1003,13 @@ extern void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id); + .driver = "q35-pcihost",\ + .property = "x-pci-hole64-fix",\ + .value = "off",\ ++ },\ ++ { /* PC_RHEL7_4_COMPAT from PC_COMPAT_2_10 */ \ ++ .driver = TYPE_X86_CPU,\ ++ .property = "x-hv-max-vps",\ ++ .value = "0x40",\ + }, + +- + #define PC_RHEL7_3_COMPAT \ + HW_COMPAT_RHEL7_3 \ + { /* PC_RHEL7_3_COMPAT from PC_COMPAT_2_8 */ \ +@@ -1067,11 +1071,6 @@ extern void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id); + .driver = TYPE_X86_CPU,\ + .property = "kvm-no-smi-migration",\ + .value = "on",\ +- },\ +- { /* PC_RHEL7_4_COMPAT from PC_COMPAT_2_10 */ \ +- .driver = TYPE_X86_CPU,\ +- .property = "x-hv-max-vps",\ +- .value = "0x40",\ + }, + + #define PC_RHEL7_2_COMPAT \ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-Match-POWER-max-cpus-to-x86.patch b/SOURCES/kvm-Match-POWER-max-cpus-to-x86.patch deleted file mode 100644 index 3e92e3f..0000000 --- a/SOURCES/kvm-Match-POWER-max-cpus-to-x86.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 0584216921b243fac91395aa8975dbc34997381a Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Mon, 4 Dec 2017 06:30:08 +0100 -Subject: [PATCH 28/36] Match POWER max cpus to x86 - -RH-Author: David Gibson -Message-id: <20171204063008.31826-1-dgibson@redhat.com> -Patchwork-id: 78091 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH] [RHEL only] Match POWER max cpus to x86 -Bugzilla: 1495456 -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier -RH-Acked-by: Serhii Popovych - -On at least some x86 configurations we now support 384 guest vcpus. -POWER supports more than that in theory, but set the cap to 384 as a -supported maximum for feature parity. This includes updating the -downstream lie about what KVM supports (in fact it supports 2048 vcpus -as of right now). - -As of the current kernel, even with this patch 384 vcpus can only be -created with threads=2 or greater (in the guest), otherwise the -spacing of guest vcpu numbers causes us to exhaust the 2048 vcpu ids -in KVM. There are a few ways we could address that, which we'll track -as a different bug. - -Testing: Started guest with -smp 384,threads=2 using new qemu - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - accel/kvm/kvm-all.c | 4 ++-- - hw/ppc/spapr.c | 3 ++- - 2 files changed, 4 insertions(+), 3 deletions(-) - -diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c -index 80ab1c7..94c4968 100644 ---- a/accel/kvm/kvm-all.c -+++ b/accel/kvm/kvm-all.c -@@ -1638,9 +1638,9 @@ static int kvm_init(MachineState *ms) - * - * However the POWER hard limit advertised by the kernel is 2048 - * (== NR_CPUS) but we only want to allow up to the number of -- * vCPUs we actually test, so we force the hard limit to 240 -+ * vCPUs we actually test, so we force the hard limit to 384 - */ -- hard_vcpus_limit = 240; -+ hard_vcpus_limit = 384; - if (soft_vcpus_limit > hard_vcpus_limit) { - soft_vcpus_limit = hard_vcpus_limit; - } -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 6c64c55..8623996 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -3580,7 +3580,8 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) - mc->init = ppc_spapr_init; - mc->reset = ppc_spapr_reset; - mc->block_default_type = IF_SCSI; -- mc->max_cpus = 1024; -+ /* RHEL: set to max # of supported vcpus */ -+ mc->max_cpus = 384; - mc->no_parallel = 1; - mc->default_boot_order = ""; - mc->default_ram_size = 512 * M_BYTE; --- -1.8.3.1 - diff --git a/SOURCES/kvm-Migration-TLS-Fix-crash-due-to-double-cleanup.patch b/SOURCES/kvm-Migration-TLS-Fix-crash-due-to-double-cleanup.patch new file mode 100644 index 0000000..13da7be --- /dev/null +++ b/SOURCES/kvm-Migration-TLS-Fix-crash-due-to-double-cleanup.patch @@ -0,0 +1,65 @@ +From c70d2938f2acf89ca872061086f1fe26e6c5a69d Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Fri, 22 Jun 2018 19:00:01 +0200 +Subject: [PATCH 22/57] Migration+TLS: Fix crash due to double cleanup +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Dr. David Alan Gilbert +Message-id: <20180622190005.21297-15-dgilbert@redhat.com> +Patchwork-id: 81004 +O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH 14/18] Migration+TLS: Fix crash due to double cleanup +Bugzilla: 1584139 +RH-Acked-by: Juan Quintela +RH-Acked-by: Peter Xu +RH-Acked-by: Laurent Vivier + +From: "Dr. David Alan Gilbert" + +During a TLS connect we see: + migration_channel_connect calls + migration_tls_channel_connect + (calls after TLS setup) + migration_channel_connect + +My previous error handling fix made migration_channel_connect +call migrate_fd_connect in all cases; unfortunately the above +means it gets called twice and crashes doing double cleanup. + +Fixes: 688a3dcba98 + +Reported-by: Peter Krempa +Signed-off-by: Dr. David Alan Gilbert +Reviewed-by: Daniel P. Berrangé +Message-Id: <20180430185943.35714-1-dgilbert@redhat.com> +Signed-off-by: Juan Quintela +(cherry picked from commit 8b7bf2badac25c0a52aff1b181ad75fdb304dd0c) +Signed-off-by: Miroslav Rezanina +--- + migration/channel.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/migration/channel.c b/migration/channel.c +index c5eaf0f..7a32b5a 100644 +--- a/migration/channel.c ++++ b/migration/channel.c +@@ -71,6 +71,15 @@ void migration_channel_connect(MigrationState *s, + !object_dynamic_cast(OBJECT(ioc), + TYPE_QIO_CHANNEL_TLS)) { + migration_tls_channel_connect(s, ioc, hostname, &error); ++ ++ if (!error) { ++ /* tls_channel_connect will call back to this ++ * function after the TLS handshake, ++ * so we mustn't call migrate_fd_connect until then ++ */ ++ ++ return; ++ } + } else { + QEMUFile *f = qemu_fopen_channel_output(ioc); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-PPC-KVM-Support-machine-option-to-set-VSMT-mode.patch b/SOURCES/kvm-PPC-KVM-Support-machine-option-to-set-VSMT-mode.patch deleted file mode 100644 index 3e3ff2d..0000000 --- a/SOURCES/kvm-PPC-KVM-Support-machine-option-to-set-VSMT-mode.patch +++ /dev/null @@ -1,304 +0,0 @@ -From cdb93019369dff9f8a3ab19df18f24a5ba508698 Mon Sep 17 00:00:00 2001 -From: Sam Bobroff -Date: Fri, 6 Oct 2017 06:04:59 +0200 -Subject: [PATCH 13/34] PPC: KVM: Support machine option to set VSMT mode - -RH-Author: Sam Bobroff -Message-id: <1507269899-22908-1-git-send-email-sbobroff@redhat.com> -Patchwork-id: 76834 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH] PPC: KVM: Support machine option to set VSMT mode -Bugzilla: 1479178 -RH-Acked-by: David Gibson -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth - -From: Sam Bobroff - -KVM now allows writing to KVM_CAP_PPC_SMT which has previously been -read only. Doing so causes KVM to act, for that VM, as if the host's -SMT mode was the given value. This is particularly important on Power -9 systems because their default value is 1, but they are able to -support values up to 8. - -This patch introduces a way to control this capability via a new -machine property called VSMT ("Virtual SMT"). If the value is not set -on the command line a default is chosen that is, when possible, -compatible with legacy systems. - -Note that the intialization of KVM_CAP_PPC_SMT has changed slightly -because it has changed (in KVM) from a global capability to a -VM-specific one. This won't cause a problem on older KVMs because VM -capabilities fall back to global ones. - -Signed-off-by: Sam Bobroff -Signed-off-by: David Gibson -(cherry picked from commit fa98fbfcdfcb980b4a690b8bc93ab597935087b1) - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1479178 -Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=14187630 -Testing: Start QEMU using "--machine pseries,vsmt=4". -Signed-off-by: Sam Bobroff -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr.c | 75 +++++++++++++++++++++++++++++++++++++++++++++ - include/hw/ppc/spapr.h | 1 + - target/ppc/kvm.c | 39 ++++++++++++++++++++++- - target/ppc/kvm_ppc.h | 12 ++++++++ - target/ppc/translate_init.c | 14 --------- - 5 files changed, 126 insertions(+), 15 deletions(-) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index d3db051..30b2c5b 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -26,6 +26,7 @@ - */ - #include "qemu/osdep.h" - #include "qapi/error.h" -+#include "qapi/visitor.h" - #include "sysemu/sysemu.h" - #include "sysemu/numa.h" - #include "hw/hw.h" -@@ -2166,6 +2167,61 @@ static void spapr_init_cpus(sPAPRMachineState *spapr) - g_free(type); - } - -+static void spapr_set_vsmt_mode(sPAPRMachineState *spapr, Error **errp) -+{ -+ Error *local_err = NULL; -+ bool vsmt_user = !!spapr->vsmt; -+ int kvm_smt = kvmppc_smt_threads(); -+ int ret; -+ -+ if (!kvm_enabled() && (smp_threads > 1)) { -+ error_setg(&local_err, "TCG cannot support more than 1 thread/core " -+ "on a pseries machine"); -+ goto out; -+ } -+ if (!is_power_of_2(smp_threads)) { -+ error_setg(&local_err, "Cannot support %d threads/core on a pseries " -+ "machine because it must be a power of 2", smp_threads); -+ goto out; -+ } -+ -+ /* Detemine the VSMT mode to use: */ -+ if (vsmt_user) { -+ if (spapr->vsmt < smp_threads) { -+ error_setg(&local_err, "Cannot support VSMT mode %d" -+ " because it must be >= threads/core (%d)", -+ spapr->vsmt, smp_threads); -+ goto out; -+ } -+ /* In this case, spapr->vsmt has been set by the command line */ -+ } else { -+ /* Choose a VSMT mode that may be higher than necessary but is -+ * likely to be compatible with hosts that don't have VSMT. */ -+ spapr->vsmt = MAX(kvm_smt, smp_threads); -+ } -+ -+ /* KVM: If necessary, set the SMT mode: */ -+ if (kvm_enabled() && (spapr->vsmt != kvm_smt)) { -+ ret = kvmppc_set_smt_threads(spapr->vsmt); -+ if (ret) { -+ error_setg(&local_err, -+ "Failed to set KVM's VSMT mode to %d (errno %d)", -+ spapr->vsmt, ret); -+ if (!vsmt_user) { -+ error_append_hint(&local_err, "On PPC, a VM with %d threads/" -+ "core on a host with %d threads/core requires " -+ " the use of VSMT mode %d.\n", -+ smp_threads, kvm_smt, spapr->vsmt); -+ } -+ kvmppc_hint_smt_possible(&local_err); -+ goto out; -+ } -+ } -+ /* else TCG: nothing to do currently */ -+out: -+ error_propagate(errp, local_err); -+} -+ - /* pSeries LPAR / sPAPR hardware init */ - static void ppc_spapr_init(MachineState *machine) - { -@@ -2298,6 +2354,8 @@ static void ppc_spapr_init(MachineState *machine) - - spapr_cpu_parse_features(spapr); - -+ spapr_set_vsmt_mode(spapr, &error_fatal); -+ - spapr_init_cpus(spapr); - - if (kvm_enabled()) { -@@ -2682,6 +2740,18 @@ static void spapr_set_resize_hpt(Object *obj, const char *value, Error **errp) - } - } - -+static void spapr_get_vsmt(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ visit_type_uint32(v, name, (uint32_t *)opaque, errp); -+} -+ -+static void spapr_set_vsmt(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ visit_type_uint32(v, name, (uint32_t *)opaque, errp); -+} -+ - static void spapr_machine_initfn(Object *obj) - { - sPAPRMachineState *spapr = SPAPR_MACHINE(obj); -@@ -2712,6 +2782,11 @@ static void spapr_machine_initfn(Object *obj) - object_property_set_description(obj, "resize-hpt", - "Resizing of the Hash Page Table (enabled, disabled, required)", - NULL); -+ object_property_add(obj, "vsmt", "uint32", spapr_get_vsmt, -+ spapr_set_vsmt, NULL, &spapr->vsmt, &error_abort); -+ object_property_set_description(obj, "vsmt", -+ "Virtual SMT: KVM behaves as if this were" -+ " the host's SMT mode", &error_abort); - } - - static void spapr_machine_finalizefn(Object *obj) -diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h -index 5d161ec..3d0d206 100644 ---- a/include/hw/ppc/spapr.h -+++ b/include/hw/ppc/spapr.h -@@ -99,6 +99,7 @@ struct sPAPRMachineState { - uint64_t rtc_offset; /* Now used only during incoming migration */ - struct PPCTimebase tb; - bool has_graphics; -+ uint32_t vsmt; /* Virtual SMT mode (KVM's "core stride") */ - - Notifier epow_notifier; - QTAILQ_HEAD(, sPAPREventLogEntry) pending_events; -diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c -index f31c67e..ce7e2ec 100644 ---- a/target/ppc/kvm.c -+++ b/target/ppc/kvm.c -@@ -74,6 +74,7 @@ static int cap_interrupt_level = false; - static int cap_segstate; - static int cap_booke_sregs; - static int cap_ppc_smt; -+static int cap_ppc_smt_possible; - static int cap_ppc_rma; - static int cap_spapr_tce; - static int cap_spapr_tce_64; -@@ -130,7 +131,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) - cap_interrupt_level = kvm_check_extension(s, KVM_CAP_PPC_IRQ_LEVEL); - cap_segstate = kvm_check_extension(s, KVM_CAP_PPC_SEGSTATE); - cap_booke_sregs = kvm_check_extension(s, KVM_CAP_PPC_BOOKE_SREGS); -- cap_ppc_smt = kvm_check_extension(s, KVM_CAP_PPC_SMT); -+ cap_ppc_smt_possible = kvm_check_extension(s, KVM_CAP_PPC_SMT_POSSIBLE); - cap_ppc_rma = kvm_check_extension(s, KVM_CAP_PPC_RMA); - cap_spapr_tce = kvm_check_extension(s, KVM_CAP_SPAPR_TCE); - cap_spapr_tce_64 = kvm_check_extension(s, KVM_CAP_SPAPR_TCE_64); -@@ -144,6 +145,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) - * only activated after this by kvmppc_set_papr() */ - cap_htab_fd = kvm_check_extension(s, KVM_CAP_PPC_HTAB_FD); - cap_fixup_hcalls = kvm_check_extension(s, KVM_CAP_PPC_FIXUP_HCALL); -+ cap_ppc_smt = kvm_vm_check_extension(s, KVM_CAP_PPC_SMT); - cap_htm = kvm_vm_check_extension(s, KVM_CAP_PPC_HTM); - cap_mmu_radix = kvm_vm_check_extension(s, KVM_CAP_PPC_MMU_RADIX); - cap_mmu_hash_v3 = kvm_vm_check_extension(s, KVM_CAP_PPC_MMU_HASH_V3); -@@ -2134,6 +2136,41 @@ int kvmppc_smt_threads(void) - return cap_ppc_smt ? cap_ppc_smt : 1; - } - -+int kvmppc_set_smt_threads(int smt) -+{ -+ int ret; -+ -+ ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_PPC_SMT, 0, smt, 0); -+ if (!ret) { -+ cap_ppc_smt = smt; -+ } -+ return ret; -+} -+ -+void kvmppc_hint_smt_possible(Error **errp) -+{ -+ int i; -+ GString *g; -+ char *s; -+ -+ assert(kvm_enabled()); -+ if (cap_ppc_smt_possible) { -+ g = g_string_new("Available VSMT modes:"); -+ for (i = 63; i >= 0; i--) { -+ if ((1UL << i) & cap_ppc_smt_possible) { -+ g_string_append_printf(g, " %lu", (1UL << i)); -+ } -+ } -+ s = g_string_free(g, false); -+ error_append_hint(errp, "%s.\n", s); -+ g_free(s); -+ } else { -+ error_append_hint(errp, -+ "This KVM seems to be too old to support VSMT.\n"); -+ } -+} -+ -+ - #ifdef TARGET_PPC64 - off_t kvmppc_alloc_rma(void **rma) - { -diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h -index 381afe6..e6711fc 100644 ---- a/target/ppc/kvm_ppc.h -+++ b/target/ppc/kvm_ppc.h -@@ -29,6 +29,8 @@ void kvmppc_set_papr(PowerPCCPU *cpu); - int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr); - void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy); - int kvmppc_smt_threads(void); -+void kvmppc_hint_smt_possible(Error **errp); -+int kvmppc_set_smt_threads(int smt); - int kvmppc_clear_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits); - int kvmppc_or_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits); - int kvmppc_set_tcr(PowerPCCPU *cpu); -@@ -148,6 +150,16 @@ static inline int kvmppc_smt_threads(void) - return 1; - } - -+static inline void kvmppc_hint_smt_possible(Error **errp) -+{ -+ return; -+} -+ -+static inline int kvmppc_set_smt_threads(int smt) -+{ -+ return 0; -+} -+ - static inline int kvmppc_or_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits) - { - return 0; -diff --git a/target/ppc/translate_init.c b/target/ppc/translate_init.c -index 8fb407e..371bbae 100644 ---- a/target/ppc/translate_init.c -+++ b/target/ppc/translate_init.c -@@ -9817,20 +9817,6 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp) - int max_smt = kvmppc_smt_threads(); - #endif - --#if !defined(CONFIG_USER_ONLY) -- if (smp_threads > max_smt) { -- error_setg(errp, "Cannot support more than %d threads on PPC with %s", -- max_smt, kvm_enabled() ? "KVM" : "TCG"); -- return; -- } -- if (!is_power_of_2(smp_threads)) { -- error_setg(errp, "Cannot support %d threads on PPC with %s, " -- "threads count must be a power of 2.", -- smp_threads, kvm_enabled() ? "KVM" : "TCG"); -- return; -- } --#endif -- - cpu_exec_realizefn(cs, &local_err); - if (local_err != NULL) { - error_propagate(errp, local_err); --- -1.8.3.1 - diff --git a/SOURCES/kvm-RHEL-7.6-Add-pseries-rhel7.6.0-sxxm-machine-type.patch b/SOURCES/kvm-RHEL-7.6-Add-pseries-rhel7.6.0-sxxm-machine-type.patch new file mode 100644 index 0000000..b033b5f --- /dev/null +++ b/SOURCES/kvm-RHEL-7.6-Add-pseries-rhel7.6.0-sxxm-machine-type.patch @@ -0,0 +1,70 @@ +From 5aec9f19936a96f0140e8ede00fb1a5753477dc7 Mon Sep 17 00:00:00 2001 +From: David Gibson +Date: Mon, 25 Jun 2018 05:11:41 +0200 +Subject: [PATCH 01/89] RHEL-7.6: Add pseries-rhel7.6.0-sxxm machine type + +RH-Author: David Gibson +Message-id: <20180625051141.8203-1-dgibson@redhat.com> +Patchwork-id: 81034 +O-Subject: [RHEL-7.6 qemu-kvm-rhv PATCH] RHEL-7.6: Add pseries-rhel7.6.0-sxxm machine type +Bugzilla: 1592648 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Serhii Popovych +RH-Acked-by: Thomas Huth + +For the pseries-rhel7.3.0 .. pseries-rhel7.5.0 machine types we have -sxxm +variants, the only difference being that the -sxxm variants have the +Spectre and Meltdown mitigations available to guests by default. + +We'd delayed on adding a similar variant for RHEL 7.6, in the hope that we +might be able to enable the mitigations by default for the ordinary 7.6 +machine type. This requires that updated POWER8 firmware (FW860.51 or +newer) be installed on the host. + +The updated firmware was only released late May, and it's not clear how +quickly and widely it will be deployed. For that reason, plus for +consistency in how things need to be configured across rhel-7.y, we're now +adding a pseries-rhel7.6.0-sxxm machine type. + +Signed-off-by: David Gibson +Signed-off-by: Miroslav Rezanina +--- + hw/ppc/spapr.c | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c +index e2df370..a580334 100644 +--- a/hw/ppc/spapr.c ++++ b/hw/ppc/spapr.c +@@ -4369,6 +4369,28 @@ static void spapr_machine_rhel760_class_options(MachineClass *mc) + DEFINE_SPAPR_MACHINE(rhel760, "rhel7.6.0", true); + + /* ++ * pseries-rhel7.6.0-sxxm ++ * ++ * pseries-rhel7.6.0 with speculative execution exploit mitigations enabled by default ++ */ ++static void spapr_machine_rhel760sxxm_instance_options(MachineState *machine) ++{ ++ spapr_machine_rhel760_instance_options(machine); ++} ++ ++static void spapr_machine_rhel760sxxm_class_options(MachineClass *mc) ++{ ++ sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); ++ ++ spapr_machine_rhel760_class_options(mc); ++ smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND; ++ smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND; ++ smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_FIXED_CCD; ++} ++ ++DEFINE_SPAPR_MACHINE(rhel760sxxm, "rhel7.6.0-sxxm", false); ++ ++/* + * pseries-rhel7.5.0 + * like SPAPR_COMPAT_2_11 and SPAPR_COMPAT_2_10 + * SPAPR_CAP_HTM already enabled in 7.4 +-- +1.8.3.1 + diff --git a/SOURCES/kvm-RHEL-Add-RHEL7-machine-type-for-qemu-on-s390x.patch b/SOURCES/kvm-RHEL-Add-RHEL7-machine-type-for-qemu-on-s390x.patch deleted file mode 100644 index 89b7ce7..0000000 --- a/SOURCES/kvm-RHEL-Add-RHEL7-machine-type-for-qemu-on-s390x.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 1ece5bfd00eda071ff19d17035d1af23f4d160e9 Mon Sep 17 00:00:00 2001 -From: Thomas Huth -Date: Mon, 9 Oct 2017 15:50:34 +0200 -Subject: [PATCH 31/34] RHEL: Add RHEL7 machine type for qemu on s390x - -RH-Author: Thomas Huth -Message-id: <1507564234-19627-3-git-send-email-thuth@redhat.com> -Patchwork-id: 77037 -O-Subject: [RHEL-7.5 qemu-kvm-ma PATCH 2/2] RHEL: Add RHEL7 machine type for qemu on s390x -Bugzilla: 1473292 -RH-Acked-by: Cornelia Huck -RH-Acked-by: Jens Freimann -RH-Acked-by: Laurent Vivier - -Upstream-status: downstream only - -Since downstream qemu-kvm is an engineered version (with additional -bug fixes and features on top of the upstream version), we can not -use the upstream machine types here. Introduce RHEL-specific machine -types instead. - -Signed-off-by: Thomas Huth -Signed-off-by: Miroslav Rezanina ---- - hw/s390x/s390-virtio-ccw.c | 17 ++++++++++++++++- - 1 file changed, 16 insertions(+), 1 deletion(-) - -diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c -index 1aec58c..4e524b0 100644 ---- a/hw/s390x/s390-virtio-ccw.c -+++ b/hw/s390x/s390-virtio-ccw.c -@@ -411,7 +411,7 @@ bool css_migration_enabled(void) - { \ - MachineClass *mc = MACHINE_CLASS(oc); \ - ccw_machine_##suffix##_class_options(mc); \ -- mc->desc = "VirtIO-ccw based S390 machine v" verstr; \ -+ mc->desc = "VirtIO-ccw based S390 machine " verstr; \ - if (latest) { \ - mc->alias = "s390-ccw-virtio"; \ - mc->is_default = 1; \ -@@ -435,6 +435,8 @@ bool css_migration_enabled(void) - } \ - type_init(ccw_machine_register_##suffix) - -+#if 0 /* Disabled for Red Hat Enterprise Linux */ -+ - #define CCW_COMPAT_2_9 \ - HW_COMPAT_2_9 \ - {\ -@@ -605,6 +607,19 @@ static void ccw_machine_2_4_class_options(MachineClass *mc) - } - DEFINE_CCW_MACHINE(2_4, "2.4", false); - -+#else -+ -+static void ccw_machine_rhel750_instance_options(MachineState *machine) -+{ -+} -+ -+static void ccw_machine_rhel750_class_options(MachineClass *mc) -+{ -+} -+DEFINE_CCW_MACHINE(rhel750, "rhel7.5.0", true); -+ -+#endif -+ - static void ccw_machine_register_types(void) - { - type_register_static(&ccw_machine_info); --- -1.8.3.1 - diff --git a/SOURCES/kvm-RHEL-Disable-vfio-ccw-and-x-terminal3270-devices.patch b/SOURCES/kvm-RHEL-Disable-vfio-ccw-and-x-terminal3270-devices.patch deleted file mode 100644 index 384ee0e..0000000 --- a/SOURCES/kvm-RHEL-Disable-vfio-ccw-and-x-terminal3270-devices.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 17abc4f5bd7df54a1e09e2f8a1086354ef69aa87 Mon Sep 17 00:00:00 2001 -From: Thomas Huth -Date: Mon, 9 Oct 2017 12:32:48 +0200 -Subject: [PATCH 29/34] RHEL: Disable vfio-ccw and x-terminal3270 devices - -RH-Author: Thomas Huth -Message-id: <1507552368-9245-13-git-send-email-thuth@redhat.com> -Patchwork-id: 77030 -O-Subject: [RHEL-7.5 qemu-kvm-ma PATCH 12/12] RHEL: Disable vfio-ccw and x-terminal3270 devices -Bugzilla: 1492033 -RH-Acked-by: Cornelia Huck -RH-Acked-by: David Gibson -RH-Acked-by: Miroslav Rezanina - -Upstream-status: downstream only - -We don't support them in downstream RHEL, so disable them in -the config files. - -Signed-off-by: Thomas Huth -Signed-off-by: Miroslav Rezanina ---- - default-configs/s390x-softmmu.mak | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/default-configs/s390x-softmmu.mak b/default-configs/s390x-softmmu.mak -index 43dbf34..2846634 100644 ---- a/default-configs/s390x-softmmu.mak -+++ b/default-configs/s390x-softmmu.mak -@@ -3,8 +3,10 @@ CONFIG_PCI=y - CONFIG_VHOST_USER_SCSI=$(and $(CONFIG_VHOST_USER),$(CONFIG_LINUX)) - CONFIG_VIRTIO=y - CONFIG_SCLPCONSOLE=y --CONFIG_TERMINAL3270=y -+# Disabled for Red Hat Enterprise Linux: -+# CONFIG_TERMINAL3270=y - CONFIG_S390_FLIC=y - CONFIG_S390_FLIC_KVM=$(CONFIG_KVM) --CONFIG_VFIO_CCW=$(CONFIG_LINUX) -+# Disabled for Red Hat Enterprise Linux: -+# CONFIG_VFIO_CCW=$(CONFIG_LINUX) - CONFIG_WDT_DIAG288=y --- -1.8.3.1 - diff --git a/SOURCES/kvm-Revert-Disable-PCIe-to-PCI-bridge-device.patch b/SOURCES/kvm-Revert-Disable-PCIe-to-PCI-bridge-device.patch new file mode 100644 index 0000000..cd2dffb --- /dev/null +++ b/SOURCES/kvm-Revert-Disable-PCIe-to-PCI-bridge-device.patch @@ -0,0 +1,42 @@ +From ec6f06f14094727dbe049343b1f815c40a6f05b4 Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Thu, 9 Aug 2018 18:23:25 +0200 +Subject: [PATCH 3/5] Revert "Disable PCIe-to-PCI bridge device" + +RH-Author: Eduardo Habkost +Message-id: <20180809182325.21534-2-ehabkost@redhat.com> +Patchwork-id: 81691 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/1] Revert "Disable PCIe-to-PCI bridge device" +Bugzilla: 1390329 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek + +This reverts commit d496bec5b14df55d49658a283326ad720f974a0a. + +Without pcie-pci-bridge, libvirt will keep using the DMI bridge +(i82801b11-bridge) to plug Conventional PCI devices, and we want +to discourage its usage. + +Signed-off-by: Eduardo Habkost +Signed-off-by: Miroslav Rezanina +--- + hw/pci-bridge/Makefile.objs | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/hw/pci-bridge/Makefile.objs b/hw/pci-bridge/Makefile.objs +index 68db0da..47065f8 100644 +--- a/hw/pci-bridge/Makefile.objs ++++ b/hw/pci-bridge/Makefile.objs +@@ -1,6 +1,5 @@ + common-obj-y += pci_bridge_dev.o +-common-obj-$(CONFIG_PCIE_PORT) += pcie_root_port.o gen_pcie_root_port.o +-#common-obj-$(CONFIG_PCIE_PORT) += pcie_pci_bridge.o ++common-obj-$(CONFIG_PCIE_PORT) += pcie_root_port.o gen_pcie_root_port.o pcie_pci_bridge.o + common-obj-$(CONFIG_PXB) += pci_expander_bridge.o + common-obj-$(CONFIG_XIO3130) += xio3130_upstream.o xio3130_downstream.o + common-obj-$(CONFIG_IOH3420) += ioh3420.o +-- +1.8.3.1 + diff --git a/SOURCES/kvm-Revert-qdev-Free-QemuOpts-when-the-QOM-path-goes-awa.patch b/SOURCES/kvm-Revert-qdev-Free-QemuOpts-when-the-QOM-path-goes-awa.patch deleted file mode 100644 index c2d550b..0000000 --- a/SOURCES/kvm-Revert-qdev-Free-QemuOpts-when-the-QOM-path-goes-awa.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 8edc99e92cf93764e190e69d3f970bdf6de606e0 Mon Sep 17 00:00:00 2001 -From: Serhii Popovych -Date: Thu, 9 Nov 2017 15:30:04 +0100 -Subject: [PATCH 4/7] Revert "qdev: Free QemuOpts when the QOM path goes away" - -RH-Author: Serhii Popovych -Message-id: <1510241405-20597-3-git-send-email-spopovyc@redhat.com> -Patchwork-id: 77630 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 2/3] Revert "qdev: Free QemuOpts when the QOM path goes away" -Bugzilla: 1445460 -RH-Acked-by: David Gibson -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier - -From: Michael Roth - -This reverts commit abed886ec60cf239a03515cf0b30fb11fa964c44. - -This patch originally addressed an issue where a DEVICE_DELETED -event could be emitted (in device_unparent()) before a Device's -QemuOpts were cleaned up (in device_finalize()), leading to a -"duplicate ID" error if management attempted to immediately add -a device with the same ID in response to the DEVICE_DELETED event. - -An alternative will be implemented in a subsequent patch where we -defer the DEVICE_DELETED event until device_finalize(), which would -also prevent the race, so we revert the original fix in preparation. - -Signed-off-by: Michael Roth -Reviewed-by: Greg Kurz -Tested-by: Eric Auger -Reviewed-by: David Gibson -Message-Id: <20171016222315.407-3-mdroth@linux.vnet.ibm.com> -Signed-off-by: Paolo Bonzini -(cherry picked from commit 2fc06c4ac65594ad248e9a9150ebdde9ff5a1253) -Signed-off-by: Serhii Popovych -Signed-off-by: Miroslav Rezanina ---- - hw/core/qdev.c | 4 +--- - 1 file changed, 1 insertion(+), 3 deletions(-) - -diff --git a/hw/core/qdev.c b/hw/core/qdev.c -index 0019a49..418cdac 100644 ---- a/hw/core/qdev.c -+++ b/hw/core/qdev.c -@@ -1069,6 +1069,7 @@ static void device_finalize(Object *obj) - NamedGPIOList *ngl, *next; - - DeviceState *dev = DEVICE(obj); -+ qemu_opts_del(dev->opts); - - QLIST_FOREACH_SAFE(ngl, &dev->gpios, node, next) { - QLIST_REMOVE(ngl, node); -@@ -1118,9 +1119,6 @@ static void device_unparent(Object *obj) - g_free(dev->canonical_path); - dev->canonical_path = NULL; - } -- -- qemu_opts_del(dev->opts); -- dev->opts = NULL; - } - - static void device_class_init(ObjectClass *class, void *data) --- -1.8.3.1 - diff --git a/SOURCES/kvm-Revert-spapr-Don-t-allow-memory-hotplug-to-memory-le.patch b/SOURCES/kvm-Revert-spapr-Don-t-allow-memory-hotplug-to-memory-le.patch new file mode 100644 index 0000000..58ed66a --- /dev/null +++ b/SOURCES/kvm-Revert-spapr-Don-t-allow-memory-hotplug-to-memory-le.patch @@ -0,0 +1,69 @@ +From 55cc729e37b945bcbb9135fe5553d1bb9a293424 Mon Sep 17 00:00:00 2001 +From: Serhii Popovych +Date: Wed, 2 May 2018 18:52:28 +0200 +Subject: [PATCH 05/13] Revert "spapr: Don't allow memory hotplug to memory + less nodes" + +RH-Author: Serhii Popovych +Message-id: <1525287148-92715-3-git-send-email-spopovyc@redhat.com> +Patchwork-id: 80012 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 2/2] Revert "spapr: Don't allow memory hotplug to memory less nodes" +Bugzilla: 1570525 +RH-Acked-by: David Gibson +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier + +This reverts commit b556854bd8524c26b8be98ab1bfdf0826831e793. + +Leave change @node type from uint32_t to to int from reverted commit +because node < 0 is always false. + +Note that implementing capability or some trick to detect if guest +kernel does not support hot-add to memory: this returns previous +behavour where memory added to first non-empty node. + +Signed-off-by: Serhii Popovych +Signed-off-by: David Gibson +(cherry picked from commit e47f1d2786c3d01a7894a493aafe0efa6b64453c) +Signed-off-by: Serhii Popovych +Signed-off-by: Miroslav Rezanina +--- + hw/ppc/spapr.c | 22 ---------------------- + 1 file changed, 22 deletions(-) + +diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c +index c9561e1..6f005a0 100644 +--- a/hw/ppc/spapr.c ++++ b/hw/ppc/spapr.c +@@ -3501,28 +3501,6 @@ static void spapr_machine_device_plug(HotplugHandler *hotplug_dev, + return; + } + +- /* +- * Currently PowerPC kernel doesn't allow hot-adding memory to +- * memory-less node, but instead will silently add the memory +- * to the first node that has some memory. This causes two +- * unexpected behaviours for the user. +- * +- * - Memory gets hotplugged to a different node than what the user +- * specified. +- * - Since pc-dimm subsystem in QEMU still thinks that memory belongs +- * to memory-less node, a reboot will set things accordingly +- * and the previously hotplugged memory now ends in the right node. +- * This appears as if some memory moved from one node to another. +- * +- * So until kernel starts supporting memory hotplug to memory-less +- * nodes, just prevent such attempts upfront in QEMU. +- */ +- if (nb_numa_nodes && !numa_info[node].node_mem) { +- error_setg(errp, "Can't hotplug memory to memory-less node %d", +- node); +- return; +- } +- + spapr_memory_plug(hotplug_dev, dev, node, errp); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) { + spapr_core_plug(hotplug_dev, dev, errp); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-Revert-usb-release-the-created-buses.patch b/SOURCES/kvm-Revert-usb-release-the-created-buses.patch new file mode 100644 index 0000000..24c4639 --- /dev/null +++ b/SOURCES/kvm-Revert-usb-release-the-created-buses.patch @@ -0,0 +1,99 @@ +From 5969300e27c6a28f1bc345b84cd9e690780e29f8 Mon Sep 17 00:00:00 2001 +From: Serhii Popovych +Date: Mon, 9 Jul 2018 11:31:18 +0200 +Subject: [PATCH 28/89] Revert "usb: release the created buses" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Serhii Popovych +Message-id: <1531135878-18813-4-git-send-email-spopovyc@redhat.com> +Patchwork-id: 81266 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v2 3/3] Revert "usb: release the created buses" +Bugzilla: 1556678 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Marc-André Lureau +RH-Acked-by: David Gibson + +From: Marc-André Lureau + +The USB device don't hold the bus. There is no ASAN related reports +anymore. + +This reverts commit cd7bc87868d534f95e928cad98e2a52df7695771. + +Signed-off-by: Marc-André Lureau +Message-id: 20180613172815.32738-3-marcandre.lureau@redhat.com +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 9b5c2fd53feb574036747d0284fd7f73dfedc89c) +Signed-off-by: Serhii Popovych +Signed-off-by: Miroslav Rezanina +--- + hw/usb/dev-storage.c | 16 ---------------- + hw/usb/dev-uas.c | 2 -- + 2 files changed, 18 deletions(-) + +diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c +index 68e2062..9fb00a9 100644 +--- a/hw/usb/dev-storage.c ++++ b/hw/usb/dev-storage.c +@@ -589,13 +589,6 @@ static const struct SCSIBusInfo usb_msd_scsi_info_bot = { + .load_request = usb_msd_load_request, + }; + +-static void usb_msd_unrealize_storage(USBDevice *dev, Error **errp) +-{ +- MSDState *s = USB_STORAGE_DEV(dev); +- +- object_unref(OBJECT(&s->bus)); +-} +- + static void usb_msd_storage_realize(USBDevice *dev, Error **errp) + { + MSDState *s = USB_STORAGE_DEV(dev); +@@ -645,13 +638,6 @@ static void usb_msd_storage_realize(USBDevice *dev, Error **errp) + s->scsi_dev = scsi_dev; + } + +-static void usb_msd_bot_unrealize(USBDevice *dev, Error **errp) +-{ +- MSDState *s = USB_STORAGE_DEV(dev); +- +- object_unref(OBJECT(&s->bus)); +-} +- + static void usb_msd_bot_realize(USBDevice *dev, Error **errp) + { + MSDState *s = USB_STORAGE_DEV(dev); +@@ -716,7 +702,6 @@ static void usb_msd_class_storage_initfn(ObjectClass *klass, void *data) + USBDeviceClass *uc = USB_DEVICE_CLASS(klass); + + uc->realize = usb_msd_storage_realize; +- uc->unrealize = usb_msd_unrealize_storage; + dc->props = msd_properties; + } + +@@ -779,7 +764,6 @@ static void usb_msd_class_bot_initfn(ObjectClass *klass, void *data) + USBDeviceClass *uc = USB_DEVICE_CLASS(klass); + + uc->realize = usb_msd_bot_realize; +- uc->unrealize = usb_msd_bot_unrealize; + uc->attached_settable = true; + } + +diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c +index c218b53..eaf515d 100644 +--- a/hw/usb/dev-uas.c ++++ b/hw/usb/dev-uas.c +@@ -896,8 +896,6 @@ static void usb_uas_unrealize(USBDevice *dev, Error **errp) + UASDevice *uas = USB_UAS(dev); + + qemu_bh_delete(uas->status_bh); +- +- object_unref(OBJECT(&uas->bus)); + } + + static void usb_uas_realize(USBDevice *dev, Error **errp) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-Use-4-MB-vram-for-cirrus.patch b/SOURCES/kvm-Use-4-MB-vram-for-cirrus.patch new file mode 100644 index 0000000..8dd1c24 --- /dev/null +++ b/SOURCES/kvm-Use-4-MB-vram-for-cirrus.patch @@ -0,0 +1,63 @@ +From 798456424d4941bed5e19e4ee3c712c7bc3766dd Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 13 Jun 2018 10:40:26 +0200 +Subject: [PATCH 4/9] Use 4 MB vram for cirrus. + +RH-Author: Gerd Hoffmann +Message-id: <20180613104026.4395-3-kraxel@redhat.com> +Patchwork-id: 80652 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 2/2] Use 4 MB vram for cirrus. +Bugzilla: 1542080 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Daniel P. Berrange + +Follow upstream, which switched from 8 MB to 4 MB in release 2.9, +see commit 73c148130b58709f0f2abfedbae92681d87eb404. + +RHEL traditionally defaults to 16 MB video memory, so we had a patch +changing 8 MB -> 16 MB downstream. The 2.9 rebase kept that patch, now +changing 4 MB -> 16 MB. + +This patch effectively reverts the downstream change and adds a compat +property so the video memory will stay at 16 MB for 7.5 and older +machine types. + +Signed-off-by: Gerd Hoffmann +Signed-off-by: Miroslav Rezanina +--- + hw/display/cirrus_vga.c | 2 +- + include/hw/compat.h | 4 ++++ + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c +index feacb45..014268a 100644 +--- a/hw/display/cirrus_vga.c ++++ b/hw/display/cirrus_vga.c +@@ -3133,7 +3133,7 @@ static void pci_cirrus_vga_realize(PCIDevice *dev, Error **errp) + + static Property pci_vga_cirrus_properties[] = { + DEFINE_PROP_UINT32("vgamem_mb", struct PCICirrusVGAState, +- cirrus_vga.vga.vram_size_mb, 16), ++ cirrus_vga.vga.vram_size_mb, 4), + DEFINE_PROP_BOOL("blitter", struct PCICirrusVGAState, + cirrus_vga.enable_blitter, true), + DEFINE_PROP_END_OF_LIST(), +diff --git a/include/hw/compat.h b/include/hw/compat.h +index 666eed9..9e659e9 100644 +--- a/include/hw/compat.h ++++ b/include/hw/compat.h +@@ -476,6 +476,10 @@ + .driver = "virtio-tablet-device",\ + .property = "wheel-axis",\ + .value = "false",\ ++ },{ /* HW_COMPAT_RHEL7_5 */ \ ++ .driver = "cirrus-vga",\ ++ .property = "vgamem_mb",\ ++ .value = "16",\ + }, + + #endif /* HW_COMPAT_H */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-acpi-Force-rev1-FADT-on-old-q35-machine-types.patch b/SOURCES/kvm-acpi-Force-rev1-FADT-on-old-q35-machine-types.patch deleted file mode 100644 index 2e68432..0000000 --- a/SOURCES/kvm-acpi-Force-rev1-FADT-on-old-q35-machine-types.patch +++ /dev/null @@ -1,114 +0,0 @@ -From e63d707db946519d04590b86e241ac82e328339b Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Wed, 11 Oct 2017 17:54:59 +0200 -Subject: [PATCH 14/69] acpi: Force rev1 FADT on old q35 machine types - -RH-Author: Dr. David Alan Gilbert -Message-id: <20171011175500.12390-2-dgilbert@redhat.com> -Patchwork-id: 77177 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH v3 1/2] acpi: Force rev1 FADT on old q35 machine types -Bugzilla: 1489800 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Gerd Hoffmann -RH-Acked-by: Igor Mammedov - -From: "Dr. David Alan Gilbert" - -Upstream lp's 1714331 found that older OVMF -didn't boot various versions of windows on 2.10+q35 -due to the change to the newer FADT version. That's -fixed with a newer OVMF, and it's too late upstream -to keep compatibility. - -Downstream, keep the compatibility on the older rhel-q35 -machine types by forcing rev1 FADT. - -Signed-off-by: Dr. David Alan Gilbert -Signed-off-by: Miroslav Rezanina ---- - hw/acpi/ich9.c | 16 ++++++++++++++++ - hw/i386/acpi-build.c | 2 ++ - include/hw/acpi/ich9.h | 3 +++ - include/hw/i386/pc.h | 5 +++++ - 4 files changed, 26 insertions(+) - -diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c -index a4e87b8..23a7baa 100644 ---- a/hw/acpi/ich9.c -+++ b/hw/acpi/ich9.c -@@ -441,6 +441,18 @@ static void ich9_pm_set_enable_tco(Object *obj, bool value, Error **errp) - s->pm.enable_tco = value; - } - -+static bool ich9_pm_get_force_rev1_fadt(Object *obj, Error **errp) -+{ -+ ICH9LPCState *s = ICH9_LPC_DEVICE(obj); -+ return s->pm.force_rev1_fadt; -+} -+ -+static void ich9_pm_set_force_rev1_fadt(Object *obj, bool value, Error **errp) -+{ -+ ICH9LPCState *s = ICH9_LPC_DEVICE(obj); -+ s->pm.force_rev1_fadt = value; -+} -+ - void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp) - { - static const uint32_t gpe0_len = ICH9_PMIO_GPE0_LEN; -@@ -465,6 +477,10 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp) - ich9_pm_get_cpu_hotplug_legacy, - ich9_pm_set_cpu_hotplug_legacy, - NULL); -+ object_property_add_bool(obj, "__com.redhat_force-rev1-fadt", -+ ich9_pm_get_force_rev1_fadt, -+ ich9_pm_set_force_rev1_fadt, -+ NULL); - object_property_add(obj, ACPI_PM_PROP_S3_DISABLED, "uint8", - ich9_pm_get_disable_s3, - ich9_pm_set_disable_s3, -diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c -index 98dd424..e38fff2 100644 ---- a/hw/i386/acpi-build.c -+++ b/hw/i386/acpi-build.c -@@ -146,6 +146,8 @@ static void acpi_get_pm_info(AcpiPmInfo *pm) - } - if (lpc) { - obj = lpc; -+ pm->force_rev1_fadt = object_property_get_bool(lpc, -+ "__com.redhat_force-rev1-fadt", NULL); - pm->cpu_hp_io_base = ICH9_CPU_HOTPLUG_IO_BASE; - } - assert(obj); -diff --git a/include/hw/acpi/ich9.h b/include/hw/acpi/ich9.h -index a352c94..e9a8fad 100644 ---- a/include/hw/acpi/ich9.h -+++ b/include/hw/acpi/ich9.h -@@ -61,6 +61,9 @@ typedef struct ICH9LPCPMRegs { - uint8_t smm_enabled; - bool enable_tco; - TCOIORegs tco_regs; -+ -+ /* RH addition, see bz 1489800 */ -+ bool force_rev1_fadt; - } ICH9LPCPMRegs; - - void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, -diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h -index 89bdaa4..a8d6857 100644 ---- a/include/hw/i386/pc.h -+++ b/include/hw/i386/pc.h -@@ -1007,6 +1007,11 @@ extern void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id); - .driver = "mch",\ - .property = "extended-tseg-mbytes",\ - .value = stringify(0),\ -+ },\ -+ { /* PC_RHEL7_4_COMPAT bz 1489800 */ \ -+ .driver = "ICH9-LPC",\ -+ .property = "__com.redhat_force-rev1-fadt",\ -+ .value = "on",\ - }, - - --- -1.8.3.1 - diff --git a/SOURCES/kvm-address_space_access_valid-address_space_to_flatview.patch b/SOURCES/kvm-address_space_access_valid-address_space_to_flatview.patch deleted file mode 100644 index 27e2d2f..0000000 --- a/SOURCES/kvm-address_space_access_valid-address_space_to_flatview.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 026e3aa58780db72c38618e576f4c6029e3b029a Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Thu, 8 Mar 2018 15:58:17 +0100 -Subject: [PATCH 04/17] address_space_access_valid: address_space_to_flatview - needs RCU lock - -RH-Author: Paolo Bonzini -Message-id: <20180308155819.20598-5-pbonzini@redhat.com> -Patchwork-id: 79195 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 4/6] address_space_access_valid: address_space_to_flatview needs RCU lock -Bugzilla: 1554930 -RH-Acked-by: Cornelia Huck -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier - -address_space_access_valid is calling address_space_to_flatview but it can -be called outside the RCU lock. To fix it, push the rcu_read_lock/unlock -pair up from flatview_access_valid to address_space_access_valid. - -Reviewed-by: Alexey Kardashevskiy -Signed-off-by: Paolo Bonzini -(cherry pick from commit 11e732a5ed46903f997985bed4c3767ca28a7eb6) - -[squashed fix for rcu_read_unlock() that should have been removed, - for which I'll send a pull request upstream tomorrow] - -Signed-off-by: Miroslav Rezanina ---- - exec.c | 13 ++++++++----- - 1 file changed, 8 insertions(+), 5 deletions(-) - -diff --git a/exec.c b/exec.c -index 43c66da..431b85b 100644 ---- a/exec.c -+++ b/exec.c -@@ -3259,14 +3259,12 @@ static bool flatview_access_valid(FlatView *fv, hwaddr addr, int len, - MemoryRegion *mr; - hwaddr l, xlat; - -- rcu_read_lock(); - while (len > 0) { - l = len; - mr = flatview_translate(fv, addr, &xlat, &l, is_write); - if (!memory_access_is_direct(mr, is_write)) { - l = memory_access_size(mr, l, addr); - if (!memory_region_access_valid(mr, xlat, l, is_write)) { -- rcu_read_unlock(); - return false; - } - } -@@ -3274,15 +3272,20 @@ static bool flatview_access_valid(FlatView *fv, hwaddr addr, int len, - len -= l; - addr += l; - } -- rcu_read_unlock(); - return true; - } - - bool address_space_access_valid(AddressSpace *as, hwaddr addr, - int len, bool is_write) - { -- return flatview_access_valid(address_space_to_flatview(as), -- addr, len, is_write); -+ FlatView *fv; -+ bool result; -+ -+ rcu_read_lock(); -+ fv = address_space_to_flatview(as); -+ result = flatview_access_valid(fv, addr, len, is_write); -+ rcu_read_unlock(); -+ return result; - } - - static hwaddr --- -1.8.3.1 - diff --git a/SOURCES/kvm-address_space_map-address_space_to_flatview-needs-RC.patch b/SOURCES/kvm-address_space_map-address_space_to_flatview-needs-RC.patch deleted file mode 100644 index 4d6191f..0000000 --- a/SOURCES/kvm-address_space_map-address_space_to_flatview-needs-RC.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 622dc83554563b3d6c74ee7936dbc08bfa6bfa1a Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Thu, 8 Mar 2018 15:58:18 +0100 -Subject: [PATCH 05/17] address_space_map: address_space_to_flatview needs RCU - lock - -RH-Author: Paolo Bonzini -Message-id: <20180308155819.20598-6-pbonzini@redhat.com> -Patchwork-id: 79196 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 5/6] address_space_map: address_space_to_flatview needs RCU lock -Bugzilla: 1554930 -RH-Acked-by: Cornelia Huck -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier - -address_space_map is calling address_space_to_flatview but it can -be called outside the RCU lock. The function itself is calling -rcu_read_lock/rcu_read_unlock, just in the wrong place, so the -fix is easy. - -Reviewed-by: Alexey Kardashevskiy -Signed-off-by: Paolo Bonzini -(cherry pick from commit ad0c60fa572d4050255b698ecdb67294dd4c0125) - -Signed-off-by: Miroslav Rezanina ---- - exec.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/exec.c b/exec.c -index 431b85b..58ad24b 100644 ---- a/exec.c -+++ b/exec.c -@@ -3331,7 +3331,7 @@ void *address_space_map(AddressSpace *as, - hwaddr l, xlat; - MemoryRegion *mr; - void *ptr; -- FlatView *fv = address_space_to_flatview(as); -+ FlatView *fv; - - if (len == 0) { - return NULL; -@@ -3339,6 +3339,7 @@ void *address_space_map(AddressSpace *as, - - l = len; - rcu_read_lock(); -+ fv = address_space_to_flatview(as); - mr = flatview_translate(fv, addr, &xlat, &l, is_write); - - if (!memory_access_is_direct(mr, is_write)) { --- -1.8.3.1 - diff --git a/SOURCES/kvm-address_space_read-address_space_to_flatview-needs-R.patch b/SOURCES/kvm-address_space_read-address_space_to_flatview-needs-R.patch deleted file mode 100644 index 35558e0..0000000 --- a/SOURCES/kvm-address_space_read-address_space_to_flatview-needs-R.patch +++ /dev/null @@ -1,173 +0,0 @@ -From e85fa0f42359527628b5b2243c514acc9670871a Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Thu, 8 Mar 2018 15:58:16 +0100 -Subject: [PATCH 03/17] address_space_read: address_space_to_flatview needs RCU - lock - -RH-Author: Paolo Bonzini -Message-id: <20180308155819.20598-4-pbonzini@redhat.com> -Patchwork-id: 79190 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 3/6] address_space_read: address_space_to_flatview needs RCU lock -Bugzilla: 1554930 -RH-Acked-by: Cornelia Huck -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier - -address_space_read is calling address_space_to_flatview but it can -be called outside the RCU lock. To fix it, push the rcu_read_lock/unlock -pair up from flatview_read_full to address_space_read's constant size -fast path and address_space_read_full. - -Reviewed-by: Alexey Kardashevskiy -Signed-off-by: Paolo Bonzini -(cherry pick from commit b2a44fcad74f1cc7a6786d38eba7db12ab2352ba) - -Signed-off-by: Miroslav Rezanina ---- - exec.c | 38 +++++++++++++++++++++++++------------- - include/exec/memory.h | 23 +++++++++-------------- - 2 files changed, 34 insertions(+), 27 deletions(-) - -diff --git a/exec.c b/exec.c -index 8b50133..43c66da 100644 ---- a/exec.c -+++ b/exec.c -@@ -2512,6 +2512,8 @@ static const MemoryRegionOps watch_mem_ops = { - .endianness = DEVICE_NATIVE_ENDIAN, - }; - -+static MemTxResult flatview_read(FlatView *fv, hwaddr addr, -+ MemTxAttrs attrs, uint8_t *buf, int len); - static MemTxResult flatview_write(FlatView *fv, hwaddr addr, MemTxAttrs attrs, - const uint8_t *buf, int len); - static bool flatview_access_valid(FlatView *fv, hwaddr addr, int len, -@@ -3029,24 +3031,18 @@ MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr, - return result; - } - --MemTxResult flatview_read_full(FlatView *fv, hwaddr addr, -- MemTxAttrs attrs, uint8_t *buf, int len) -+/* Called from RCU critical section. */ -+static MemTxResult flatview_read(FlatView *fv, hwaddr addr, -+ MemTxAttrs attrs, uint8_t *buf, int len) - { - hwaddr l; - hwaddr addr1; - MemoryRegion *mr; -- MemTxResult result = MEMTX_OK; -- -- if (len > 0) { -- rcu_read_lock(); -- l = len; -- mr = flatview_translate(fv, addr, &addr1, &l, false); -- result = flatview_read_continue(fv, addr, attrs, buf, len, -- addr1, l, mr); -- rcu_read_unlock(); -- } - -- return result; -+ l = len; -+ mr = flatview_translate(fv, addr, &addr1, &l, false); -+ return flatview_read_continue(fv, addr, attrs, buf, len, -+ addr1, l, mr); - } - - static MemTxResult flatview_rw(FlatView *fv, hwaddr addr, MemTxAttrs attrs, -@@ -3067,6 +3063,22 @@ MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, - addr, attrs, buf, len, is_write); - } - -+MemTxResult address_space_read_full(AddressSpace *as, hwaddr addr, -+ MemTxAttrs attrs, uint8_t *buf, int len) -+{ -+ MemTxResult result = MEMTX_OK; -+ FlatView *fv; -+ -+ if (len > 0) { -+ rcu_read_lock(); -+ fv = address_space_to_flatview(as); -+ result = flatview_read(fv, addr, attrs, buf, len); -+ rcu_read_unlock(); -+ } -+ -+ return result; -+} -+ - MemTxResult address_space_write(AddressSpace *as, hwaddr addr, - MemTxAttrs attrs, - const uint8_t *buf, int len) -diff --git a/include/exec/memory.h b/include/exec/memory.h -index 3df0dcc..a66b6ef 100644 ---- a/include/exec/memory.h -+++ b/include/exec/memory.h -@@ -1917,13 +1917,12 @@ void address_space_unmap(AddressSpace *as, void *buffer, hwaddr len, - - - /* Internal functions, part of the implementation of address_space_read. */ -+MemTxResult address_space_read_full(AddressSpace *as, hwaddr addr, -+ MemTxAttrs attrs, uint8_t *buf, int len); - MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr, - MemTxAttrs attrs, uint8_t *buf, - int len, hwaddr addr1, hwaddr l, - MemoryRegion *mr); -- --MemTxResult flatview_read_full(FlatView *fv, hwaddr addr, -- MemTxAttrs attrs, uint8_t *buf, int len); - void *qemu_map_ram_ptr(RAMBlock *ram_block, ram_addr_t addr); - - static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write) -@@ -1942,7 +1941,7 @@ static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write) - * - * Return a MemTxResult indicating whether the operation succeeded - * or failed (eg unassigned memory, device rejected the transaction, -- * IOMMU fault). -+ * IOMMU fault). Called within RCU critical section. - * - * @as: #AddressSpace to be accessed - * @addr: address within that address space -@@ -1950,17 +1949,20 @@ static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write) - * @buf: buffer with the data transferred - */ - static inline __attribute__((__always_inline__)) --MemTxResult flatview_read(FlatView *fv, hwaddr addr, MemTxAttrs attrs, -- uint8_t *buf, int len) -+MemTxResult address_space_read(AddressSpace *as, hwaddr addr, -+ MemTxAttrs attrs, uint8_t *buf, -+ int len) - { - MemTxResult result = MEMTX_OK; - hwaddr l, addr1; - void *ptr; - MemoryRegion *mr; -+ FlatView *fv; - - if (__builtin_constant_p(len)) { - if (len) { - rcu_read_lock(); -+ fv = address_space_to_flatview(as); - l = len; - mr = flatview_translate(fv, addr, &addr1, &l, false); - if (len == l && memory_access_is_direct(mr, false)) { -@@ -1973,18 +1975,11 @@ MemTxResult flatview_read(FlatView *fv, hwaddr addr, MemTxAttrs attrs, - rcu_read_unlock(); - } - } else { -- result = flatview_read_full(fv, addr, attrs, buf, len); -+ result = address_space_read_full(as, addr, attrs, buf, len); - } - return result; - } - --static inline MemTxResult address_space_read(AddressSpace *as, hwaddr addr, -- MemTxAttrs attrs, uint8_t *buf, -- int len) --{ -- return flatview_read(address_space_to_flatview(as), addr, attrs, buf, len); --} -- - /** - * address_space_read_cached: read from a cached RAM region - * --- -1.8.3.1 - diff --git a/SOURCES/kvm-address_space_rw-address_space_to_flatview-needs-RCU.patch b/SOURCES/kvm-address_space_rw-address_space_to_flatview-needs-RCU.patch deleted file mode 100644 index 2225610..0000000 --- a/SOURCES/kvm-address_space_rw-address_space_to_flatview-needs-RCU.patch +++ /dev/null @@ -1,77 +0,0 @@ -From ca87b042011f83f8851f0f76b3599d627d61463d Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Thu, 8 Mar 2018 15:58:19 +0100 -Subject: [PATCH 06/17] address_space_rw: address_space_to_flatview needs RCU - lock - -RH-Author: Paolo Bonzini -Message-id: <20180308155819.20598-7-pbonzini@redhat.com> -Patchwork-id: 79192 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 6/6] address_space_rw: address_space_to_flatview needs RCU lock -Bugzilla: 1554930 -RH-Acked-by: Cornelia Huck -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier - -address_space_rw is calling address_space_to_flatview but it can -be called outside the RCU lock. To fix it, transform flatview_rw -into address_space_rw, since flatview_rw is otherwise unused. - -Reviewed-by: Alexey Kardashevskiy -Signed-off-by: Paolo Bonzini -(cherry pick from commit db84fd973eba3f1e121416dcab73a4e8a60f2526) - -Signed-off-by: Miroslav Rezanina ---- - exec.c | 28 ++++++++++------------------ - 1 file changed, 10 insertions(+), 18 deletions(-) - -diff --git a/exec.c b/exec.c -index 58ad24b..12ec761 100644 ---- a/exec.c -+++ b/exec.c -@@ -3045,24 +3045,6 @@ static MemTxResult flatview_read(FlatView *fv, hwaddr addr, - addr1, l, mr); - } - --static MemTxResult flatview_rw(FlatView *fv, hwaddr addr, MemTxAttrs attrs, -- uint8_t *buf, int len, bool is_write) --{ -- if (is_write) { -- return flatview_write(fv, addr, attrs, (uint8_t *)buf, len); -- } else { -- return flatview_read(fv, addr, attrs, (uint8_t *)buf, len); -- } --} -- --MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, -- MemTxAttrs attrs, uint8_t *buf, -- int len, bool is_write) --{ -- return flatview_rw(address_space_to_flatview(as), -- addr, attrs, buf, len, is_write); --} -- - MemTxResult address_space_read_full(AddressSpace *as, hwaddr addr, - MemTxAttrs attrs, uint8_t *buf, int len) - { -@@ -3096,6 +3078,16 @@ MemTxResult address_space_write(AddressSpace *as, hwaddr addr, - return result; - } - -+MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, MemTxAttrs attrs, -+ uint8_t *buf, int len, bool is_write) -+{ -+ if (is_write) { -+ return address_space_write(as, addr, attrs, buf, len); -+ } else { -+ return address_space_read_full(as, addr, attrs, buf, len); -+ } -+} -+ - void cpu_physical_memory_rw(hwaddr addr, uint8_t *buf, - int len, int is_write) - { --- -1.8.3.1 - diff --git a/SOURCES/kvm-address_space_write-address_space_to_flatview-needs-.patch b/SOURCES/kvm-address_space_write-address_space_to_flatview-needs-.patch deleted file mode 100644 index 6028b19..0000000 --- a/SOURCES/kvm-address_space_write-address_space_to_flatview-needs-.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 2f3881255e6a50d9821f390972b07c1e9d9de626 Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Thu, 8 Mar 2018 15:58:15 +0100 -Subject: [PATCH 02/17] address_space_write: address_space_to_flatview needs - RCU lock - -RH-Author: Paolo Bonzini -Message-id: <20180308155819.20598-3-pbonzini@redhat.com> -Patchwork-id: 79191 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 2/6] address_space_write: address_space_to_flatview needs RCU lock -Bugzilla: 1554930 -RH-Acked-by: Cornelia Huck -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier - -address_space_write is calling address_space_to_flatview but it can -be called outside the RCU lock. To fix it, push the rcu_read_lock/unlock -pair up from flatview_write to address_space_write. - -Reviewed-by: Alexey Kardashevskiy -Signed-off-by: Paolo Bonzini -(cherry pick from commit 4c6ebbb364aa6f42c5d8e83e932e967eb83f0e44) - -Signed-off-by: Miroslav Rezanina ---- - exec.c | 37 ++++++++++++++++++++++--------------- - 1 file changed, 22 insertions(+), 15 deletions(-) - -diff --git a/exec.c b/exec.c -index 5a12e55..8b50133 100644 ---- a/exec.c -+++ b/exec.c -@@ -2942,6 +2942,7 @@ static MemTxResult flatview_write_continue(FlatView *fv, hwaddr addr, - return result; - } - -+/* Called from RCU critical section. */ - static MemTxResult flatview_write(FlatView *fv, hwaddr addr, MemTxAttrs attrs, - const uint8_t *buf, int len) - { -@@ -2950,25 +2951,14 @@ static MemTxResult flatview_write(FlatView *fv, hwaddr addr, MemTxAttrs attrs, - MemoryRegion *mr; - MemTxResult result = MEMTX_OK; - -- if (len > 0) { -- rcu_read_lock(); -- l = len; -- mr = flatview_translate(fv, addr, &addr1, &l, true); -- result = flatview_write_continue(fv, addr, attrs, buf, len, -- addr1, l, mr); -- rcu_read_unlock(); -- } -+ l = len; -+ mr = flatview_translate(fv, addr, &addr1, &l, true); -+ result = flatview_write_continue(fv, addr, attrs, buf, len, -+ addr1, l, mr); - - return result; - } - --MemTxResult address_space_write(AddressSpace *as, hwaddr addr, -- MemTxAttrs attrs, -- const uint8_t *buf, int len) --{ -- return flatview_write(address_space_to_flatview(as), addr, attrs, buf, len); --} -- - /* Called within RCU critical section. */ - MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr, - MemTxAttrs attrs, uint8_t *buf, -@@ -3077,6 +3067,23 @@ MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, - addr, attrs, buf, len, is_write); - } - -+MemTxResult address_space_write(AddressSpace *as, hwaddr addr, -+ MemTxAttrs attrs, -+ const uint8_t *buf, int len) -+{ -+ MemTxResult result = MEMTX_OK; -+ FlatView *fv; -+ -+ if (len > 0) { -+ rcu_read_lock(); -+ fv = address_space_to_flatview(as); -+ result = flatview_write(fv, addr, attrs, buf, len); -+ rcu_read_unlock(); -+ } -+ -+ return result; -+} -+ - void cpu_physical_memory_rw(hwaddr addr, uint8_t *buf, - int len, int is_write) - { --- -1.8.3.1 - diff --git a/SOURCES/kvm-ahci-don-t-schedule-unnecessary-BH.patch b/SOURCES/kvm-ahci-don-t-schedule-unnecessary-BH.patch new file mode 100644 index 0000000..dc5aef2 --- /dev/null +++ b/SOURCES/kvm-ahci-don-t-schedule-unnecessary-BH.patch @@ -0,0 +1,46 @@ +From 80d7419e93a1195b46c6c917b4533ca440c12c82 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Tue, 10 Jul 2018 23:06:16 +0200 +Subject: [PATCH 33/89] ahci: don't schedule unnecessary BH + +RH-Author: John Snow +Message-id: <20180710230616.11000-4-jsnow@redhat.com> +Patchwork-id: 81292 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 3/3] ahci: don't schedule unnecessary BH +Bugzilla: 1584914 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Stefan Hajnoczi + +The comment gives us a hint. *Maybe* we still have something to +process. Well, why not check? + +Signed-off-by: John Snow +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Jeff Cody +Message-id: 20180531004323.4611-4-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit 42af312adef8afdae11d5f83d12a404b178dbda4) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + hw/ide/ahci.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c +index a9558e4..380366b 100644 +--- a/hw/ide/ahci.c ++++ b/hw/ide/ahci.c +@@ -1427,8 +1427,7 @@ static void ahci_cmd_done(IDEDMA *dma) + /* update d2h status */ + ahci_write_fis_d2h(ad); + +- if (!ad->check_bh) { +- /* maybe we still have something to process, check later */ ++ if (ad->port_regs.cmd_issue && !ad->check_bh) { + ad->check_bh = qemu_bh_new(ahci_check_cmd_bh, ad); + qemu_bh_schedule(ad->check_bh); + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-ahci-fix-PxCI-register-race.patch b/SOURCES/kvm-ahci-fix-PxCI-register-race.patch new file mode 100644 index 0000000..40412a4 --- /dev/null +++ b/SOURCES/kvm-ahci-fix-PxCI-register-race.patch @@ -0,0 +1,81 @@ +From 41f2bce1d8d55b1a35bd7456b4b13b5bc098745f Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Tue, 10 Jul 2018 23:06:15 +0200 +Subject: [PATCH 32/89] ahci: fix PxCI register race +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: John Snow +Message-id: <20180710230616.11000-3-jsnow@redhat.com> +Patchwork-id: 81293 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 2/3] ahci: fix PxCI register race +Bugzilla: 1584914 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Stefan Hajnoczi + +Fixes: https://bugs.launchpad.net/qemu/+bug/1769189 + +AHCI presently signals completion prior to the PxCI register being +cleared to indicate completion. If a guest driver attempts to issue +a new command in its IRQ handler, it might be surprised to learn there +is still a command pending. + +In the case of Windows 10's boot driver, it will actually poll the IRQ +register hoping to find out when the command is done running -- which +will never happen, as there isn't a command running. + +Fix this: clear PxCI in ahci_cmd_done and not in the asynchronous BH. +Because it now runs synchronously, we don't need to check if the command +is actually done by spying on the ATA registers. We know it's done. + +CC: qemu-stable +Reported-by: François Guerraz +Tested-by: Bruce Rogers +Signed-off-by: John Snow +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Jeff Cody +Message-id: 20180531004323.4611-3-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit 5694c7eacce6b263ad7497cc1bb76aad746cfd4e) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + hw/ide/ahci.c | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c +index b7a6f68..a9558e4 100644 +--- a/hw/ide/ahci.c ++++ b/hw/ide/ahci.c +@@ -532,13 +532,6 @@ static void ahci_check_cmd_bh(void *opaque) + qemu_bh_delete(ad->check_bh); + ad->check_bh = NULL; + +- if ((ad->busy_slot != -1) && +- !(ad->port.ifs[0].status & (BUSY_STAT|DRQ_STAT))) { +- /* no longer busy */ +- ad->port_regs.cmd_issue &= ~(1 << ad->busy_slot); +- ad->busy_slot = -1; +- } +- + check_cmd(ad->hba, ad->port_no); + } + +@@ -1425,6 +1418,12 @@ static void ahci_cmd_done(IDEDMA *dma) + + trace_ahci_cmd_done(ad->hba, ad->port_no); + ++ /* no longer busy */ ++ if (ad->busy_slot != -1) { ++ ad->port_regs.cmd_issue &= ~(1 << ad->busy_slot); ++ ad->busy_slot = -1; ++ } ++ + /* update d2h status */ + ahci_write_fis_d2h(ad); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-ahci-trim-signatures-on-raise-lower.patch b/SOURCES/kvm-ahci-trim-signatures-on-raise-lower.patch new file mode 100644 index 0000000..7a36f41 --- /dev/null +++ b/SOURCES/kvm-ahci-trim-signatures-on-raise-lower.patch @@ -0,0 +1,66 @@ +From 2b9789734ace2edd99aab3e76a559f29201e0d8d Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Tue, 10 Jul 2018 23:06:14 +0200 +Subject: [PATCH 31/89] ahci: trim signatures on raise/lower + +RH-Author: John Snow +Message-id: <20180710230616.11000-2-jsnow@redhat.com> +Patchwork-id: 81295 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/3] ahci: trim signatures on raise/lower +Bugzilla: 1584914 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Stefan Hajnoczi + +These functions work on the AHCI device, not the individual +AHCI devices, so trim the AHCIDevice argument. + +Signed-off-by: John Snow +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Jeff Cody +Message-id: 20180531004323.4611-2-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit dc5a43eda68fff32c7b0b43847332db325b094f3) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + hw/ide/ahci.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c +index e22d7be..b7a6f68 100644 +--- a/hw/ide/ahci.c ++++ b/hw/ide/ahci.c +@@ -131,7 +131,7 @@ static uint32_t ahci_port_read(AHCIState *s, int port, int offset) + return val; + } + +-static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev) ++static void ahci_irq_raise(AHCIState *s) + { + DeviceState *dev_state = s->container; + PCIDevice *pci_dev = (PCIDevice *) object_dynamic_cast(OBJECT(dev_state), +@@ -146,7 +146,7 @@ static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev) + } + } + +-static void ahci_irq_lower(AHCIState *s, AHCIDevice *dev) ++static void ahci_irq_lower(AHCIState *s) + { + DeviceState *dev_state = s->container; + PCIDevice *pci_dev = (PCIDevice *) object_dynamic_cast(OBJECT(dev_state), +@@ -174,9 +174,9 @@ static void ahci_check_irq(AHCIState *s) + trace_ahci_check_irq(s, old_irq, s->control_regs.irqstatus); + if (s->control_regs.irqstatus && + (s->control_regs.ghc & HOST_CTL_IRQ_EN)) { +- ahci_irq_raise(s, NULL); ++ ahci_irq_raise(s); + } else { +- ahci_irq_lower(s, NULL); ++ ahci_irq_lower(s); + } + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-aio-Do-aio_notify_accept-only-during-blocking-aio_po.patch b/SOURCES/kvm-aio-Do-aio_notify_accept-only-during-blocking-aio_po.patch new file mode 100644 index 0000000..fff781d --- /dev/null +++ b/SOURCES/kvm-aio-Do-aio_notify_accept-only-during-blocking-aio_po.patch @@ -0,0 +1,122 @@ +From a2e385fea51333b9cfbf88b19cbb4f82a5677381 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 17 Aug 2018 03:08:36 +0200 +Subject: [PATCH 5/5] aio: Do aio_notify_accept only during blocking aio_poll + +RH-Author: Fam Zheng +Message-id: <20180817030836.20581-3-famz@redhat.com> +Patchwork-id: 81862 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 2/2] aio: Do aio_notify_accept only during blocking aio_poll +Bugzilla: 1562750 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek + +An aio_notify() pairs with an aio_notify_accept(). The former should +happen in the main thread or a vCPU thread, and the latter should be +done in the IOThread. + +There is one rare case that the main thread or vCPU thread may "steal" +the aio_notify() event just raised by itself, in bdrv_set_aio_context() +[1]. The sequence is like this: + + main thread IO Thread + =============================================================== + bdrv_drained_begin() + aio_disable_external(ctx) + aio_poll(ctx, true) + ctx->notify_me += 2 + ... + bdrv_drained_end() + ... + aio_notify() + ... + bdrv_set_aio_context() + aio_poll(ctx, false) +[1] aio_notify_accept(ctx) + ppoll() /* Hang! */ + +[1] is problematic. It will clear the ctx->notifier event so that +the blocked ppoll() will not return. + +(For the curious, this bug was noticed when booting a number of VMs +simultaneously in RHV. One or two of the VMs will hit this race +condition, making the VIRTIO device unresponsive to I/O commands. When +it hangs, Seabios is busy waiting for a read request to complete (read +MBR), right after initializing the virtio-blk-pci device, using 100% +guest CPU. See also https://bugzilla.redhat.com/show_bug.cgi?id=1562750 +for the original bug analysis.) + +aio_notify() only injects an event when ctx->notify_me is set, +correspondingly aio_notify_accept() is only useful when ctx->notify_me +_was_ set. Move the call to it into the "blocking" branch. This will +effectively skip [1] and fix the hang. + +Furthermore, blocking aio_poll is only allowed on home thread +(in_aio_context_home_thread), because otherwise two blocking +aio_poll()'s can steal each other's ctx->notifier event and cause +hanging just like described above. + +Cc: qemu-stable@nongnu.org +Suggested-by: Paolo Bonzini +Signed-off-by: Fam Zheng +Message-Id: <20180809132259.18402-3-famz@redhat.com> +Signed-off-by: Fam Zheng +(cherry picked from commit b37548fcd1b8ac2e88e185a395bef851f3fc4e65) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + util/aio-posix.c | 4 ++-- + util/aio-win32.c | 3 ++- + 2 files changed, 4 insertions(+), 3 deletions(-) + +diff --git a/util/aio-posix.c b/util/aio-posix.c +index f650c7c..f05d3a8 100644 +--- a/util/aio-posix.c ++++ b/util/aio-posix.c +@@ -591,6 +591,7 @@ bool aio_poll(AioContext *ctx, bool blocking) + * so disable the optimization now. + */ + if (blocking) { ++ assert(in_aio_context_home_thread(ctx)); + atomic_add(&ctx->notify_me, 2); + } + +@@ -633,6 +634,7 @@ bool aio_poll(AioContext *ctx, bool blocking) + + if (blocking) { + atomic_sub(&ctx->notify_me, 2); ++ aio_notify_accept(ctx); + } + + /* Adjust polling time */ +@@ -676,8 +678,6 @@ bool aio_poll(AioContext *ctx, bool blocking) + } + } + +- aio_notify_accept(ctx); +- + /* if we have any readable fds, dispatch event */ + if (ret > 0) { + for (i = 0; i < npfd; i++) { +diff --git a/util/aio-win32.c b/util/aio-win32.c +index a67b00c..ac5524c 100644 +--- a/util/aio-win32.c ++++ b/util/aio-win32.c +@@ -373,11 +373,12 @@ bool aio_poll(AioContext *ctx, bool blocking) + ret = WaitForMultipleObjects(count, events, FALSE, timeout); + if (blocking) { + assert(first); ++ assert(in_aio_context_home_thread(ctx)); + atomic_sub(&ctx->notify_me, 2); ++ aio_notify_accept(ctx); + } + + if (first) { +- aio_notify_accept(ctx); + progress |= aio_bh_poll(ctx); + first = false; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-aio-fix-assert-when-remove-poll-during-destroy.patch b/SOURCES/kvm-aio-fix-assert-when-remove-poll-during-destroy.patch deleted file mode 100644 index ad3bb86..0000000 --- a/SOURCES/kvm-aio-fix-assert-when-remove-poll-during-destroy.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 5ca7635b41a142a709364412fb367c23ac169a21 Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Fri, 22 Dec 2017 11:08:48 +0100 -Subject: [PATCH 30/42] aio: fix assert when remove poll during destroy - -RH-Author: Stefan Hajnoczi -Message-id: <20171222110900.24813-9-stefanha@redhat.com> -Patchwork-id: 78491 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 08/20] aio: fix assert when remove poll during destroy -Bugzilla: 1519721 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -After iothread is enabled internally inside QEMU with GMainContext, we -may encounter this warning when destroying the iothread: - -(qemu-system-x86_64:19925): GLib-CRITICAL **: g_source_remove_poll: - assertion '!SOURCE_DESTROYED (source)' failed - -The problem is that g_source_remove_poll() does not allow to remove one -source from array if the source is detached from its owner -context. (peterx: which IMHO does not make much sense) - -Fix it on QEMU side by avoid calling g_source_remove_poll() if we know -the object is during destruction, and we won't leak anything after all -since the array will be gone soon cleanly even with that fd. - -Signed-off-by: Stefan Hajnoczi -Reviewed-by: Fam Zheng -Signed-off-by: Peter Xu -Message-id: 20170928025958.1420-6-peterx@redhat.com -[peterx: write the commit message] -Signed-off-by: Peter Xu -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit f708a5e71cba0d784e307334c07ade5f56f827ab) -Signed-off-by: Stefan Hajnoczi - -Signed-off-by: Miroslav Rezanina ---- - util/aio-posix.c | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/util/aio-posix.c b/util/aio-posix.c -index 2d51239..5946ac0 100644 ---- a/util/aio-posix.c -+++ b/util/aio-posix.c -@@ -223,7 +223,14 @@ void aio_set_fd_handler(AioContext *ctx, - return; - } - -- g_source_remove_poll(&ctx->source, &node->pfd); -+ /* If the GSource is in the process of being destroyed then -+ * g_source_remove_poll() causes an assertion failure. Skip -+ * removal in that case, because glib cleans up its state during -+ * destruction anyway. -+ */ -+ if (!g_source_is_destroyed(&ctx->source)) { -+ g_source_remove_poll(&ctx->source, &node->pfd); -+ } - - /* If the lock is held, just mark the node as deleted */ - if (qemu_lockcnt_count(&ctx->list_lock)) { --- -1.8.3.1 - diff --git a/SOURCES/kvm-aio-posix-Don-t-count-ctx-notifier-as-progress-when-.patch b/SOURCES/kvm-aio-posix-Don-t-count-ctx-notifier-as-progress-when-.patch new file mode 100644 index 0000000..a6fd736 --- /dev/null +++ b/SOURCES/kvm-aio-posix-Don-t-count-ctx-notifier-as-progress-when-.patch @@ -0,0 +1,47 @@ +From 8c5d6c7bdc1cd5557503764ff8187d39bed3cbe1 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 17 Aug 2018 03:08:35 +0200 +Subject: [PATCH 4/5] aio-posix: Don't count ctx->notifier as progress when + polling + +RH-Author: Fam Zheng +Message-id: <20180817030836.20581-2-famz@redhat.com> +Patchwork-id: 81861 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/2] aio-posix: Don't count ctx->notifier as progress when polling +Bugzilla: 1562750 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek + +The same logic exists in fd polling. This change is especially important +to avoid busy loop once we limit aio_notify_accept() to blocking +aio_poll(). + +Cc: qemu-stable@nongnu.org +Signed-off-by: Fam Zheng +Message-Id: <20180809132259.18402-2-famz@redhat.com> +Signed-off-by: Fam Zheng +(cherry picked from commit 70232b5253a3c4e03ed1ac47ef9246a8ac66c6fa) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + util/aio-posix.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/util/aio-posix.c b/util/aio-posix.c +index d8f0cb4..f650c7c 100644 +--- a/util/aio-posix.c ++++ b/util/aio-posix.c +@@ -494,7 +494,8 @@ static bool run_poll_handlers_once(AioContext *ctx) + QLIST_FOREACH_RCU(node, &ctx->aio_handlers, node) { + if (!node->deleted && node->io_poll && + aio_node_check(ctx, node->is_external) && +- node->io_poll(node->opaque)) { ++ node->io_poll(node->opaque) && ++ node->opaque != &ctx->notifier) { + progress = true; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-aio-posix-compute-timeout-before-polling.patch b/SOURCES/kvm-aio-posix-compute-timeout-before-polling.patch new file mode 100644 index 0000000..3e5b6ed --- /dev/null +++ b/SOURCES/kvm-aio-posix-compute-timeout-before-polling.patch @@ -0,0 +1,182 @@ +From 451a04350505ac3078620cacc1c89389c848e6c5 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Tue, 18 Sep 2018 09:07:13 +0200 +Subject: [PATCH 2/3] aio-posix: compute timeout before polling + +RH-Author: Fam Zheng +Message-id: <20180918090714.18069-3-famz@redhat.com> +Patchwork-id: 82213 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 2/3] aio-posix: compute timeout before polling +Bugzilla: 1628191 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +From: Paolo Bonzini + +This is a preparation for the next patch, and also a very small +optimization. Compute the timeout only once, before invoking +try_poll_mode, and adjust it in run_poll_handlers. The adjustment +is the polling time when polling fails, or zero (non-blocking) if +polling succeeds. + +Fixes: 70232b5253a3c4e03ed1ac47ef9246a8ac66c6fa +Signed-off-by: Paolo Bonzini +Message-Id: <20180912171040.1732-3-pbonzini@redhat.com> +Reviewed-by: Fam Zheng +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + util/aio-posix.c | 59 ++++++++++++++++++++++++++++++++----------------------- + util/trace-events | 4 ++-- + 2 files changed, 36 insertions(+), 27 deletions(-) + +diff --git a/util/aio-posix.c b/util/aio-posix.c +index 1d7cc53..1b17597 100644 +--- a/util/aio-posix.c ++++ b/util/aio-posix.c +@@ -490,7 +490,7 @@ static void add_pollfd(AioHandler *node) + npfd++; + } + +-static bool run_poll_handlers_once(AioContext *ctx) ++static bool run_poll_handlers_once(AioContext *ctx, int64_t *timeout) + { + bool progress = false; + AioHandler *node; +@@ -500,6 +500,7 @@ static bool run_poll_handlers_once(AioContext *ctx) + aio_node_check(ctx, node->is_external) && + node->io_poll(node->opaque) && + node->opaque != &ctx->notifier) { ++ *timeout = 0; + progress = true; + } + +@@ -522,31 +523,38 @@ static bool run_poll_handlers_once(AioContext *ctx) + * + * Returns: true if progress was made, false otherwise + */ +-static bool run_poll_handlers(AioContext *ctx, int64_t max_ns) ++static bool run_poll_handlers(AioContext *ctx, int64_t max_ns, int64_t *timeout) + { + bool progress; +- int64_t end_time; ++ int64_t start_time, elapsed_time; + + assert(ctx->notify_me); + assert(qemu_lockcnt_count(&ctx->list_lock) > 0); + +- trace_run_poll_handlers_begin(ctx, max_ns); +- +- end_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + max_ns; ++ trace_run_poll_handlers_begin(ctx, max_ns, *timeout); + ++ start_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); + do { +- progress = run_poll_handlers_once(ctx); +- } while (!progress && qemu_clock_get_ns(QEMU_CLOCK_REALTIME) < end_time ++ progress = run_poll_handlers_once(ctx, timeout); ++ elapsed_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - start_time; ++ } while (!progress && elapsed_time < max_ns + && !atomic_read(&ctx->poll_disable_cnt)); + +- trace_run_poll_handlers_end(ctx, progress); ++ /* If time has passed with no successful polling, adjust *timeout to ++ * keep the same ending time. ++ */ ++ if (*timeout != -1) { ++ *timeout -= MIN(*timeout, elapsed_time); ++ } + ++ trace_run_poll_handlers_end(ctx, progress, *timeout); + return progress; + } + + /* try_poll_mode: + * @ctx: the AioContext +- * @blocking: busy polling is only attempted when blocking is true ++ * @timeout: timeout for blocking wait, computed by the caller and updated if ++ * polling succeeds. + * + * ctx->notify_me must be non-zero so this function can detect aio_notify(). + * +@@ -554,19 +562,16 @@ static bool run_poll_handlers(AioContext *ctx, int64_t max_ns) + * + * Returns: true if progress was made, false otherwise + */ +-static bool try_poll_mode(AioContext *ctx, bool blocking) ++static bool try_poll_mode(AioContext *ctx, int64_t *timeout) + { +- if (blocking && ctx->poll_max_ns && !atomic_read(&ctx->poll_disable_cnt)) { +- /* See qemu_soonest_timeout() uint64_t hack */ +- int64_t max_ns = MIN((uint64_t)aio_compute_timeout(ctx), +- (uint64_t)ctx->poll_ns); ++ /* See qemu_soonest_timeout() uint64_t hack */ ++ int64_t max_ns = MIN((uint64_t)*timeout, (uint64_t)ctx->poll_ns); + +- if (max_ns) { +- poll_set_started(ctx, true); ++ if (max_ns && !atomic_read(&ctx->poll_disable_cnt)) { ++ poll_set_started(ctx, true); + +- if (run_poll_handlers(ctx, max_ns)) { +- return true; +- } ++ if (run_poll_handlers(ctx, max_ns, timeout)) { ++ return true; + } + } + +@@ -575,7 +580,7 @@ static bool try_poll_mode(AioContext *ctx, bool blocking) + /* Even if we don't run busy polling, try polling once in case it can make + * progress and the caller will be able to avoid ppoll(2)/epoll_wait(2). + */ +- return run_poll_handlers_once(ctx); ++ return run_poll_handlers_once(ctx, timeout); + } + + bool aio_poll(AioContext *ctx, bool blocking) +@@ -605,8 +610,14 @@ bool aio_poll(AioContext *ctx, bool blocking) + start = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); + } + +- progress = try_poll_mode(ctx, blocking); +- if (!progress) { ++ timeout = blocking ? aio_compute_timeout(ctx) : 0; ++ progress = try_poll_mode(ctx, &timeout); ++ assert(!(timeout && progress)); ++ ++ /* If polling is allowed, non-blocking aio_poll does not need the ++ * system call---a single round of run_poll_handlers_once suffices. ++ */ ++ if (timeout || atomic_read(&ctx->poll_disable_cnt)) { + assert(npfd == 0); + + /* fill pollfds */ +@@ -620,8 +631,6 @@ bool aio_poll(AioContext *ctx, bool blocking) + } + } + +- timeout = blocking ? aio_compute_timeout(ctx) : 0; +- + /* wait until next event */ + if (aio_epoll_check_poll(ctx, pollfds, npfd, timeout)) { + AioHandler epoll_handler; +diff --git a/util/trace-events b/util/trace-events +index 4822434..79569b7 100644 +--- a/util/trace-events ++++ b/util/trace-events +@@ -1,8 +1,8 @@ + # See docs/devel/tracing.txt for syntax documentation. + + # util/aio-posix.c +-run_poll_handlers_begin(void *ctx, int64_t max_ns) "ctx %p max_ns %"PRId64 +-run_poll_handlers_end(void *ctx, bool progress) "ctx %p progress %d" ++run_poll_handlers_begin(void *ctx, int64_t max_ns, int64_t timeout) "ctx %p max_ns %"PRId64 " timeout %"PRId64 ++run_poll_handlers_end(void *ctx, bool progress, int64_t timeout) "ctx %p progress %d new timeout %"PRId64 + poll_shrink(void *ctx, int64_t old, int64_t new) "ctx %p old %"PRId64" new %"PRId64 + poll_grow(void *ctx, int64_t old, int64_t new) "ctx %p old %"PRId64" new %"PRId64 + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-aio-posix-do-skip-system-call-if-ctx-notifier-pollin.patch b/SOURCES/kvm-aio-posix-do-skip-system-call-if-ctx-notifier-pollin.patch new file mode 100644 index 0000000..019141c --- /dev/null +++ b/SOURCES/kvm-aio-posix-do-skip-system-call-if-ctx-notifier-pollin.patch @@ -0,0 +1,61 @@ +From 189e720e9fa5536fb22960f158b3b7f91dcccf2c Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Tue, 18 Sep 2018 09:07:14 +0200 +Subject: [PATCH 3/3] aio-posix: do skip system call if ctx->notifier polling + succeeds + +RH-Author: Fam Zheng +Message-id: <20180918090714.18069-4-famz@redhat.com> +Patchwork-id: 82214 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 3/3] aio-posix: do skip system call if ctx->notifier polling succeeds +Bugzilla: 1628191 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +From: Paolo Bonzini + +Commit 70232b5253 ("aio-posix: Don't count ctx->notifier as progress when +2018-08-15), by not reporting progress, causes aio_poll to execute the +system call when polling succeeds because of ctx->notifier. This introduces +latency before the call to aio_bh_poll() and negates the advantages of +polling, unfortunately. + +The fix builds on the previous patch, separating the effect of polling on +the timeout from the progress reported to aio_poll(). ctx->notifier +does zero the timeout, causing the caller to skip the system call, +but it does not report progress, so that the bug fix of commit 70232b5253 +still stands. + +Fixes: 70232b5253a3c4e03ed1ac47ef9246a8ac66c6fa +Signed-off-by: Paolo Bonzini +Message-Id: <20180912171040.1732-4-pbonzini@redhat.com> +Reviewed-by: Fam Zheng +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + util/aio-posix.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/util/aio-posix.c b/util/aio-posix.c +index 1b17597..357de8a 100644 +--- a/util/aio-posix.c ++++ b/util/aio-posix.c +@@ -498,10 +498,11 @@ static bool run_poll_handlers_once(AioContext *ctx, int64_t *timeout) + QLIST_FOREACH_RCU(node, &ctx->aio_handlers, node) { + if (!node->deleted && node->io_poll && + aio_node_check(ctx, node->is_external) && +- node->io_poll(node->opaque) && +- node->opaque != &ctx->notifier) { ++ node->io_poll(node->opaque)) { + *timeout = 0; +- progress = true; ++ if (node->opaque != &ctx->notifier) { ++ progress = true; ++ } + } + + /* Caller handles freeing deleted nodes. Don't do it here. */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-aio-posix-fix-concurrent-access-to-poll_disable_cnt.patch b/SOURCES/kvm-aio-posix-fix-concurrent-access-to-poll_disable_cnt.patch new file mode 100644 index 0000000..13cc84a --- /dev/null +++ b/SOURCES/kvm-aio-posix-fix-concurrent-access-to-poll_disable_cnt.patch @@ -0,0 +1,118 @@ +From a9becae1ae86e699ee4a606ff2319799a9fda48c Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Tue, 18 Sep 2018 09:07:12 +0200 +Subject: [PATCH 1/3] aio-posix: fix concurrent access to poll_disable_cnt + +RH-Author: Fam Zheng +Message-id: <20180918090714.18069-2-famz@redhat.com> +Patchwork-id: 82215 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/3] aio-posix: fix concurrent access to poll_disable_cnt +Bugzilla: 1628191 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +From: Paolo Bonzini + +It is valid for an aio_set_fd_handler to happen concurrently with +aio_poll. In that case, poll_disable_cnt can change under the heels +of aio_poll, and the assertion on poll_disable_cnt can fail in +run_poll_handlers. + +Therefore, this patch simply checks the counter on every polling +iteration. There are no particular needs for ordering, since the +polling loop is terminated anyway by aio_notify at the end of +aio_set_fd_handler. + +Signed-off-by: Paolo Bonzini +Message-Id: <20180912171040.1732-2-pbonzini@redhat.com> +Reviewed-by: Fam Zheng +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + util/aio-posix.c | 26 +++++++++++++++----------- + 1 file changed, 15 insertions(+), 11 deletions(-) + +diff --git a/util/aio-posix.c b/util/aio-posix.c +index f05d3a8..1d7cc53 100644 +--- a/util/aio-posix.c ++++ b/util/aio-posix.c +@@ -211,6 +211,7 @@ void aio_set_fd_handler(AioContext *ctx, + AioHandler *node; + bool is_new = false; + bool deleted = false; ++ int poll_disable_change; + + qemu_lockcnt_lock(&ctx->list_lock); + +@@ -244,11 +245,9 @@ void aio_set_fd_handler(AioContext *ctx, + QLIST_REMOVE(node, node); + deleted = true; + } +- +- if (!node->io_poll) { +- ctx->poll_disable_cnt--; +- } ++ poll_disable_change = -!node->io_poll; + } else { ++ poll_disable_change = !io_poll - (node && !node->io_poll); + if (node == NULL) { + /* Alloc and insert if it's not already there */ + node = g_new0(AioHandler, 1); +@@ -257,10 +256,6 @@ void aio_set_fd_handler(AioContext *ctx, + + g_source_add_poll(&ctx->source, &node->pfd); + is_new = true; +- +- ctx->poll_disable_cnt += !io_poll; +- } else { +- ctx->poll_disable_cnt += !io_poll - !node->io_poll; + } + + /* Update handler with latest information */ +@@ -274,6 +269,15 @@ void aio_set_fd_handler(AioContext *ctx, + node->pfd.events |= (io_write ? G_IO_OUT | G_IO_ERR : 0); + } + ++ /* No need to order poll_disable_cnt writes against other updates; ++ * the counter is only used to avoid wasting time and latency on ++ * iterated polling when the system call will be ultimately necessary. ++ * Changing handlers is a rare event, and a little wasted polling until ++ * the aio_notify below is not an issue. ++ */ ++ atomic_set(&ctx->poll_disable_cnt, ++ atomic_read(&ctx->poll_disable_cnt) + poll_disable_change); ++ + aio_epoll_update(ctx, node, is_new); + qemu_lockcnt_unlock(&ctx->list_lock); + aio_notify(ctx); +@@ -525,7 +529,6 @@ static bool run_poll_handlers(AioContext *ctx, int64_t max_ns) + + assert(ctx->notify_me); + assert(qemu_lockcnt_count(&ctx->list_lock) > 0); +- assert(ctx->poll_disable_cnt == 0); + + trace_run_poll_handlers_begin(ctx, max_ns); + +@@ -533,7 +536,8 @@ static bool run_poll_handlers(AioContext *ctx, int64_t max_ns) + + do { + progress = run_poll_handlers_once(ctx); +- } while (!progress && qemu_clock_get_ns(QEMU_CLOCK_REALTIME) < end_time); ++ } while (!progress && qemu_clock_get_ns(QEMU_CLOCK_REALTIME) < end_time ++ && !atomic_read(&ctx->poll_disable_cnt)); + + trace_run_poll_handlers_end(ctx, progress); + +@@ -552,7 +556,7 @@ static bool run_poll_handlers(AioContext *ctx, int64_t max_ns) + */ + static bool try_poll_mode(AioContext *ctx, bool blocking) + { +- if (blocking && ctx->poll_max_ns && ctx->poll_disable_cnt == 0) { ++ if (blocking && ctx->poll_max_ns && !atomic_read(&ctx->poll_disable_cnt)) { + /* See qemu_soonest_timeout() uint64_t hack */ + int64_t max_ns = MIN((uint64_t)aio_compute_timeout(ctx), + (uint64_t)ctx->poll_ns); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-aio-wait-Increase-num_waiters-even-in-home-thread.patch b/SOURCES/kvm-aio-wait-Increase-num_waiters-even-in-home-thread.patch new file mode 100644 index 0000000..6f65743 --- /dev/null +++ b/SOURCES/kvm-aio-wait-Increase-num_waiters-even-in-home-thread.patch @@ -0,0 +1,62 @@ +From efb378ef6983c9f7cc7cdb2cc0540a52b05ff916 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:26 +0200 +Subject: [PATCH 35/49] aio-wait: Increase num_waiters even in home thread + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-29-kwolf@redhat.com> +Patchwork-id: 82179 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 28/42] aio-wait: Increase num_waiters even in home thread +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +Even if AIO_WAIT_WHILE() is called in the home context of the +AioContext, we still want to allow the condition to change depending on +other threads as long as they kick the AioWait. Specfically block jobs +can be running in an I/O thread and should then be able to kick a drain +in the main loop context. + +Signed-off-by: Kevin Wolf +Reviewed-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + include/block/aio-wait.h | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/include/block/aio-wait.h b/include/block/aio-wait.h +index c85a62f..600fad1 100644 +--- a/include/block/aio-wait.h ++++ b/include/block/aio-wait.h +@@ -76,6 +76,8 @@ typedef struct { + bool waited_ = false; \ + AioWait *wait_ = (wait); \ + AioContext *ctx_ = (ctx); \ ++ /* Increment wait_->num_waiters before evaluating cond. */ \ ++ atomic_inc(&wait_->num_waiters); \ + if (ctx_ && in_aio_context_home_thread(ctx_)) { \ + while ((cond)) { \ + aio_poll(ctx_, true); \ +@@ -84,8 +86,6 @@ typedef struct { + } else { \ + assert(qemu_get_current_aio_context() == \ + qemu_get_aio_context()); \ +- /* Increment wait_->num_waiters before evaluating cond. */ \ +- atomic_inc(&wait_->num_waiters); \ + while ((cond)) { \ + if (ctx_) { \ + aio_context_release(ctx_); \ +@@ -96,8 +96,8 @@ typedef struct { + } \ + waited_ = true; \ + } \ +- atomic_dec(&wait_->num_waiters); \ + } \ ++ atomic_dec(&wait_->num_waiters); \ + waited_; }) + + /** +-- +1.8.3.1 + diff --git a/SOURCES/kvm-arm-virt-Add-RHEL-7.5-machine-type.patch b/SOURCES/kvm-arm-virt-Add-RHEL-7.5-machine-type.patch deleted file mode 100644 index e2c7957..0000000 --- a/SOURCES/kvm-arm-virt-Add-RHEL-7.5-machine-type.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 082bd3ba3df66c556def600e0a9b4b451e106290 Mon Sep 17 00:00:00 2001 -From: Wei Huang -Date: Tue, 17 Oct 2017 16:39:11 +0200 -Subject: [PATCH 21/69] arm/virt: Add RHEL 7.5 machine type - -RH-Author: Wei Huang -Message-id: <1508258351-22962-1-git-send-email-wei@redhat.com> -Patchwork-id: 77308 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 1/1] arm/virt: Add RHEL 7.5 machine type -Bugzilla: 1498662 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Laurent Vivier -RH-Acked-by: Andrew Jones - -BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1498662 -Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=14281054 -Brew-ma: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=14280994 -Upstream: No, downstream only - -This patch adds a new machine type, virt-rhel7.5.0, for AArch64. Note -the existing 7.4 machine type, virt-rhel7.4.0, is removed in this patch -because RHEL 7.4 for ARM was as a development preview. So we decided -that it is unnecessary to support the 7.4 machine type. - -After applying this patch, the machine type list ("-M ?") is shown as -the following: - -virt RHEL 7.5.0 ARM Virtual Machine (alias of virt-rhel7.5.0) -virt-rhel7.5.0 RHEL 7.5.0 ARM Virtual Machine (default) -none empty machine - -Signed-off-by: Wei Huang -Signed-off-by: Miroslav Rezanina ---- - hw/arm/virt.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index b14e16d..f243536 100644 ---- a/hw/arm/virt.c -+++ b/hw/arm/virt.c -@@ -1851,7 +1851,7 @@ static void rhel_machine_init(void) - } - type_init(rhel_machine_init); - --static void rhel740_virt_instance_init(Object *obj) -+static void rhel750_virt_instance_init(Object *obj) - { - VirtMachineState *vms = VIRT_MACHINE(obj); - VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); -@@ -1893,8 +1893,8 @@ static void rhel740_virt_instance_init(Object *obj) - vms->irqmap=a15irqmap; - } - --static void rhel740_virt_options(MachineClass *mc) -+static void rhel750_virt_options(MachineClass *mc) - { - SET_MACHINE_COMPAT(mc, ARM_RHEL_COMPAT); - } --DEFINE_RHEL_MACHINE_AS_LATEST(7, 4, 0) -+DEFINE_RHEL_MACHINE_AS_LATEST(7, 5, 0) --- -1.8.3.1 - diff --git a/SOURCES/kvm-atomic-update-documentation.patch b/SOURCES/kvm-atomic-update-documentation.patch deleted file mode 100644 index 8965c30..0000000 --- a/SOURCES/kvm-atomic-update-documentation.patch +++ /dev/null @@ -1,57 +0,0 @@ -From be36671765f098deb41e032b40253967cbd50452 Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Thu, 16 Nov 2017 03:07:12 +0100 -Subject: [PATCH 08/30] atomic: update documentation - -RH-Author: David Gibson -Message-id: <20171116030732.8560-3-dgibson@redhat.com> -Patchwork-id: 77692 -O-Subject: [PATCH 02/22] atomic: update documentation -Bugzilla: 1481593 -RH-Acked-by: Thomas Huth -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Eduardo Habkost -RH-Acked-by: Laurent Vivier - -From: Paolo Bonzini - -Signed-off-by: Paolo Bonzini -(cherry picked from commit db81b9953761cac71906728fb3dfefce661ab903) - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - docs/devel/atomics.txt | 13 ++++++++++++- - 1 file changed, 12 insertions(+), 1 deletion(-) - -diff --git a/docs/devel/atomics.txt b/docs/devel/atomics.txt -index 3ef5d85..048e5f2 100644 ---- a/docs/devel/atomics.txt -+++ b/docs/devel/atomics.txt -@@ -63,11 +63,22 @@ operations: - typeof(*ptr) atomic_fetch_sub(ptr, val) - typeof(*ptr) atomic_fetch_and(ptr, val) - typeof(*ptr) atomic_fetch_or(ptr, val) -+ typeof(*ptr) atomic_fetch_xor(ptr, val) - typeof(*ptr) atomic_xchg(ptr, val) - typeof(*ptr) atomic_cmpxchg(ptr, old, new) - - all of which return the old value of *ptr. These operations are --polymorphic; they operate on any type that is as wide as an int. -+polymorphic; they operate on any type that is as wide as a pointer. -+ -+Similar operations return the new value of *ptr: -+ -+ typeof(*ptr) atomic_inc_fetch(ptr) -+ typeof(*ptr) atomic_dec_fetch(ptr) -+ typeof(*ptr) atomic_add_fetch(ptr, val) -+ typeof(*ptr) atomic_sub_fetch(ptr, val) -+ typeof(*ptr) atomic_and_fetch(ptr, val) -+ typeof(*ptr) atomic_or_fetch(ptr, val) -+ typeof(*ptr) atomic_xor_fetch(ptr, val) - - Sequentially consistent loads and stores can be done using: - --- -1.8.3.1 - diff --git a/SOURCES/kvm-backup-Use-copy-offloading.patch b/SOURCES/kvm-backup-Use-copy-offloading.patch new file mode 100644 index 0000000..857fb6c --- /dev/null +++ b/SOURCES/kvm-backup-Use-copy-offloading.patch @@ -0,0 +1,260 @@ +From 6e2070840430f3009b201976b0a10a9d627adfed Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 18 Jul 2018 22:54:52 +0200 +Subject: [PATCH 67/89] backup: Use copy offloading + +RH-Author: John Snow +Message-id: <20180718225511.14878-17-jsnow@redhat.com> +Patchwork-id: 81399 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 16/35] backup: Use copy offloading +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Fam Zheng + +The implementation is similar to the 'qemu-img convert'. In the +beginning of the job, offloaded copy is attempted. If it fails, further +I/O will go through the existing bounce buffer code path. + +Then, as Kevin pointed out, both this and qemu-img convert can benefit +from a local check if one request fails because of, for example, the +offset is beyond EOF, but another may well be accepted by the protocol +layer. This will be implemented separately. + +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Fam Zheng +Message-id: 20180703023758.14422-4-famz@redhat.com +Signed-off-by: Jeff Cody +(cherry picked from commit 9ded4a0114968e98b41494fc035ba14f84cdf700) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/backup.c | 150 ++++++++++++++++++++++++++++++++++++++--------------- + block/trace-events | 1 + + 2 files changed, 110 insertions(+), 41 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index 5661435..d26eeb5 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -45,6 +45,8 @@ typedef struct BackupBlockJob { + QLIST_HEAD(, CowRequest) inflight_reqs; + + HBitmap *copy_bitmap; ++ bool use_copy_range; ++ int64_t copy_range_size; + } BackupBlockJob; + + static const BlockJobDriver backup_job_driver; +@@ -86,19 +88,101 @@ static void cow_request_end(CowRequest *req) + qemu_co_queue_restart_all(&req->wait_queue); + } + ++/* Copy range to target with a bounce buffer and return the bytes copied. If ++ * error occured, return a negative error number */ ++static int coroutine_fn backup_cow_with_bounce_buffer(BackupBlockJob *job, ++ int64_t start, ++ int64_t end, ++ bool is_write_notifier, ++ bool *error_is_read, ++ void **bounce_buffer) ++{ ++ int ret; ++ struct iovec iov; ++ QEMUIOVector qiov; ++ BlockBackend *blk = job->common.blk; ++ int nbytes; ++ ++ hbitmap_reset(job->copy_bitmap, start / job->cluster_size, 1); ++ nbytes = MIN(job->cluster_size, job->len - start); ++ if (!*bounce_buffer) { ++ *bounce_buffer = blk_blockalign(blk, job->cluster_size); ++ } ++ iov.iov_base = *bounce_buffer; ++ iov.iov_len = nbytes; ++ qemu_iovec_init_external(&qiov, &iov, 1); ++ ++ ret = blk_co_preadv(blk, start, qiov.size, &qiov, ++ is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0); ++ if (ret < 0) { ++ trace_backup_do_cow_read_fail(job, start, ret); ++ if (error_is_read) { ++ *error_is_read = true; ++ } ++ goto fail; ++ } ++ ++ if (qemu_iovec_is_zero(&qiov)) { ++ ret = blk_co_pwrite_zeroes(job->target, start, ++ qiov.size, BDRV_REQ_MAY_UNMAP); ++ } else { ++ ret = blk_co_pwritev(job->target, start, ++ qiov.size, &qiov, ++ job->compress ? BDRV_REQ_WRITE_COMPRESSED : 0); ++ } ++ if (ret < 0) { ++ trace_backup_do_cow_write_fail(job, start, ret); ++ if (error_is_read) { ++ *error_is_read = false; ++ } ++ goto fail; ++ } ++ ++ return nbytes; ++fail: ++ hbitmap_set(job->copy_bitmap, start / job->cluster_size, 1); ++ return ret; ++ ++} ++ ++/* Copy range to target and return the bytes copied. If error occured, return a ++ * negative error number. */ ++static int coroutine_fn backup_cow_with_offload(BackupBlockJob *job, ++ int64_t start, ++ int64_t end, ++ bool is_write_notifier) ++{ ++ int ret; ++ int nr_clusters; ++ BlockBackend *blk = job->common.blk; ++ int nbytes; ++ ++ assert(QEMU_IS_ALIGNED(job->copy_range_size, job->cluster_size)); ++ nbytes = MIN(job->copy_range_size, end - start); ++ nr_clusters = DIV_ROUND_UP(nbytes, job->cluster_size); ++ hbitmap_reset(job->copy_bitmap, start / job->cluster_size, ++ nr_clusters); ++ ret = blk_co_copy_range(blk, start, job->target, start, nbytes, ++ is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0); ++ if (ret < 0) { ++ trace_backup_do_cow_copy_range_fail(job, start, ret); ++ hbitmap_set(job->copy_bitmap, start / job->cluster_size, ++ nr_clusters); ++ return ret; ++ } ++ ++ return nbytes; ++} ++ + static int coroutine_fn backup_do_cow(BackupBlockJob *job, + int64_t offset, uint64_t bytes, + bool *error_is_read, + bool is_write_notifier) + { +- BlockBackend *blk = job->common.blk; + CowRequest cow_request; +- struct iovec iov; +- QEMUIOVector bounce_qiov; +- void *bounce_buffer = NULL; + int ret = 0; + int64_t start, end; /* bytes */ +- int n; /* bytes */ ++ void *bounce_buffer = NULL; + + qemu_co_rwlock_rdlock(&job->flush_rwlock); + +@@ -110,60 +194,38 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job, + wait_for_overlapping_requests(job, start, end); + cow_request_begin(&cow_request, job, start, end); + +- for (; start < end; start += job->cluster_size) { ++ while (start < end) { + if (!hbitmap_get(job->copy_bitmap, start / job->cluster_size)) { + trace_backup_do_cow_skip(job, start); ++ start += job->cluster_size; + continue; /* already copied */ + } +- hbitmap_reset(job->copy_bitmap, start / job->cluster_size, 1); + + trace_backup_do_cow_process(job, start); + +- n = MIN(job->cluster_size, job->len - start); +- +- if (!bounce_buffer) { +- bounce_buffer = blk_blockalign(blk, job->cluster_size); +- } +- iov.iov_base = bounce_buffer; +- iov.iov_len = n; +- qemu_iovec_init_external(&bounce_qiov, &iov, 1); +- +- ret = blk_co_preadv(blk, start, bounce_qiov.size, &bounce_qiov, +- is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0); +- if (ret < 0) { +- trace_backup_do_cow_read_fail(job, start, ret); +- if (error_is_read) { +- *error_is_read = true; ++ if (job->use_copy_range) { ++ ret = backup_cow_with_offload(job, start, end, is_write_notifier); ++ if (ret < 0) { ++ job->use_copy_range = false; + } +- hbitmap_set(job->copy_bitmap, start / job->cluster_size, 1); +- goto out; + } +- +- if (buffer_is_zero(iov.iov_base, iov.iov_len)) { +- ret = blk_co_pwrite_zeroes(job->target, start, +- bounce_qiov.size, BDRV_REQ_MAY_UNMAP); +- } else { +- ret = blk_co_pwritev(job->target, start, +- bounce_qiov.size, &bounce_qiov, +- job->compress ? BDRV_REQ_WRITE_COMPRESSED : 0); ++ if (!job->use_copy_range) { ++ ret = backup_cow_with_bounce_buffer(job, start, end, is_write_notifier, ++ error_is_read, &bounce_buffer); + } + if (ret < 0) { +- trace_backup_do_cow_write_fail(job, start, ret); +- if (error_is_read) { +- *error_is_read = false; +- } +- hbitmap_set(job->copy_bitmap, start / job->cluster_size, 1); +- goto out; ++ break; + } + + /* Publish progress, guest I/O counts as progress too. Note that the + * offset field is an opaque progress value, it is not a disk offset. + */ +- job->bytes_read += n; +- job_progress_update(&job->common.job, n); ++ start += ret; ++ job->bytes_read += ret; ++ job_progress_update(&job->common.job, ret); ++ ret = 0; + } + +-out: + if (bounce_buffer) { + qemu_vfree(bounce_buffer); + } +@@ -665,6 +727,12 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, + } else { + job->cluster_size = MAX(BACKUP_CLUSTER_SIZE_DEFAULT, bdi.cluster_size); + } ++ job->use_copy_range = true; ++ job->copy_range_size = MIN_NON_ZERO(blk_get_max_transfer(job->common.blk), ++ blk_get_max_transfer(job->target)); ++ job->copy_range_size = MAX(job->cluster_size, ++ QEMU_ALIGN_UP(job->copy_range_size, ++ job->cluster_size)); + + /* Required permissions are already taken with target's blk_new() */ + block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL, +diff --git a/block/trace-events b/block/trace-events +index 2d59b53..c35287b 100644 +--- a/block/trace-events ++++ b/block/trace-events +@@ -42,6 +42,7 @@ backup_do_cow_skip(void *job, int64_t start) "job %p start %"PRId64 + backup_do_cow_process(void *job, int64_t start) "job %p start %"PRId64 + backup_do_cow_read_fail(void *job, int64_t start, int ret) "job %p start %"PRId64" ret %d" + backup_do_cow_write_fail(void *job, int64_t start, int ret) "job %p start %"PRId64" ret %d" ++backup_do_cow_copy_range_fail(void *job, int64_t start, int ret) "job %p start %"PRId64" ret %d" + + # blockdev.c + qmp_block_job_cancel(void *job) "job %p" +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Add-BDRV_REQ_WRITE_UNCHANGED-flag.patch b/SOURCES/kvm-block-Add-BDRV_REQ_WRITE_UNCHANGED-flag.patch new file mode 100644 index 0000000..068b6ce --- /dev/null +++ b/SOURCES/kvm-block-Add-BDRV_REQ_WRITE_UNCHANGED-flag.patch @@ -0,0 +1,70 @@ +From c757f534ae34ad858e0d706e0fb893ef5f3aeb28 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 16:12:06 +0200 +Subject: [PATCH 30/54] block: Add BDRV_REQ_WRITE_UNCHANGED flag + +RH-Author: Max Reitz +Message-id: <20180618161212.14444-5-mreitz@redhat.com> +Patchwork-id: 80764 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 04/10] block: Add BDRV_REQ_WRITE_UNCHANGED flag +Bugzilla: 1518738 +RH-Acked-by: John Snow +RH-Acked-by: Kevin Wolf +RH-Acked-by: Miroslav Rezanina + +This flag signifies that a write request will not change the visible +disk content. With this flag set, it is sufficient to have the +BLK_PERM_WRITE_UNCHANGED permission instead of BLK_PERM_WRITE. + +Signed-off-by: Max Reitz +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Alberto Garcia +Message-id: 20180421132929.21610-4-mreitz@redhat.com +Reviewed-by: Kevin Wolf +Signed-off-by: Max Reitz +(cherry picked from commit c6035964f8316b504060618d05b5dd434f18595b) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + block/io.c | 6 +++++- + include/block/block.h | 6 +++++- + 2 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/block/io.c b/block/io.c +index bd9a19a..134b2a4 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -1501,7 +1501,11 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child, + assert(!waited || !req->serialising); + assert(req->overlap_offset <= offset); + assert(offset + bytes <= req->overlap_offset + req->overlap_bytes); +- assert(child->perm & BLK_PERM_WRITE); ++ if (flags & BDRV_REQ_WRITE_UNCHANGED) { ++ assert(child->perm & (BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE)); ++ } else { ++ assert(child->perm & BLK_PERM_WRITE); ++ } + assert(end_sector <= bs->total_sectors || child->perm & BLK_PERM_RESIZE); + + ret = notifier_with_return_list_notify(&bs->before_write_notifiers, req); +diff --git a/include/block/block.h b/include/block/block.h +index 397b5e8..3894edd 100644 +--- a/include/block/block.h ++++ b/include/block/block.h +@@ -54,8 +54,12 @@ typedef enum { + BDRV_REQ_FUA = 0x10, + BDRV_REQ_WRITE_COMPRESSED = 0x20, + ++ /* Signifies that this write request will not change the visible disk ++ * content. */ ++ BDRV_REQ_WRITE_UNCHANGED = 0x40, ++ + /* Mask of valid flags */ +- BDRV_REQ_MASK = 0x3f, ++ BDRV_REQ_MASK = 0x7f, + } BdrvRequestFlags; + + typedef struct BlockSizes { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Add-COR-filter-driver.patch b/SOURCES/kvm-block-Add-COR-filter-driver.patch new file mode 100644 index 0000000..35eccbe --- /dev/null +++ b/SOURCES/kvm-block-Add-COR-filter-driver.patch @@ -0,0 +1,260 @@ +From b6f5671191f1ce4d7ee2fe5d794c93b316cc0a1a Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 16:12:04 +0200 +Subject: [PATCH 28/54] block: Add COR filter driver + +RH-Author: Max Reitz +Message-id: <20180618161212.14444-3-mreitz@redhat.com> +Patchwork-id: 80762 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 02/10] block: Add COR filter driver +Bugzilla: 1518738 +RH-Acked-by: John Snow +RH-Acked-by: Kevin Wolf +RH-Acked-by: Miroslav Rezanina + +This adds a simple copy-on-read filter driver. It relies on the already +existing COR functionality in the central block layer code, which may be +moved here once we no longer need it there. + +Signed-off-by: Max Reitz +Message-id: 20180421132929.21610-2-mreitz@redhat.com +Reviewed-by: Alberto Garcia +Reviewed-by: Kevin Wolf +Signed-off-by: Max Reitz +(cherry picked from commit 6c6f24fd84895d03baa898bbc4324dd4ccc97071) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + block/Makefile.objs | 2 +- + block/copy-on-read.c | 171 +++++++++++++++++++++++++++++++++++++++++++++++++++ + qapi/block-core.json | 5 +- + 3 files changed, 176 insertions(+), 2 deletions(-) + create mode 100644 block/copy-on-read.c + +diff --git a/block/Makefile.objs b/block/Makefile.objs +index c0693fc..be2cda1 100644 +--- a/block/Makefile.objs ++++ b/block/Makefile.objs +@@ -26,7 +26,7 @@ block-obj-y += accounting.o dirty-bitmap.o + block-obj-y += write-threshold.o + block-obj-y += backup.o + block-obj-$(CONFIG_REPLICATION) += replication.o +-block-obj-y += throttle.o ++block-obj-y += throttle.o copy-on-read.o + + block-obj-y += crypto.o + +diff --git a/block/copy-on-read.c b/block/copy-on-read.c +new file mode 100644 +index 0000000..823ec75 +--- /dev/null ++++ b/block/copy-on-read.c +@@ -0,0 +1,171 @@ ++/* ++ * Copy-on-read filter block driver ++ * ++ * Copyright (c) 2018 Red Hat, Inc. ++ * ++ * Author: ++ * 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) version 3 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 . ++ */ ++ ++#include "qemu/osdep.h" ++#include "block/block_int.h" ++ ++ ++static int cor_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; ++ } ++ ++ bs->supported_write_flags = BDRV_REQ_FUA & ++ bs->file->bs->supported_write_flags; ++ ++ bs->supported_zero_flags = (BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) & ++ bs->file->bs->supported_zero_flags; ++ ++ return 0; ++} ++ ++ ++static void cor_close(BlockDriverState *bs) ++{ ++} ++ ++ ++#define PERM_PASSTHROUGH (BLK_PERM_CONSISTENT_READ \ ++ | BLK_PERM_WRITE \ ++ | BLK_PERM_RESIZE) ++#define PERM_UNCHANGED (BLK_PERM_ALL & ~PERM_PASSTHROUGH) ++ ++static void cor_child_perm(BlockDriverState *bs, BdrvChild *c, ++ const BdrvChildRole *role, ++ BlockReopenQueue *reopen_queue, ++ uint64_t perm, uint64_t shared, ++ uint64_t *nperm, uint64_t *nshared) ++{ ++ if (c == NULL) { ++ *nperm = (perm & PERM_PASSTHROUGH) | BLK_PERM_WRITE_UNCHANGED; ++ *nshared = (shared & PERM_PASSTHROUGH) | PERM_UNCHANGED; ++ return; ++ } ++ ++ *nperm = (perm & PERM_PASSTHROUGH) | ++ (c->perm & PERM_UNCHANGED); ++ *nshared = (shared & PERM_PASSTHROUGH) | ++ (c->shared_perm & PERM_UNCHANGED); ++} ++ ++ ++static int64_t cor_getlength(BlockDriverState *bs) ++{ ++ return bdrv_getlength(bs->file->bs); ++} ++ ++ ++static int cor_truncate(BlockDriverState *bs, int64_t offset, ++ PreallocMode prealloc, Error **errp) ++{ ++ return bdrv_truncate(bs->file, offset, prealloc, errp); ++} ++ ++ ++static int coroutine_fn cor_co_preadv(BlockDriverState *bs, ++ uint64_t offset, uint64_t bytes, ++ QEMUIOVector *qiov, int flags) ++{ ++ return bdrv_co_preadv(bs->file, offset, bytes, qiov, ++ flags | BDRV_REQ_COPY_ON_READ); ++} ++ ++ ++static int coroutine_fn cor_co_pwritev(BlockDriverState *bs, ++ uint64_t offset, uint64_t bytes, ++ QEMUIOVector *qiov, int flags) ++{ ++ ++ return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags); ++} ++ ++ ++static int coroutine_fn cor_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 cor_co_pdiscard(BlockDriverState *bs, ++ int64_t offset, int bytes) ++{ ++ return bdrv_co_pdiscard(bs->file->bs, offset, bytes); ++} ++ ++ ++static void cor_eject(BlockDriverState *bs, bool eject_flag) ++{ ++ bdrv_eject(bs->file->bs, eject_flag); ++} ++ ++ ++static void cor_lock_medium(BlockDriverState *bs, bool locked) ++{ ++ bdrv_lock_medium(bs->file->bs, locked); ++} ++ ++ ++static bool cor_recurse_is_first_non_filter(BlockDriverState *bs, ++ BlockDriverState *candidate) ++{ ++ return bdrv_recurse_is_first_non_filter(bs->file->bs, candidate); ++} ++ ++ ++BlockDriver bdrv_copy_on_read = { ++ .format_name = "copy-on-read", ++ ++ .bdrv_open = cor_open, ++ .bdrv_close = cor_close, ++ .bdrv_child_perm = cor_child_perm, ++ ++ .bdrv_getlength = cor_getlength, ++ .bdrv_truncate = cor_truncate, ++ ++ .bdrv_co_preadv = cor_co_preadv, ++ .bdrv_co_pwritev = cor_co_pwritev, ++ .bdrv_co_pwrite_zeroes = cor_co_pwrite_zeroes, ++ .bdrv_co_pdiscard = cor_co_pdiscard, ++ ++ .bdrv_eject = cor_eject, ++ .bdrv_lock_medium = cor_lock_medium, ++ ++ .bdrv_co_block_status = bdrv_co_block_status_from_file, ++ ++ .bdrv_recurse_is_first_non_filter = cor_recurse_is_first_non_filter, ++ ++ .has_variable_length = true, ++ .is_filter = true, ++}; ++ ++static void bdrv_copy_on_read_init(void) ++{ ++ bdrv_register(&bdrv_copy_on_read); ++} ++ ++block_init(bdrv_copy_on_read_init); +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 46469be..5aac0c7 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -2506,11 +2506,12 @@ + # @vxhs: Since 2.10 + # @throttle: Since 2.11 + # @nvme: Since 2.12 ++# @copy-on-read: Since 2.13 + # + # Since: 2.9 + ## + { 'enum': 'BlockdevDriver', +- 'data': [ 'blkdebug', 'blkverify', 'bochs', 'cloop', ++ 'data': [ 'blkdebug', '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', +@@ -3541,6 +3542,7 @@ + 'blkverify': 'BlockdevOptionsBlkverify', + 'bochs': 'BlockdevOptionsGenericFormat', + 'cloop': 'BlockdevOptionsGenericFormat', ++ 'copy-on-read':'BlockdevOptionsGenericFormat', + 'dmg': 'BlockdevOptionsGenericFormat', + 'file': 'BlockdevOptionsFile', + 'ftp': 'BlockdevOptionsCurlFtp', +@@ -4068,6 +4070,7 @@ + 'blkverify': 'BlockdevCreateNotSupported', + 'bochs': 'BlockdevCreateNotSupported', + 'cloop': 'BlockdevCreateNotSupported', ++ 'copy-on-read': 'BlockdevCreateNotSupported', + 'dmg': 'BlockdevCreateNotSupported', + 'file': 'BlockdevCreateOptionsFile', + 'ftp': 'BlockdevCreateNotSupported', +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Add-Error-parameter-to-bdrv_amend_options.patch b/SOURCES/kvm-block-Add-Error-parameter-to-bdrv_amend_options.patch new file mode 100644 index 0000000..97badc2 --- /dev/null +++ b/SOURCES/kvm-block-Add-Error-parameter-to-bdrv_amend_options.patch @@ -0,0 +1,465 @@ +From e01a2ccba2a784caad5192f8d1e4b37ae1d65bed Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 14:59:38 +0200 +Subject: [PATCH 04/89] block: Add Error parameter to bdrv_amend_options + +RH-Author: Max Reitz +Message-id: <20180618145943.4489-3-mreitz@redhat.com> +Patchwork-id: 80755 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 2/7] block: Add Error parameter to bdrv_amend_options +Bugzilla: 1537956 +RH-Acked-by: John Snow +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi + +Looking at the qcow2 code that is riddled with error_report() calls, +this is really how it should have been from the start. + +Along the way, turn the target_version/current_version comparisons at +the beginning of qcow2_downgrade() into assertions (the caller has to +make sure these conditions are met), and rephrase the error message on +using compat=1.1 to get refcount widths other than 16 bits. + +Signed-off-by: Max Reitz +Message-id: 20180509210023.20283-3-mreitz@redhat.com +Reviewed-by: Eric Blake +Reviewed-by: John Snow +Signed-off-by: Max Reitz +(cherry picked from commit d1402b502691142b9cebadd5cb993dc8858e9071) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + block.c | 8 ++++-- + block/qcow2.c | 72 ++++++++++++++++++++++++++-------------------- + include/block/block.h | 3 +- + include/block/block_int.h | 3 +- + qemu-img.c | 4 +-- + tests/qemu-iotests/060.out | 4 +-- + tests/qemu-iotests/061.out | 7 ----- + tests/qemu-iotests/080.out | 4 +-- + tests/qemu-iotests/112.out | 5 +--- + 9 files changed, 58 insertions(+), 52 deletions(-) + +diff --git a/block.c b/block.c +index 982d54e..d991a09 100644 +--- a/block.c ++++ b/block.c +@@ -5008,15 +5008,19 @@ void bdrv_remove_aio_context_notifier(BlockDriverState *bs, + } + + int bdrv_amend_options(BlockDriverState *bs, QemuOpts *opts, +- BlockDriverAmendStatusCB *status_cb, void *cb_opaque) ++ BlockDriverAmendStatusCB *status_cb, void *cb_opaque, ++ Error **errp) + { + if (!bs->drv) { ++ error_setg(errp, "Node is ejected"); + return -ENOMEDIUM; + } + if (!bs->drv->bdrv_amend_options) { ++ error_setg(errp, "Block driver '%s' does not support option amendment", ++ bs->drv->format_name); + return -ENOTSUP; + } +- return bs->drv->bdrv_amend_options(bs, opts, status_cb, cb_opaque); ++ return bs->drv->bdrv_amend_options(bs, opts, status_cb, cb_opaque, errp); + } + + /* This function will be called by the bdrv_recurse_is_first_non_filter method +diff --git a/block/qcow2.c b/block/qcow2.c +index 26a6a7f..092db81 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -4039,22 +4039,21 @@ static int qcow2_load_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, + * have to be removed. + */ + static int qcow2_downgrade(BlockDriverState *bs, int target_version, +- BlockDriverAmendStatusCB *status_cb, void *cb_opaque) ++ BlockDriverAmendStatusCB *status_cb, void *cb_opaque, ++ Error **errp) + { + BDRVQcow2State *s = bs->opaque; + int current_version = s->qcow_version; + int ret; + +- if (target_version == current_version) { +- return 0; +- } else if (target_version > current_version) { +- return -EINVAL; +- } else if (target_version != 2) { +- return -EINVAL; +- } ++ /* This is qcow2_downgrade(), not qcow2_upgrade() */ ++ assert(target_version < current_version); ++ ++ /* There are no other versions (now) that you can downgrade to */ ++ assert(target_version == 2); + + if (s->refcount_order != 4) { +- error_report("compat=0.10 requires refcount_bits=16"); ++ error_setg(errp, "compat=0.10 requires refcount_bits=16"); + return -ENOTSUP; + } + +@@ -4062,6 +4061,7 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version, + if (s->incompatible_features & QCOW2_INCOMPAT_DIRTY) { + ret = qcow2_mark_clean(bs); + if (ret < 0) { ++ error_setg_errno(errp, -ret, "Failed to make the image clean"); + return ret; + } + } +@@ -4071,6 +4071,8 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version, + * best thing to do anyway */ + + if (s->incompatible_features) { ++ error_setg(errp, "Cannot downgrade an image with incompatible features " ++ "%#" PRIx64 " set", s->incompatible_features); + return -ENOTSUP; + } + +@@ -4084,6 +4086,7 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version, + + ret = qcow2_expand_zero_clusters(bs, status_cb, cb_opaque); + if (ret < 0) { ++ error_setg_errno(errp, -ret, "Failed to turn zero into data clusters"); + return ret; + } + +@@ -4091,6 +4094,7 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version, + ret = qcow2_update_header(bs); + if (ret < 0) { + s->qcow_version = current_version; ++ error_setg_errno(errp, -ret, "Failed to update the image header"); + return ret; + } + return 0; +@@ -4168,7 +4172,8 @@ static void qcow2_amend_helper_cb(BlockDriverState *bs, + + static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, + BlockDriverAmendStatusCB *status_cb, +- void *cb_opaque) ++ void *cb_opaque, ++ Error **errp) + { + BDRVQcow2State *s = bs->opaque; + int old_version = s->qcow_version, new_version = old_version; +@@ -4180,7 +4185,6 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, + bool encrypt; + int encformat; + int refcount_bits = s->refcount_bits; +- Error *local_err = NULL; + int ret; + QemuOptDesc *desc = opts->list->desc; + Qcow2AmendHelperCBInfo helper_cb_info; +@@ -4201,11 +4205,11 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, + } else if (!strcmp(compat, "1.1")) { + new_version = 3; + } else { +- error_report("Unknown compatibility level %s", compat); ++ error_setg(errp, "Unknown compatibility level %s", compat); + return -EINVAL; + } + } else if (!strcmp(desc->name, BLOCK_OPT_PREALLOC)) { +- error_report("Cannot change preallocation mode"); ++ error_setg(errp, "Cannot change preallocation mode"); + return -ENOTSUP; + } else if (!strcmp(desc->name, BLOCK_OPT_SIZE)) { + new_size = qemu_opt_get_size(opts, BLOCK_OPT_SIZE, 0); +@@ -4218,7 +4222,8 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, + !!s->crypto); + + if (encrypt != !!s->crypto) { +- error_report("Changing the encryption flag is not supported"); ++ error_setg(errp, ++ "Changing the encryption flag is not supported"); + return -ENOTSUP; + } + } else if (!strcmp(desc->name, BLOCK_OPT_ENCRYPT_FORMAT)) { +@@ -4226,17 +4231,19 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, + qemu_opt_get(opts, BLOCK_OPT_ENCRYPT_FORMAT)); + + if (encformat != s->crypt_method_header) { +- error_report("Changing the encryption format is not supported"); ++ error_setg(errp, ++ "Changing the encryption format is not supported"); + return -ENOTSUP; + } + } else if (g_str_has_prefix(desc->name, "encrypt.")) { +- error_report("Changing the encryption parameters is not supported"); ++ error_setg(errp, ++ "Changing the encryption parameters is not supported"); + return -ENOTSUP; + } else if (!strcmp(desc->name, BLOCK_OPT_CLUSTER_SIZE)) { + cluster_size = qemu_opt_get_size(opts, BLOCK_OPT_CLUSTER_SIZE, + cluster_size); + if (cluster_size != s->cluster_size) { +- error_report("Changing the cluster size is not supported"); ++ error_setg(errp, "Changing the cluster size is not supported"); + return -ENOTSUP; + } + } else if (!strcmp(desc->name, BLOCK_OPT_LAZY_REFCOUNTS)) { +@@ -4249,8 +4256,8 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, + if (refcount_bits <= 0 || refcount_bits > 64 || + !is_power_of_2(refcount_bits)) + { +- error_report("Refcount width must be a power of two and may " +- "not exceed 64 bits"); ++ error_setg(errp, "Refcount width must be a power of two and " ++ "may not exceed 64 bits"); + return -EINVAL; + } + } else { +@@ -4275,6 +4282,7 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, + ret = qcow2_update_header(bs); + if (ret < 0) { + s->qcow_version = old_version; ++ error_setg_errno(errp, -ret, "Failed to update the image header"); + return ret; + } + } +@@ -4283,18 +4291,17 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, + int refcount_order = ctz32(refcount_bits); + + if (new_version < 3 && refcount_bits != 16) { +- error_report("Different refcount widths than 16 bits require " +- "compatibility level 1.1 or above (use compat=1.1 or " +- "greater)"); ++ error_setg(errp, "Refcount widths other than 16 bits require " ++ "compatibility level 1.1 or above (use compat=1.1 or " ++ "greater)"); + return -EINVAL; + } + + helper_cb_info.current_operation = QCOW2_CHANGING_REFCOUNT_ORDER; + ret = qcow2_change_refcount_order(bs, refcount_order, + &qcow2_amend_helper_cb, +- &helper_cb_info, &local_err); ++ &helper_cb_info, errp); + if (ret < 0) { +- error_report_err(local_err); + return ret; + } + } +@@ -4304,6 +4311,7 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, + backing_file ?: s->image_backing_file, + backing_format ?: s->image_backing_format); + if (ret < 0) { ++ error_setg_errno(errp, -ret, "Failed to change the backing file"); + return ret; + } + } +@@ -4311,14 +4319,16 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, + if (s->use_lazy_refcounts != lazy_refcounts) { + if (lazy_refcounts) { + if (new_version < 3) { +- error_report("Lazy refcounts only supported with compatibility " +- "level 1.1 and above (use compat=1.1 or greater)"); ++ error_setg(errp, "Lazy refcounts only supported with " ++ "compatibility level 1.1 and above (use compat=1.1 " ++ "or greater)"); + return -EINVAL; + } + s->compatible_features |= QCOW2_COMPAT_LAZY_REFCOUNTS; + ret = qcow2_update_header(bs); + if (ret < 0) { + s->compatible_features &= ~QCOW2_COMPAT_LAZY_REFCOUNTS; ++ error_setg_errno(errp, -ret, "Failed to update the image header"); + return ret; + } + s->use_lazy_refcounts = true; +@@ -4326,6 +4336,7 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, + /* make image clean first */ + ret = qcow2_mark_clean(bs); + if (ret < 0) { ++ error_setg_errno(errp, -ret, "Failed to make the image clean"); + return ret; + } + /* now disallow lazy refcounts */ +@@ -4333,6 +4344,7 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, + ret = qcow2_update_header(bs); + if (ret < 0) { + s->compatible_features |= QCOW2_COMPAT_LAZY_REFCOUNTS; ++ error_setg_errno(errp, -ret, "Failed to update the image header"); + return ret; + } + s->use_lazy_refcounts = false; +@@ -4341,17 +4353,15 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, + + if (new_size) { + BlockBackend *blk = blk_new(BLK_PERM_RESIZE, BLK_PERM_ALL); +- ret = blk_insert_bs(blk, bs, &local_err); ++ ret = blk_insert_bs(blk, bs, errp); + if (ret < 0) { +- error_report_err(local_err); + blk_unref(blk); + return ret; + } + +- ret = blk_truncate(blk, new_size, PREALLOC_MODE_OFF, &local_err); ++ ret = blk_truncate(blk, new_size, PREALLOC_MODE_OFF, errp); + blk_unref(blk); + if (ret < 0) { +- error_report_err(local_err); + return ret; + } + } +@@ -4360,7 +4370,7 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, + if (new_version < old_version) { + helper_cb_info.current_operation = QCOW2_DOWNGRADING; + ret = qcow2_downgrade(bs, new_version, &qcow2_amend_helper_cb, +- &helper_cb_info); ++ &helper_cb_info, errp); + if (ret < 0) { + return ret; + } +diff --git a/include/block/block.h b/include/block/block.h +index 06cd772..2d17b09 100644 +--- a/include/block/block.h ++++ b/include/block/block.h +@@ -343,7 +343,8 @@ int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix); + typedef void BlockDriverAmendStatusCB(BlockDriverState *bs, int64_t offset, + int64_t total_work_size, void *opaque); + int bdrv_amend_options(BlockDriverState *bs_new, QemuOpts *opts, +- BlockDriverAmendStatusCB *status_cb, void *cb_opaque); ++ BlockDriverAmendStatusCB *status_cb, void *cb_opaque, ++ Error **errp); + + /* external snapshots */ + bool bdrv_recurse_is_first_non_filter(BlockDriverState *bs, +diff --git a/include/block/block_int.h b/include/block/block_int.h +index c4dd1d4..d913ed1 100644 +--- a/include/block/block_int.h ++++ b/include/block/block_int.h +@@ -324,7 +324,8 @@ struct BlockDriver { + + int (*bdrv_amend_options)(BlockDriverState *bs, QemuOpts *opts, + BlockDriverAmendStatusCB *status_cb, +- void *cb_opaque); ++ void *cb_opaque, ++ Error **errp); + + void (*bdrv_debug_event)(BlockDriverState *bs, BlkdebugEvent event); + +diff --git a/qemu-img.c b/qemu-img.c +index 2f7c491..e40d6ff 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -3761,10 +3761,10 @@ static int img_amend(int argc, char **argv) + + /* In case the driver does not call amend_status_cb() */ + qemu_progress_print(0.f, 0); +- ret = bdrv_amend_options(bs, opts, &amend_status_cb, NULL); ++ ret = bdrv_amend_options(bs, opts, &amend_status_cb, NULL, &err); + qemu_progress_print(100.f, 0); + if (ret < 0) { +- error_report("Error while amending options: %s", strerror(-ret)); ++ error_report_err(err); + goto out; + } + +diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out +index 99234fb..bff023d 100644 +--- a/tests/qemu-iotests/060.out ++++ b/tests/qemu-iotests/060.out +@@ -129,7 +129,7 @@ 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) + qcow2: Marking image as corrupt: L2 table offset 0x42a00 unaligned (L1 index: 0); further corruption events will be suppressed +-qemu-img: Error while amending options: Input/output error ++qemu-img: Failed to turn zero into data clusters: Input/output error + + === Testing unaligned L2 entry === + +@@ -145,7 +145,7 @@ 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) + qcow2: Marking image as corrupt: Cluster allocation offset 0x52a00 unaligned (L2 offset: 0x40000, L2 index: 0); further corruption events will be suppressed +-qemu-img: Error while amending options: Input/output error ++qemu-img: Failed to turn zero into data clusters: Input/output error + + === Testing unaligned reftable entry === + +diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out +index e857ef9..183f7dd 100644 +--- a/tests/qemu-iotests/061.out ++++ b/tests/qemu-iotests/061.out +@@ -358,18 +358,12 @@ No errors were found on the image. + + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 + qemu-img: Lazy refcounts only supported with compatibility level 1.1 and above (use compat=1.1 or greater) +-qemu-img: Error while amending options: Invalid argument + qemu-img: Lazy refcounts only supported with compatibility level 1.1 and above (use compat=1.1 or greater) +-qemu-img: Error while amending options: Invalid argument + qemu-img: Unknown compatibility level 0.42 +-qemu-img: Error while amending options: Invalid argument + qemu-img: Invalid parameter 'foo' + qemu-img: Changing the cluster size is not supported +-qemu-img: Error while amending options: Operation not supported + qemu-img: Changing the encryption flag is not supported +-qemu-img: Error while amending options: Operation not supported + qemu-img: Cannot change preallocation mode +-qemu-img: Error while amending options: Operation not supported + + === Testing correct handling of unset value === + +@@ -377,7 +371,6 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 + Should work: + Should not work: + qemu-img: Changing the cluster size is not supported +-qemu-img: Error while amending options: Operation not supported + + === Testing zero expansion on inactive clusters === + +diff --git a/tests/qemu-iotests/080.out b/tests/qemu-iotests/080.out +index 4e0f7f7..281c7e0 100644 +--- a/tests/qemu-iotests/080.out ++++ b/tests/qemu-iotests/080.out +@@ -65,7 +65,7 @@ wrote 512/512 bytes at offset 0 + 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + qemu-img: Failed to load snapshot: Snapshot L1 table offset invalid + qemu-img: Snapshot L1 table offset invalid +-qemu-img: Error while amending options: Invalid argument ++qemu-img: Failed to turn zero into data clusters: Invalid argument + Failed to flush the refcount block cache: Invalid argument + write failed: Invalid argument + qemu-img: Snapshot L1 table offset invalid +@@ -88,7 +88,7 @@ wrote 512/512 bytes at offset 0 + 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + qemu-img: Failed to load snapshot: Snapshot L1 table too large + qemu-img: Snapshot L1 table too large +-qemu-img: Error while amending options: File too large ++qemu-img: Failed to turn zero into data clusters: File too large + Failed to flush the refcount block cache: File too large + write failed: File too large + qemu-img: Snapshot L1 table too large +diff --git a/tests/qemu-iotests/112.out b/tests/qemu-iotests/112.out +index 86f0410..ae0318c 100644 +--- a/tests/qemu-iotests/112.out ++++ b/tests/qemu-iotests/112.out +@@ -99,13 +99,11 @@ refcount bits: 64 + === Amend to compat=0.10 === + + qemu-img: compat=0.10 requires refcount_bits=16 +-qemu-img: Error while amending options: Operation not supported + refcount bits: 64 + No errors were found on the image. + refcount bits: 16 + refcount bits: 16 +-qemu-img: Different refcount widths than 16 bits require compatibility level 1.1 or above (use compat=1.1 or greater) +-qemu-img: Error while amending options: Invalid argument ++qemu-img: Refcount widths other than 16 bits require compatibility level 1.1 or above (use compat=1.1 or greater) + refcount bits: 16 + + === Amend with snapshot === +@@ -113,7 +111,6 @@ refcount bits: 16 + wrote 16777216/16777216 bytes at offset 0 + 16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + qemu-img: Cannot decrease refcount entry width to 1 bits: Cluster at offset 0x50000 has a refcount of 2 +-qemu-img: Error while amending options: Invalid argument + No errors were found on the image. + refcount bits: 16 + No errors were found on the image. +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Add-block-specific-QDict-header.patch b/SOURCES/kvm-block-Add-block-specific-QDict-header.patch new file mode 100644 index 0000000..146ef7c --- /dev/null +++ b/SOURCES/kvm-block-Add-block-specific-QDict-header.patch @@ -0,0 +1,423 @@ +From 29e09fe238bfbf9657384e8a05087398925626ac Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Mon, 18 Jun 2018 08:43:15 +0200 +Subject: [PATCH 08/54] block: Add block-specific QDict header + +RH-Author: Markus Armbruster +Message-id: <20180618084330.30009-9-armbru@redhat.com> +Patchwork-id: 80736 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 08/23] block: Add block-specific QDict header +Bugzilla: 1557995 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +From: Max Reitz + +There are numerous QDict functions that have been introduced for and are +used only by the block layer. Move their declarations into an own +header file to reflect that. + +While qdict_extract_subqdict() is in fact used outside of the block +layer (in util/qemu-config.c), it is still a function related very +closely to how the block layer works with nested QDicts, namely by +sometimes flattening them. Therefore, its declaration is put into this +header as well and util/qemu-config.c includes it with a comment stating +exactly which function it needs. + +Suggested-by: Markus Armbruster +Signed-off-by: Max Reitz +Message-Id: <20180509165530.29561-7-mreitz@redhat.com> +[Copyright note tweaked, superfluous includes dropped] +Signed-off-by: Markus Armbruster +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit 609f45ea9507fc1603eaeda7f5066b99beac6721) +[Trivial conflict in block/nbd.c resolved] + +Signed-off-by: Miroslav Rezanina +--- + block.c | 1 + + block/gluster.c | 1 + + block/iscsi.c | 1 + + block/nbd.c | 1 + + block/nfs.c | 1 + + block/parallels.c | 1 + + block/qcow.c | 1 + + block/qcow2.c | 1 + + block/qed.c | 1 + + block/quorum.c | 1 + + block/rbd.c | 1 + + block/sheepdog.c | 1 + + block/snapshot.c | 1 + + block/ssh.c | 1 + + block/vhdx.c | 1 + + block/vpc.c | 1 + + block/vvfat.c | 1 + + block/vxhs.c | 1 + + blockdev.c | 1 + + include/block/qdict.h | 32 ++++++++++++++++++++++++++++++++ + include/qapi/qmp/qdict.h | 17 ----------------- + qobject/qdict.c | 1 + + tests/check-qdict.c | 1 + + tests/check-qobject.c | 1 + + tests/test-replication.c | 1 + + util/qemu-config.c | 1 + + 26 files changed, 56 insertions(+), 17 deletions(-) + create mode 100644 include/block/qdict.h + +diff --git a/block.c b/block.c +index 676e57f..3c3e8fd 100644 +--- a/block.c ++++ b/block.c +@@ -27,6 +27,7 @@ + #include "block/block_int.h" + #include "block/blockjob.h" + #include "block/nbd.h" ++#include "block/qdict.h" + #include "qemu/error-report.h" + #include "module_block.h" + #include "qemu/module.h" +diff --git a/block/gluster.c b/block/gluster.c +index 55be566..418bb73 100644 +--- a/block/gluster.c ++++ b/block/gluster.c +@@ -11,6 +11,7 @@ + #include "qemu/osdep.h" + #include + #include "block/block_int.h" ++#include "block/qdict.h" + #include "qapi/error.h" + #include "qapi/qmp/qdict.h" + #include "qapi/qmp/qerror.h" +diff --git a/block/iscsi.c b/block/iscsi.c +index 658462b..1705187 100644 +--- a/block/iscsi.c ++++ b/block/iscsi.c +@@ -33,6 +33,7 @@ + #include "qemu/bitops.h" + #include "qemu/bitmap.h" + #include "block/block_int.h" ++#include "block/qdict.h" + #include "scsi/constants.h" + #include "qemu/iov.h" + #include "qemu/option.h" +diff --git a/block/nbd.c b/block/nbd.c +index 3e1693c..f499830 100644 +--- a/block/nbd.c ++++ b/block/nbd.c +@@ -28,6 +28,7 @@ + + #include "qemu/osdep.h" + #include "block/nbd-client.h" ++#include "block/qdict.h" + #include "qapi/error.h" + #include "qemu/uri.h" + #include "block/block_int.h" +diff --git a/block/nfs.c b/block/nfs.c +index 66fddf1..5159ef0 100644 +--- a/block/nfs.c ++++ b/block/nfs.c +@@ -29,6 +29,7 @@ + #include "qemu/error-report.h" + #include "qapi/error.h" + #include "block/block_int.h" ++#include "block/qdict.h" + #include "trace.h" + #include "qemu/iov.h" + #include "qemu/option.h" +diff --git a/block/parallels.c b/block/parallels.c +index 045810d..0ee1f6a 100644 +--- a/block/parallels.c ++++ b/block/parallels.c +@@ -31,6 +31,7 @@ + #include "qemu/osdep.h" + #include "qapi/error.h" + #include "block/block_int.h" ++#include "block/qdict.h" + #include "sysemu/block-backend.h" + #include "qemu/module.h" + #include "qemu/option.h" +diff --git a/block/qcow.c b/block/qcow.c +index 4b2f7db..fb821ad 100644 +--- a/block/qcow.c ++++ b/block/qcow.c +@@ -26,6 +26,7 @@ + #include "qapi/error.h" + #include "qemu/error-report.h" + #include "block/block_int.h" ++#include "block/qdict.h" + #include "sysemu/block-backend.h" + #include "qemu/module.h" + #include "qemu/option.h" +diff --git a/block/qcow2.c b/block/qcow2.c +index 2f36e63..fa9f557 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -24,6 +24,7 @@ + + #include "qemu/osdep.h" + #include "block/block_int.h" ++#include "block/qdict.h" + #include "sysemu/block-backend.h" + #include "qemu/module.h" + #include +diff --git a/block/qed.c b/block/qed.c +index 1db8eaf..9a8997a 100644 +--- a/block/qed.c ++++ b/block/qed.c +@@ -13,6 +13,7 @@ + */ + + #include "qemu/osdep.h" ++#include "block/qdict.h" + #include "qapi/error.h" + #include "qemu/timer.h" + #include "qemu/bswap.h" +diff --git a/block/quorum.c b/block/quorum.c +index a5051da..f1f39ba 100644 +--- a/block/quorum.c ++++ b/block/quorum.c +@@ -17,6 +17,7 @@ + #include "qemu/cutils.h" + #include "qemu/option.h" + #include "block/block_int.h" ++#include "block/qdict.h" + #include "qapi/error.h" + #include "qapi/qapi-events-block.h" + #include "qapi/qmp/qdict.h" +diff --git a/block/rbd.c b/block/rbd.c +index 2842c0e..e695cf2 100644 +--- a/block/rbd.c ++++ b/block/rbd.c +@@ -18,6 +18,7 @@ + #include "qemu/error-report.h" + #include "qemu/option.h" + #include "block/block_int.h" ++#include "block/qdict.h" + #include "crypto/secret.h" + #include "qemu/cutils.h" + #include "qapi/qmp/qstring.h" +diff --git a/block/sheepdog.c b/block/sheepdog.c +index 07529f4..fd3876f 100644 +--- a/block/sheepdog.c ++++ b/block/sheepdog.c +@@ -24,6 +24,7 @@ + #include "qemu/option.h" + #include "qemu/sockets.h" + #include "block/block_int.h" ++#include "block/qdict.h" + #include "sysemu/block-backend.h" + #include "qemu/bitops.h" + #include "qemu/cutils.h" +diff --git a/block/snapshot.c b/block/snapshot.c +index 2953d96..f9903bc 100644 +--- a/block/snapshot.c ++++ b/block/snapshot.c +@@ -25,6 +25,7 @@ + #include "qemu/osdep.h" + #include "block/snapshot.h" + #include "block/block_int.h" ++#include "block/qdict.h" + #include "qapi/error.h" + #include "qapi/qmp/qdict.h" + #include "qapi/qmp/qerror.h" +diff --git a/block/ssh.c b/block/ssh.c +index 412a1bf..5931064 100644 +--- a/block/ssh.c ++++ b/block/ssh.c +@@ -28,6 +28,7 @@ + #include + + #include "block/block_int.h" ++#include "block/qdict.h" + #include "qapi/error.h" + #include "qemu/error-report.h" + #include "qemu/option.h" +diff --git a/block/vhdx.c b/block/vhdx.c +index c3a4220..26c05aa 100644 +--- a/block/vhdx.c ++++ b/block/vhdx.c +@@ -18,6 +18,7 @@ + #include "qemu/osdep.h" + #include "qapi/error.h" + #include "block/block_int.h" ++#include "block/qdict.h" + #include "sysemu/block-backend.h" + #include "qemu/module.h" + #include "qemu/option.h" +diff --git a/block/vpc.c b/block/vpc.c +index 0ebfcd3..41c8c98 100644 +--- a/block/vpc.c ++++ b/block/vpc.c +@@ -26,6 +26,7 @@ + #include "qemu/osdep.h" + #include "qapi/error.h" + #include "block/block_int.h" ++#include "block/qdict.h" + #include "sysemu/block-backend.h" + #include "qemu/module.h" + #include "qemu/option.h" +diff --git a/block/vvfat.c b/block/vvfat.c +index 662dca0..4595f33 100644 +--- a/block/vvfat.c ++++ b/block/vvfat.c +@@ -27,6 +27,7 @@ + #include + #include "qapi/error.h" + #include "block/block_int.h" ++#include "block/qdict.h" + #include "qemu/module.h" + #include "qemu/option.h" + #include "qemu/bswap.h" +diff --git a/block/vxhs.c b/block/vxhs.c +index 96e83d9..25fea7f 100644 +--- a/block/vxhs.c ++++ b/block/vxhs.c +@@ -13,6 +13,7 @@ + #include + #include + #include "block/block_int.h" ++#include "block/qdict.h" + #include "qapi/qmp/qerror.h" + #include "qapi/qmp/qdict.h" + #include "qapi/qmp/qstring.h" +diff --git a/blockdev.c b/blockdev.c +index 129e444..96a89cc 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -35,6 +35,7 @@ + #include "sysemu/blockdev.h" + #include "hw/block/block.h" + #include "block/blockjob.h" ++#include "block/qdict.h" + #include "block/throttle-groups.h" + #include "monitor/monitor.h" + #include "qemu/error-report.h" +diff --git a/include/block/qdict.h b/include/block/qdict.h +new file mode 100644 +index 0000000..71c037a +--- /dev/null ++++ b/include/block/qdict.h +@@ -0,0 +1,32 @@ ++/* ++ * Special QDict functions used by the block layer ++ * ++ * Copyright (c) 2013-2018 Red Hat, Inc. ++ * ++ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. ++ * See the COPYING.LIB file in the top-level directory. ++ */ ++ ++#ifndef BLOCK_QDICT_H ++#define BLOCK_QDICT_H ++ ++#include "qapi/qmp/qdict.h" ++ ++void qdict_copy_default(QDict *dst, QDict *src, const char *key); ++void qdict_set_default_str(QDict *dst, const char *key, const char *val); ++ ++void qdict_join(QDict *dest, QDict *src, bool overwrite); ++ ++void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start); ++void qdict_array_split(QDict *src, QList **dst); ++int qdict_array_entries(QDict *src, const char *subqdict); ++QObject *qdict_crumple(const QDict *src, Error **errp); ++void qdict_flatten(QDict *qdict); ++ ++typedef struct QDictRenames { ++ const char *from; ++ const char *to; ++} QDictRenames; ++bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp); ++ ++#endif +diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h +index 921a28d..7f3ec10 100644 +--- a/include/qapi/qmp/qdict.h ++++ b/include/qapi/qmp/qdict.h +@@ -67,23 +67,6 @@ int64_t qdict_get_try_int(const QDict *qdict, const char *key, + bool qdict_get_try_bool(const QDict *qdict, const char *key, bool def_value); + const char *qdict_get_try_str(const QDict *qdict, const char *key); + +-void qdict_copy_default(QDict *dst, QDict *src, const char *key); +-void qdict_set_default_str(QDict *dst, const char *key, const char *val); +- + QDict *qdict_clone_shallow(const QDict *src); +-void qdict_flatten(QDict *qdict); +- +-void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start); +-void qdict_array_split(QDict *src, QList **dst); +-int qdict_array_entries(QDict *src, const char *subqdict); +-QObject *qdict_crumple(const QDict *src, Error **errp); +- +-void qdict_join(QDict *dest, QDict *src, bool overwrite); +- +-typedef struct QDictRenames { +- const char *from; +- const char *to; +-} QDictRenames; +-bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp); + + #endif /* QDICT_H */ +diff --git a/qobject/qdict.c b/qobject/qdict.c +index 22800ee..0554c64 100644 +--- a/qobject/qdict.c ++++ b/qobject/qdict.c +@@ -11,6 +11,7 @@ + */ + + #include "qemu/osdep.h" ++#include "block/qdict.h" + #include "qapi/qmp/qnum.h" + #include "qapi/qmp/qdict.h" + #include "qapi/qmp/qbool.h" +diff --git a/tests/check-qdict.c b/tests/check-qdict.c +index eba5d35..93e2112 100644 +--- a/tests/check-qdict.c ++++ b/tests/check-qdict.c +@@ -11,6 +11,7 @@ + */ + + #include "qemu/osdep.h" ++#include "block/qdict.h" + #include "qapi/qmp/qdict.h" + #include "qapi/qmp/qlist.h" + #include "qapi/qmp/qnum.h" +diff --git a/tests/check-qobject.c b/tests/check-qobject.c +index 5cb08fc..16ccbde 100644 +--- a/tests/check-qobject.c ++++ b/tests/check-qobject.c +@@ -8,6 +8,7 @@ + */ + + #include "qemu/osdep.h" ++#include "block/qdict.h" + #include "qapi/qmp/qbool.h" + #include "qapi/qmp/qdict.h" + #include "qapi/qmp/qlist.h" +diff --git a/tests/test-replication.c b/tests/test-replication.c +index 68c0d04..c8165ae 100644 +--- a/tests/test-replication.c ++++ b/tests/test-replication.c +@@ -15,6 +15,7 @@ + #include "qemu/option.h" + #include "replication.h" + #include "block/block_int.h" ++#include "block/qdict.h" + #include "sysemu/block-backend.h" + + #define IMG_SIZE (64 * 1024 * 1024) +diff --git a/util/qemu-config.c b/util/qemu-config.c +index 14d8402..9d2e278 100644 +--- a/util/qemu-config.c ++++ b/util/qemu-config.c +@@ -1,4 +1,5 @@ + #include "qemu/osdep.h" ++#include "block/qdict.h" /* for qdict_extract_subqdict() */ + #include "qapi/error.h" + #include "qapi/qapi-commands-misc.h" + #include "qapi/qmp/qdict.h" +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Add-missing-locking-in-bdrv_co_drain_bh_cb.patch b/SOURCES/kvm-block-Add-missing-locking-in-bdrv_co_drain_bh_cb.patch new file mode 100644 index 0000000..d068f40 --- /dev/null +++ b/SOURCES/kvm-block-Add-missing-locking-in-bdrv_co_drain_bh_cb.patch @@ -0,0 +1,94 @@ +From e0603f9fadc9d8cabd0d47c09dc99880aafcc905 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:31 +0200 +Subject: [PATCH 40/49] block: Add missing locking in bdrv_co_drain_bh_cb() + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-34-kwolf@redhat.com> +Patchwork-id: 82185 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 33/42] block: Add missing locking in bdrv_co_drain_bh_cb() +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +bdrv_do_drained_begin/end() assume that they are called with the +AioContext lock of bs held. If we call drain functions from a coroutine +with the AioContext lock held, we yield and schedule a BH to move out of +coroutine context. This means that the lock for the home context of the +coroutine is released and must be re-acquired in the bottom half. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + block/io.c | 15 +++++++++++++++ + include/qemu/coroutine.h | 5 +++++ + util/qemu-coroutine.c | 5 +++++ + 3 files changed, 25 insertions(+) + +diff --git a/block/io.c b/block/io.c +index d404088..19db35e 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -286,6 +286,18 @@ static void bdrv_co_drain_bh_cb(void *opaque) + BlockDriverState *bs = data->bs; + + if (bs) { ++ AioContext *ctx = bdrv_get_aio_context(bs); ++ AioContext *co_ctx = qemu_coroutine_get_aio_context(co); ++ ++ /* ++ * When the coroutine yielded, the lock for its home context was ++ * released, so we need to re-acquire it here. If it explicitly ++ * acquired a different context, the lock is still held and we don't ++ * want to lock it a second time (or AIO_WAIT_WHILE() would hang). ++ */ ++ if (ctx == co_ctx) { ++ aio_context_acquire(ctx); ++ } + bdrv_dec_in_flight(bs); + if (data->begin) { + bdrv_do_drained_begin(bs, data->recursive, data->parent, +@@ -294,6 +306,9 @@ static void bdrv_co_drain_bh_cb(void *opaque) + bdrv_do_drained_end(bs, data->recursive, data->parent, + data->ignore_bds_parents); + } ++ if (ctx == co_ctx) { ++ aio_context_release(ctx); ++ } + } else { + assert(data->begin); + bdrv_drain_all_begin(); +diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h +index 6f8a487..9801e7f 100644 +--- a/include/qemu/coroutine.h ++++ b/include/qemu/coroutine.h +@@ -90,6 +90,11 @@ void qemu_aio_coroutine_enter(AioContext *ctx, Coroutine *co); + void coroutine_fn qemu_coroutine_yield(void); + + /** ++ * Get the AioContext of the given coroutine ++ */ ++AioContext *coroutine_fn qemu_coroutine_get_aio_context(Coroutine *co); ++ ++/** + * Get the currently executing coroutine + */ + Coroutine *coroutine_fn qemu_coroutine_self(void); +diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c +index 1ba4191..2295928 100644 +--- a/util/qemu-coroutine.c ++++ b/util/qemu-coroutine.c +@@ -198,3 +198,8 @@ bool qemu_coroutine_entered(Coroutine *co) + { + return co->caller; + } ++ ++AioContext *coroutine_fn qemu_coroutine_get_aio_context(Coroutine *co) ++{ ++ return co->ctx; ++} +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Add-reopen-queue-to-bdrv_check_perm.patch b/SOURCES/kvm-block-Add-reopen-queue-to-bdrv_check_perm.patch deleted file mode 100644 index 11eec90..0000000 --- a/SOURCES/kvm-block-Add-reopen-queue-to-bdrv_check_perm.patch +++ /dev/null @@ -1,156 +0,0 @@ -From 6c5f6c4a5d6471c620c905ec911b2a0cbb5687c8 Mon Sep 17 00:00:00 2001 -From: Kevin Wolf -Date: Mon, 4 Dec 2017 12:10:02 +0100 -Subject: [PATCH 31/36] block: Add reopen queue to bdrv_check_perm() - -RH-Author: Kevin Wolf -Message-id: <20171204121007.12964-4-kwolf@redhat.com> -Patchwork-id: 78110 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 3/8] block: Add reopen queue to bdrv_check_perm() -Bugzilla: 1492178 -RH-Acked-by: Fam Zheng -RH-Acked-by: Max Reitz -RH-Acked-by: Jeffrey Cody - -In the context of bdrv_reopen(), we'll have to look at the state of the -graph as it will be after the reopen. This interface addition is in -preparation for the change. - -Signed-off-by: Kevin Wolf -Reviewed-by: Eric Blake -(cherry picked from commit 3121fb45b004ea85fb3589368ea699f32e6ef832) -Signed-off-by: Miroslav Rezanina ---- - block.c | 34 +++++++++++++++++++--------------- - 1 file changed, 19 insertions(+), 15 deletions(-) - -diff --git a/block.c b/block.c -index ab67062..5ce773a 100644 ---- a/block.c -+++ b/block.c -@@ -1529,7 +1529,8 @@ static int bdrv_fill_options(QDict **options, const char *filename, - return 0; - } - --static int bdrv_child_check_perm(BdrvChild *c, uint64_t perm, uint64_t shared, -+static int bdrv_child_check_perm(BdrvChild *c, BlockReopenQueue *q, -+ uint64_t perm, uint64_t shared, - GSList *ignore_children, Error **errp); - static void bdrv_child_abort_perm_update(BdrvChild *c); - static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared); -@@ -1560,7 +1561,8 @@ static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs, - * A call to this function must always be followed by a call to bdrv_set_perm() - * or bdrv_abort_perm_update(). - */ --static int bdrv_check_perm(BlockDriverState *bs, uint64_t cumulative_perms, -+static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q, -+ uint64_t cumulative_perms, - uint64_t cumulative_shared_perms, - GSList *ignore_children, Error **errp) - { -@@ -1595,11 +1597,11 @@ static int bdrv_check_perm(BlockDriverState *bs, uint64_t cumulative_perms, - /* Check all children */ - QLIST_FOREACH(c, &bs->children, next) { - uint64_t cur_perm, cur_shared; -- bdrv_child_perm(bs, c->bs, c, c->role, NULL, -+ bdrv_child_perm(bs, c->bs, c, c->role, q, - cumulative_perms, cumulative_shared_perms, - &cur_perm, &cur_shared); -- ret = bdrv_child_check_perm(c, cur_perm, cur_shared, ignore_children, -- errp); -+ ret = bdrv_child_check_perm(c, q, cur_perm, cur_shared, -+ ignore_children, errp); - if (ret < 0) { - return ret; - } -@@ -1725,7 +1727,8 @@ char *bdrv_perm_names(uint64_t perm) - * - * Needs to be followed by a call to either bdrv_set_perm() or - * bdrv_abort_perm_update(). */ --static int bdrv_check_update_perm(BlockDriverState *bs, uint64_t new_used_perm, -+static int bdrv_check_update_perm(BlockDriverState *bs, BlockReopenQueue *q, -+ uint64_t new_used_perm, - uint64_t new_shared_perm, - GSList *ignore_children, Error **errp) - { -@@ -1767,19 +1770,20 @@ static int bdrv_check_update_perm(BlockDriverState *bs, uint64_t new_used_perm, - cumulative_shared_perms &= c->shared_perm; - } - -- return bdrv_check_perm(bs, cumulative_perms, cumulative_shared_perms, -+ return bdrv_check_perm(bs, q, cumulative_perms, cumulative_shared_perms, - ignore_children, errp); - } - - /* Needs to be followed by a call to either bdrv_child_set_perm() or - * bdrv_child_abort_perm_update(). */ --static int bdrv_child_check_perm(BdrvChild *c, uint64_t perm, uint64_t shared, -+static int bdrv_child_check_perm(BdrvChild *c, BlockReopenQueue *q, -+ uint64_t perm, uint64_t shared, - GSList *ignore_children, Error **errp) - { - int ret; - - ignore_children = g_slist_prepend(g_slist_copy(ignore_children), c); -- ret = bdrv_check_update_perm(c->bs, perm, shared, ignore_children, errp); -+ ret = bdrv_check_update_perm(c->bs, q, perm, shared, ignore_children, errp); - g_slist_free(ignore_children); - - return ret; -@@ -1807,7 +1811,7 @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared, - { - int ret; - -- ret = bdrv_child_check_perm(c, perm, shared, NULL, errp); -+ ret = bdrv_child_check_perm(c, NULL, perm, shared, NULL, errp); - if (ret < 0) { - bdrv_child_abort_perm_update(c); - return ret; -@@ -1948,7 +1952,7 @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs) - * because we're just taking a parent away, so we're loosening - * restrictions. */ - bdrv_get_cumulative_perm(old_bs, &perm, &shared_perm); -- bdrv_check_perm(old_bs, perm, shared_perm, NULL, &error_abort); -+ bdrv_check_perm(old_bs, NULL, perm, shared_perm, NULL, &error_abort); - bdrv_set_perm(old_bs, perm, shared_perm); - } - -@@ -1967,7 +1971,7 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, - BdrvChild *child; - int ret; - -- ret = bdrv_check_update_perm(child_bs, perm, shared_perm, NULL, errp); -+ ret = bdrv_check_update_perm(child_bs, NULL, perm, shared_perm, NULL, errp); - if (ret < 0) { - bdrv_abort_perm_update(child_bs); - return NULL; -@@ -3183,7 +3187,7 @@ void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to, - - /* Check whether the required permissions can be granted on @to, ignoring - * all BdrvChild in @list so that they can't block themselves. */ -- ret = bdrv_check_update_perm(to, perm, shared, list, errp); -+ ret = bdrv_check_update_perm(to, NULL, perm, shared, list, errp); - if (ret < 0) { - bdrv_abort_perm_update(to); - goto out; -@@ -4040,7 +4044,7 @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp) - - /* Update permissions, they may differ for inactive nodes */ - bdrv_get_cumulative_perm(bs, &perm, &shared_perm); -- ret = bdrv_check_perm(bs, perm, shared_perm, NULL, &local_err); -+ ret = bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, &local_err); - if (ret < 0) { - bs->open_flags |= BDRV_O_INACTIVE; - error_propagate(errp, local_err); -@@ -4107,7 +4111,7 @@ static int bdrv_inactivate_recurse(BlockDriverState *bs, - - /* Update permissions, they may differ for inactive nodes */ - bdrv_get_cumulative_perm(bs, &perm, &shared_perm); -- bdrv_check_perm(bs, perm, shared_perm, NULL, &error_abort); -+ bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, &error_abort); - bdrv_set_perm(bs, perm, shared_perm); - } - --- -1.8.3.1 - diff --git a/SOURCES/kvm-block-Add-reopen_queue-to-bdrv_child_perm.patch b/SOURCES/kvm-block-Add-reopen_queue-to-bdrv_child_perm.patch deleted file mode 100644 index 89ac615..0000000 --- a/SOURCES/kvm-block-Add-reopen_queue-to-bdrv_child_perm.patch +++ /dev/null @@ -1,198 +0,0 @@ -From 4233c105ab4dc42ea8252717a0b68ee387ef8ed8 Mon Sep 17 00:00:00 2001 -From: Kevin Wolf -Date: Mon, 4 Dec 2017 12:10:01 +0100 -Subject: [PATCH 30/36] block: Add reopen_queue to bdrv_child_perm() - -RH-Author: Kevin Wolf -Message-id: <20171204121007.12964-3-kwolf@redhat.com> -Patchwork-id: 78105 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 2/8] block: Add reopen_queue to bdrv_child_perm() -Bugzilla: 1492178 -RH-Acked-by: Fam Zheng -RH-Acked-by: Max Reitz -RH-Acked-by: Jeffrey Cody - -In the context of bdrv_reopen(), we'll have to look at the state of the -graph as it will be after the reopen. This interface addition is in -preparation for the change. - -Signed-off-by: Kevin Wolf -Reviewed-by: Eric Blake -(cherry picked from commit e0995dc3da0894d0a8260bddaa200a4cd7809ba4) -Signed-off-by: Miroslav Rezanina ---- - block.c | 19 ++++++++++++------- - block/commit.c | 1 + - block/mirror.c | 1 + - block/replication.c | 1 + - block/vvfat.c | 1 + - include/block/block_int.h | 7 +++++++ - 6 files changed, 23 insertions(+), 7 deletions(-) - -diff --git a/block.c b/block.c -index 6fb4e98..ab67062 100644 ---- a/block.c -+++ b/block.c -@@ -1535,16 +1535,17 @@ static void bdrv_child_abort_perm_update(BdrvChild *c); - static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared); - - static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs, -- BdrvChild *c, -- const BdrvChildRole *role, -+ BdrvChild *c, const BdrvChildRole *role, -+ BlockReopenQueue *reopen_queue, - uint64_t parent_perm, uint64_t parent_shared, - uint64_t *nperm, uint64_t *nshared) - { - if (bs->drv && bs->drv->bdrv_child_perm) { -- bs->drv->bdrv_child_perm(bs, c, role, -+ bs->drv->bdrv_child_perm(bs, c, role, reopen_queue, - parent_perm, parent_shared, - nperm, nshared); - } -+ /* TODO Take force_share from reopen_queue */ - if (child_bs && child_bs->force_share) { - *nshared = BLK_PERM_ALL; - } -@@ -1594,7 +1595,7 @@ static int bdrv_check_perm(BlockDriverState *bs, uint64_t cumulative_perms, - /* Check all children */ - QLIST_FOREACH(c, &bs->children, next) { - uint64_t cur_perm, cur_shared; -- bdrv_child_perm(bs, c->bs, c, c->role, -+ bdrv_child_perm(bs, c->bs, c, c->role, NULL, - cumulative_perms, cumulative_shared_perms, - &cur_perm, &cur_shared); - ret = bdrv_child_check_perm(c, cur_perm, cur_shared, ignore_children, -@@ -1656,7 +1657,7 @@ static void bdrv_set_perm(BlockDriverState *bs, uint64_t cumulative_perms, - /* Update all children */ - QLIST_FOREACH(c, &bs->children, next) { - uint64_t cur_perm, cur_shared; -- bdrv_child_perm(bs, c->bs, c, c->role, -+ bdrv_child_perm(bs, c->bs, c, c->role, NULL, - cumulative_perms, cumulative_shared_perms, - &cur_perm, &cur_shared); - bdrv_child_set_perm(c, cur_perm, cur_shared); -@@ -1825,6 +1826,7 @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared, - - void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, - const BdrvChildRole *role, -+ BlockReopenQueue *reopen_queue, - uint64_t perm, uint64_t shared, - uint64_t *nperm, uint64_t *nshared) - { -@@ -1842,6 +1844,7 @@ void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, - - void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, - const BdrvChildRole *role, -+ BlockReopenQueue *reopen_queue, - uint64_t perm, uint64_t shared, - uint64_t *nperm, uint64_t *nshared) - { -@@ -1851,9 +1854,11 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, - if (!backing) { - /* Apart from the modifications below, the same permissions are - * forwarded and left alone as for filters */ -- bdrv_filter_default_perms(bs, c, role, perm, shared, &perm, &shared); -+ bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared, -+ &perm, &shared); - - /* Format drivers may touch metadata even if the guest doesn't write */ -+ /* TODO Take flags from reopen_queue */ - if (bdrv_is_writable(bs)) { - perm |= BLK_PERM_WRITE | BLK_PERM_RESIZE; - } -@@ -1997,7 +2002,7 @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, - - assert(parent_bs->drv); - assert(bdrv_get_aio_context(parent_bs) == bdrv_get_aio_context(child_bs)); -- bdrv_child_perm(parent_bs, child_bs, NULL, child_role, -+ bdrv_child_perm(parent_bs, child_bs, NULL, child_role, NULL, - perm, shared_perm, &perm, &shared_perm); - - child = bdrv_root_attach_child(child_bs, child_name, child_role, -diff --git a/block/commit.c b/block/commit.c -index c7857c3..834084b 100644 ---- a/block/commit.c -+++ b/block/commit.c -@@ -267,6 +267,7 @@ static void bdrv_commit_top_close(BlockDriverState *bs) - - static void bdrv_commit_top_child_perm(BlockDriverState *bs, BdrvChild *c, - const BdrvChildRole *role, -+ BlockReopenQueue *reopen_queue, - uint64_t perm, uint64_t shared, - uint64_t *nperm, uint64_t *nshared) - { -diff --git a/block/mirror.c b/block/mirror.c -index 429751b..17278db 100644 ---- a/block/mirror.c -+++ b/block/mirror.c -@@ -1094,6 +1094,7 @@ static void bdrv_mirror_top_close(BlockDriverState *bs) - - static void bdrv_mirror_top_child_perm(BlockDriverState *bs, BdrvChild *c, - const BdrvChildRole *role, -+ BlockReopenQueue *reopen_queue, - uint64_t perm, uint64_t shared, - uint64_t *nperm, uint64_t *nshared) - { -diff --git a/block/replication.c b/block/replication.c -index bf4462c..3a4e682 100644 ---- a/block/replication.c -+++ b/block/replication.c -@@ -157,6 +157,7 @@ static void replication_close(BlockDriverState *bs) - - static void replication_child_perm(BlockDriverState *bs, BdrvChild *c, - const BdrvChildRole *role, -+ BlockReopenQueue *reopen_queue, - uint64_t perm, uint64_t shared, - uint64_t *nperm, uint64_t *nshared) - { -diff --git a/block/vvfat.c b/block/vvfat.c -index a9e207f..e9110a9 100644 ---- a/block/vvfat.c -+++ b/block/vvfat.c -@@ -3210,6 +3210,7 @@ err: - - static void vvfat_child_perm(BlockDriverState *bs, BdrvChild *c, - const BdrvChildRole *role, -+ BlockReopenQueue *reopen_queue, - uint64_t perm, uint64_t shared, - uint64_t *nperm, uint64_t *nshared) - { -diff --git a/include/block/block_int.h b/include/block/block_int.h -index 7571c0a..a6faf1b 100644 ---- a/include/block/block_int.h -+++ b/include/block/block_int.h -@@ -377,9 +377,14 @@ struct BlockDriver { - * - * If @c is NULL, return the permissions for attaching a new child for the - * given @role. -+ * -+ * If @reopen_queue is non-NULL, don't return the currently needed -+ * permissions, but those that will be needed after applying the -+ * @reopen_queue. - */ - void (*bdrv_child_perm)(BlockDriverState *bs, BdrvChild *c, - const BdrvChildRole *role, -+ BlockReopenQueue *reopen_queue, - uint64_t parent_perm, uint64_t parent_shared, - uint64_t *nperm, uint64_t *nshared); - -@@ -949,6 +954,7 @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared, - * all children */ - void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, - const BdrvChildRole *role, -+ BlockReopenQueue *reopen_queue, - uint64_t perm, uint64_t shared, - uint64_t *nperm, uint64_t *nshared); - -@@ -958,6 +964,7 @@ void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, - * CONSISTENT_READ and doesn't share WRITE. */ - void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, - const BdrvChildRole *role, -+ BlockReopenQueue *reopen_queue, - uint64_t perm, uint64_t shared, - uint64_t *nperm, uint64_t *nshared); - --- -1.8.3.1 - diff --git a/SOURCES/kvm-block-Allow-AIO_WAIT_WHILE-with-NULL-ctx.patch b/SOURCES/kvm-block-Allow-AIO_WAIT_WHILE-with-NULL-ctx.patch new file mode 100644 index 0000000..0b194a8 --- /dev/null +++ b/SOURCES/kvm-block-Allow-AIO_WAIT_WHILE-with-NULL-ctx.patch @@ -0,0 +1,74 @@ +From e776fb3350daea9851190d6445b4786f4b1f493f Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:14 +0200 +Subject: [PATCH 23/49] block: Allow AIO_WAIT_WHILE with NULL ctx + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-17-kwolf@redhat.com> +Patchwork-id: 82168 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 16/42] block: Allow AIO_WAIT_WHILE with NULL ctx +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +bdrv_drain_all() wants to have a single polling loop for draining the +in-flight requests of all nodes. This means that the AIO_WAIT_WHILE() +condition relies on activity in multiple AioContexts, which is polled +from the mainloop context. We must therefore call AIO_WAIT_WHILE() from +the mainloop thread and use the AioWait notification mechanism. + +Just randomly picking the AioContext of any non-mainloop thread would +work, but instead of bothering to find such a context in the caller, we +can just as well accept NULL for ctx. + +Signed-off-by: Kevin Wolf +(cherry picked from commit 4d22bbf4ef72583eefdf44db6bf9fc7683fbc4c2) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + include/block/aio-wait.h | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/include/block/aio-wait.h b/include/block/aio-wait.h +index 783d367..c85a62f 100644 +--- a/include/block/aio-wait.h ++++ b/include/block/aio-wait.h +@@ -57,7 +57,8 @@ typedef struct { + /** + * AIO_WAIT_WHILE: + * @wait: the aio wait object +- * @ctx: the aio context ++ * @ctx: the aio context, or NULL if multiple aio contexts (for which the ++ * caller does not hold a lock) are involved in the polling condition. + * @cond: wait while this conditional expression is true + * + * Wait while a condition is true. Use this to implement synchronous +@@ -75,7 +76,7 @@ typedef struct { + bool waited_ = false; \ + AioWait *wait_ = (wait); \ + AioContext *ctx_ = (ctx); \ +- if (in_aio_context_home_thread(ctx_)) { \ ++ if (ctx_ && in_aio_context_home_thread(ctx_)) { \ + while ((cond)) { \ + aio_poll(ctx_, true); \ + waited_ = true; \ +@@ -86,9 +87,13 @@ typedef struct { + /* Increment wait_->num_waiters before evaluating cond. */ \ + atomic_inc(&wait_->num_waiters); \ + while ((cond)) { \ +- aio_context_release(ctx_); \ ++ if (ctx_) { \ ++ aio_context_release(ctx_); \ ++ } \ + aio_poll(qemu_get_aio_context(), true); \ +- aio_context_acquire(ctx_); \ ++ if (ctx_) { \ ++ aio_context_acquire(ctx_); \ ++ } \ + waited_ = true; \ + } \ + atomic_dec(&wait_->num_waiters); \ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Allow-graph-changes-in-bdrv_drain_all_begin-en.patch b/SOURCES/kvm-block-Allow-graph-changes-in-bdrv_drain_all_begin-en.patch new file mode 100644 index 0000000..2c8f4b6 --- /dev/null +++ b/SOURCES/kvm-block-Allow-graph-changes-in-bdrv_drain_all_begin-en.patch @@ -0,0 +1,266 @@ +From 78fde43fee8eaaa0fd1222844961614f576ebd7c Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:17 +0200 +Subject: [PATCH 26/49] block: Allow graph changes in bdrv_drain_all_begin/end + sections + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-20-kwolf@redhat.com> +Patchwork-id: 82171 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 19/42] block: Allow graph changes in bdrv_drain_all_begin/end sections +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +bdrv_drain_all_*() used bdrv_next() to iterate over all root nodes and +did a subtree drain for each of them. This works fine as long as the +graph is static, but sadly, reality looks different. + +If the graph changes so that root nodes are added or removed, we would +have to compensate for this. bdrv_next() returns each root node only +once even if it's the root node for multiple BlockBackends or for a +monitor-owned block driver tree, which would only complicate things. + +The much easier and more obviously correct way is to fundamentally +change the way the functions work: Iterate over all BlockDriverStates, +no matter who owns them, and drain them individually. Compensation is +only necessary when a new BDS is created inside a drain_all section. +Removal of a BDS doesn't require any action because it's gone afterwards +anyway. + +Signed-off-by: Kevin Wolf +(cherry picked from commit 0f12264e7a41458179ad10276a7c33c72024861a) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block.c | 34 ++++++++++++++++++++++++--- + block/io.c | 60 ++++++++++++++++++++++++++++++++++++----------- + include/block/block.h | 1 + + include/block/block_int.h | 1 + + 4 files changed, 79 insertions(+), 17 deletions(-) + +diff --git a/block.c b/block.c +index 519be6e..eea9c6f 100644 +--- a/block.c ++++ b/block.c +@@ -333,6 +333,10 @@ BlockDriverState *bdrv_new(void) + + qemu_co_queue_init(&bs->flush_queue); + ++ for (i = 0; i < bdrv_drain_all_count; i++) { ++ bdrv_drained_begin(bs); ++ } ++ + QTAILQ_INSERT_TAIL(&all_bdrv_states, bs, bs_list); + + return bs; +@@ -1170,7 +1174,7 @@ static int bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv, + int open_flags, Error **errp) + { + Error *local_err = NULL; +- int ret; ++ int i, ret; + + bdrv_assign_node_name(bs, node_name, &local_err); + if (local_err) { +@@ -1218,6 +1222,12 @@ static int bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv, + assert(bdrv_min_mem_align(bs) != 0); + assert(is_power_of_2(bs->bl.request_alignment)); + ++ for (i = 0; i < bs->quiesce_counter; i++) { ++ if (drv->bdrv_co_drain_begin) { ++ drv->bdrv_co_drain_begin(bs); ++ } ++ } ++ + return 0; + open_failed: + bs->drv = NULL; +@@ -2039,7 +2049,12 @@ static void bdrv_replace_child_noperm(BdrvChild *child, + child->role->detach(child); + } + if (old_bs->quiesce_counter && child->role->drained_end) { +- for (i = 0; i < old_bs->quiesce_counter; i++) { ++ int num = old_bs->quiesce_counter; ++ if (child->role->parent_is_bds) { ++ num -= bdrv_drain_all_count; ++ } ++ assert(num >= 0); ++ for (i = 0; i < num; i++) { + child->role->drained_end(child); + } + } +@@ -2051,7 +2066,12 @@ static void bdrv_replace_child_noperm(BdrvChild *child, + if (new_bs) { + QLIST_INSERT_HEAD(&new_bs->parents, child, next_parent); + if (new_bs->quiesce_counter && child->role->drained_begin) { +- for (i = 0; i < new_bs->quiesce_counter; i++) { ++ int num = new_bs->quiesce_counter; ++ if (child->role->parent_is_bds) { ++ num -= bdrv_drain_all_count; ++ } ++ assert(num >= 0); ++ for (i = 0; i < num; i++) { + child->role->drained_begin(child); + } + } +@@ -3993,6 +4013,14 @@ BlockDriverState *bdrv_next_node(BlockDriverState *bs) + return QTAILQ_NEXT(bs, node_list); + } + ++BlockDriverState *bdrv_next_all_states(BlockDriverState *bs) ++{ ++ if (!bs) { ++ return QTAILQ_FIRST(&all_bdrv_states); ++ } ++ return QTAILQ_NEXT(bs, bs_list); ++} ++ + const char *bdrv_get_node_name(const BlockDriverState *bs) + { + return bs->node_name; +diff --git a/block/io.c b/block/io.c +index 0021fefd..38ae299 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -38,6 +38,8 @@ + /* Maximum bounce buffer for copy-on-read and write zeroes, in bytes */ + #define MAX_BOUNCE_BUFFER (32768 << BDRV_SECTOR_BITS) + ++static AioWait drain_all_aio_wait; ++ + static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, + int64_t offset, int bytes, BdrvRequestFlags flags); + +@@ -471,6 +473,29 @@ static void bdrv_drain_assert_idle(BlockDriverState *bs) + } + } + ++unsigned int bdrv_drain_all_count = 0; ++ ++static bool bdrv_drain_all_poll(void) ++{ ++ BlockDriverState *bs = NULL; ++ bool result = false; ++ ++ /* Execute pending BHs first (may modify the graph) and check everything ++ * else only after the BHs have executed. */ ++ while (aio_poll(qemu_get_aio_context(), false)); ++ ++ /* bdrv_drain_poll() can't make changes to the graph and we are holding the ++ * main AioContext lock, so iterating bdrv_next_all_states() is safe. */ ++ while ((bs = bdrv_next_all_states(bs))) { ++ AioContext *aio_context = bdrv_get_aio_context(bs); ++ aio_context_acquire(aio_context); ++ result |= bdrv_drain_poll(bs, false, NULL, true); ++ aio_context_release(aio_context); ++ } ++ ++ return result; ++} ++ + /* + * Wait for pending requests to complete across all BlockDriverStates + * +@@ -485,45 +510,51 @@ static void bdrv_drain_assert_idle(BlockDriverState *bs) + */ + void bdrv_drain_all_begin(void) + { +- BlockDriverState *bs; +- BdrvNextIterator it; ++ BlockDriverState *bs = NULL; + + if (qemu_in_coroutine()) { +- bdrv_co_yield_to_drain(NULL, true, false, NULL, false, true); ++ bdrv_co_yield_to_drain(NULL, true, false, NULL, true, true); + return; + } + +- /* BDRV_POLL_WHILE() for a node can only be called from its own I/O thread +- * or the main loop AioContext. We potentially use BDRV_POLL_WHILE() on +- * nodes in several different AioContexts, so make sure we're in the main +- * context. */ ++ /* AIO_WAIT_WHILE() with a NULL context can only be called from the main ++ * loop AioContext, so make sure we're in the main context. */ + assert(qemu_get_current_aio_context() == qemu_get_aio_context()); ++ assert(bdrv_drain_all_count < INT_MAX); ++ bdrv_drain_all_count++; + +- for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { ++ /* Quiesce all nodes, without polling in-flight requests yet. The graph ++ * cannot change during this loop. */ ++ while ((bs = bdrv_next_all_states(bs))) { + AioContext *aio_context = bdrv_get_aio_context(bs); + + aio_context_acquire(aio_context); +- bdrv_do_drained_begin(bs, true, NULL, false, true); ++ bdrv_do_drained_begin(bs, false, NULL, true, false); + aio_context_release(aio_context); + } + +- for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { ++ /* Now poll the in-flight requests */ ++ AIO_WAIT_WHILE(&drain_all_aio_wait, NULL, bdrv_drain_all_poll()); ++ ++ while ((bs = bdrv_next_all_states(bs))) { + bdrv_drain_assert_idle(bs); + } + } + + void bdrv_drain_all_end(void) + { +- BlockDriverState *bs; +- BdrvNextIterator it; ++ BlockDriverState *bs = NULL; + +- for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { ++ while ((bs = bdrv_next_all_states(bs))) { + AioContext *aio_context = bdrv_get_aio_context(bs); + + aio_context_acquire(aio_context); +- bdrv_do_drained_end(bs, true, NULL, false); ++ bdrv_do_drained_end(bs, false, NULL, true); + aio_context_release(aio_context); + } ++ ++ assert(bdrv_drain_all_count > 0); ++ bdrv_drain_all_count--; + } + + void bdrv_drain_all(void) +@@ -658,6 +689,7 @@ void bdrv_inc_in_flight(BlockDriverState *bs) + void bdrv_wakeup(BlockDriverState *bs) + { + aio_wait_kick(bdrv_get_aio_wait(bs)); ++ aio_wait_kick(&drain_all_aio_wait); + } + + void bdrv_dec_in_flight(BlockDriverState *bs) +diff --git a/include/block/block.h b/include/block/block.h +index 6e91803..f9079ac 100644 +--- a/include/block/block.h ++++ b/include/block/block.h +@@ -449,6 +449,7 @@ BlockDriverState *bdrv_lookup_bs(const char *device, + Error **errp); + bool bdrv_chain_contains(BlockDriverState *top, BlockDriverState *base); + BlockDriverState *bdrv_next_node(BlockDriverState *bs); ++BlockDriverState *bdrv_next_all_states(BlockDriverState *bs); + + typedef struct BdrvNextIterator { + enum { +diff --git a/include/block/block_int.h b/include/block/block_int.h +index 0ad8a76..9757d5e 100644 +--- a/include/block/block_int.h ++++ b/include/block/block_int.h +@@ -845,6 +845,7 @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child, + int64_t offset, unsigned int bytes, QEMUIOVector *qiov, + BdrvRequestFlags flags); + ++extern unsigned int bdrv_drain_all_count; + void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent); + void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Avoid-unnecessary-aio_poll-in-AIO_WAIT_WHILE.patch b/SOURCES/kvm-block-Avoid-unnecessary-aio_poll-in-AIO_WAIT_WHILE.patch new file mode 100644 index 0000000..d3d2560 --- /dev/null +++ b/SOURCES/kvm-block-Avoid-unnecessary-aio_poll-in-AIO_WAIT_WHILE.patch @@ -0,0 +1,112 @@ +From 1a6556bc1317af4669d058e6df70bc1c036d37a5 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:04 +0200 +Subject: [PATCH 13/49] block: Avoid unnecessary aio_poll() in AIO_WAIT_WHILE() + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-7-kwolf@redhat.com> +Patchwork-id: 82158 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 06/42] block: Avoid unnecessary aio_poll() in AIO_WAIT_WHILE() +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +Commit 91af091f923 added an additional aio_poll() to BDRV_POLL_WHILE() +in order to make sure that all pending BHs are executed on drain. This +was the wrong place to make the fix, as it is useless overhead for all +other users of the macro and unnecessarily complicates the mechanism. + +This patch effectively reverts said commit (the context has changed a +bit and the code has moved to AIO_WAIT_WHILE()) and instead polls in the +loop condition for drain. + +The effect is probably hard to measure in any real-world use case +because actual I/O will dominate, but if I run only the initialisation +part of 'qemu-img convert' where it calls bdrv_block_status() for the +whole image to find out how much data there is copy, this phase actually +needs only roughly half the time after this patch. + +Signed-off-by: Kevin Wolf +Reviewed-by: Stefan Hajnoczi +(cherry picked from commit 1cc8e54ada97f7ac479554e15ca9e426c895b158) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/io.c | 11 ++++++++++- + include/block/aio-wait.h | 22 ++++++++-------------- + 2 files changed, 18 insertions(+), 15 deletions(-) + +diff --git a/block/io.c b/block/io.c +index e5fc42c..4d332c3 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -181,13 +181,22 @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin) + BDRV_POLL_WHILE(bs, !data.done); + } + ++/* Returns true if BDRV_POLL_WHILE() should go into a blocking aio_poll() */ ++static bool bdrv_drain_poll(BlockDriverState *bs) ++{ ++ /* Execute pending BHs first and check everything else only after the BHs ++ * have executed. */ ++ while (aio_poll(bs->aio_context, false)); ++ return atomic_read(&bs->in_flight); ++} ++ + static bool bdrv_drain_recurse(BlockDriverState *bs) + { + BdrvChild *child, *tmp; + bool waited; + + /* Wait for drained requests to finish */ +- waited = BDRV_POLL_WHILE(bs, atomic_read(&bs->in_flight) > 0); ++ waited = BDRV_POLL_WHILE(bs, bdrv_drain_poll(bs)); + + QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) { + BlockDriverState *bs = child->bs; +diff --git a/include/block/aio-wait.h b/include/block/aio-wait.h +index 8c90a2e..783d367 100644 +--- a/include/block/aio-wait.h ++++ b/include/block/aio-wait.h +@@ -73,29 +73,23 @@ typedef struct { + */ + #define AIO_WAIT_WHILE(wait, ctx, cond) ({ \ + bool waited_ = false; \ +- bool busy_ = true; \ + AioWait *wait_ = (wait); \ + AioContext *ctx_ = (ctx); \ + if (in_aio_context_home_thread(ctx_)) { \ +- while ((cond) || busy_) { \ +- busy_ = aio_poll(ctx_, (cond)); \ +- waited_ |= !!(cond) | busy_; \ ++ while ((cond)) { \ ++ aio_poll(ctx_, true); \ ++ waited_ = true; \ + } \ + } else { \ + assert(qemu_get_current_aio_context() == \ + qemu_get_aio_context()); \ + /* Increment wait_->num_waiters before evaluating cond. */ \ + atomic_inc(&wait_->num_waiters); \ +- while (busy_) { \ +- if ((cond)) { \ +- waited_ = busy_ = true; \ +- aio_context_release(ctx_); \ +- aio_poll(qemu_get_aio_context(), true); \ +- aio_context_acquire(ctx_); \ +- } else { \ +- busy_ = aio_poll(ctx_, false); \ +- waited_ |= busy_; \ +- } \ ++ while ((cond)) { \ ++ aio_context_release(ctx_); \ ++ aio_poll(qemu_get_aio_context(), true); \ ++ aio_context_acquire(ctx_); \ ++ waited_ = true; \ + } \ + atomic_dec(&wait_->num_waiters); \ + } \ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-BLK_PERM_WRITE-includes-._UNCHANGED.patch b/SOURCES/kvm-block-BLK_PERM_WRITE-includes-._UNCHANGED.patch new file mode 100644 index 0000000..6f6bb02 --- /dev/null +++ b/SOURCES/kvm-block-BLK_PERM_WRITE-includes-._UNCHANGED.patch @@ -0,0 +1,50 @@ +From 68b3e533a4531486fe346f042e190fb5c426f24f Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 16:12:05 +0200 +Subject: [PATCH 29/54] block: BLK_PERM_WRITE includes ..._UNCHANGED + +RH-Author: Max Reitz +Message-id: <20180618161212.14444-4-mreitz@redhat.com> +Patchwork-id: 80763 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 03/10] block: BLK_PERM_WRITE includes ..._UNCHANGED +Bugzilla: 1518738 +RH-Acked-by: John Snow +RH-Acked-by: Kevin Wolf +RH-Acked-by: Miroslav Rezanina + +Currently we never actually check whether the WRITE_UNCHANGED +permission has been taken for unchanging writes. But the one check that +is commented out checks both WRITE and WRITE_UNCHANGED; and considering +that WRITE_UNCHANGED is already documented as being weaker than WRITE, +we should probably explicitly document WRITE to include WRITE_UNCHANGED. + +Signed-off-by: Max Reitz +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Alberto Garcia +Message-id: 20180421132929.21610-3-mreitz@redhat.com +Reviewed-by: Kevin Wolf +Signed-off-by: Max Reitz +(cherry picked from commit 24b7c538fea86b598e2a335f4805a0ab50a30e98) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + include/block/block.h | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/include/block/block.h b/include/block/block.h +index cdec363..397b5e8 100644 +--- a/include/block/block.h ++++ b/include/block/block.h +@@ -205,6 +205,9 @@ enum { + * This permission (which is weaker than BLK_PERM_WRITE) is both enough and + * required for writes to the block node when the caller promises that + * the visible disk content doesn't change. ++ * ++ * As the BLK_PERM_WRITE permission is strictly stronger, either is ++ * sufficient to perform an unchanging write. + */ + BLK_PERM_WRITE_UNCHANGED = 0x04, + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Base-permissions-on-rw-state-after-reopen.patch b/SOURCES/kvm-block-Base-permissions-on-rw-state-after-reopen.patch deleted file mode 100644 index 0256810..0000000 --- a/SOURCES/kvm-block-Base-permissions-on-rw-state-after-reopen.patch +++ /dev/null @@ -1,142 +0,0 @@ -From 35806318c04a6d8450ed745d1921a07915c3cc16 Mon Sep 17 00:00:00 2001 -From: Kevin Wolf -Date: Mon, 4 Dec 2017 12:10:03 +0100 -Subject: [PATCH 32/36] block: Base permissions on rw state after reopen - -RH-Author: Kevin Wolf -Message-id: <20171204121007.12964-5-kwolf@redhat.com> -Patchwork-id: 78109 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 4/8] block: Base permissions on rw state after reopen -Bugzilla: 1492178 -RH-Acked-by: Fam Zheng -RH-Acked-by: Max Reitz -RH-Acked-by: Jeffrey Cody - -When new permissions are calculated during bdrv_reopen(), they need to -be based on the state of the graph as it will be after the reopen has -completed, not on the current state of the involved nodes. - -This patch makes bdrv_is_writable() optionally accept a BlockReopenQueue -from which the new flags are taken. This is then used for determining -the new bs->file permissions of format drivers as soon as we add the -code to actually pass a non-NULL reopen queue to the .bdrv_child_perm -callbacks. - -While moving bdrv_is_writable(), make it static. It isn't used outside -block.c. - -Signed-off-by: Kevin Wolf -Reviewed-by: Eric Blake -(cherry picked from commit 148eb13c84cccd0eedd6e59f90e0151bd7bac9fa) -Signed-off-by: Miroslav Rezanina ---- - block.c | 52 ++++++++++++++++++++++++++++++++++++--------------- - include/block/block.h | 1 - - 2 files changed, 37 insertions(+), 16 deletions(-) - -diff --git a/block.c b/block.c -index 5ce773a..5cce274 100644 ---- a/block.c -+++ b/block.c -@@ -240,12 +240,6 @@ bool bdrv_is_read_only(BlockDriverState *bs) - return bs->read_only; - } - --/* Returns whether the image file can be written to right now */ --bool bdrv_is_writable(BlockDriverState *bs) --{ -- return !bdrv_is_read_only(bs) && !(bs->open_flags & BDRV_O_INACTIVE); --} -- - int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only, - bool ignore_allow_rdw, Error **errp) - { -@@ -1535,6 +1529,41 @@ static int bdrv_child_check_perm(BdrvChild *c, BlockReopenQueue *q, - static void bdrv_child_abort_perm_update(BdrvChild *c); - static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared); - -+typedef struct BlockReopenQueueEntry { -+ bool prepared; -+ BDRVReopenState state; -+ QSIMPLEQ_ENTRY(BlockReopenQueueEntry) entry; -+} BlockReopenQueueEntry; -+ -+/* -+ * Return the flags that @bs will have after the reopens in @q have -+ * successfully completed. If @q is NULL (or @bs is not contained in @q), -+ * return the current flags. -+ */ -+static int bdrv_reopen_get_flags(BlockReopenQueue *q, BlockDriverState *bs) -+{ -+ BlockReopenQueueEntry *entry; -+ -+ if (q != NULL) { -+ QSIMPLEQ_FOREACH(entry, q, entry) { -+ if (entry->state.bs == bs) { -+ return entry->state.flags; -+ } -+ } -+ } -+ -+ return bs->open_flags; -+} -+ -+/* Returns whether the image file can be written to after the reopen queue @q -+ * has been successfully applied, or right now if @q is NULL. */ -+static bool bdrv_is_writable(BlockDriverState *bs, BlockReopenQueue *q) -+{ -+ int flags = bdrv_reopen_get_flags(q, bs); -+ -+ return (flags & (BDRV_O_RDWR | BDRV_O_INACTIVE)) == BDRV_O_RDWR; -+} -+ - static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs, - BdrvChild *c, const BdrvChildRole *role, - BlockReopenQueue *reopen_queue, -@@ -1572,7 +1601,7 @@ static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q, - - /* Write permissions never work with read-only images */ - if ((cumulative_perms & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)) && -- !bdrv_is_writable(bs)) -+ !bdrv_is_writable(bs, q)) - { - error_setg(errp, "Block node is read-only"); - return -EPERM; -@@ -1862,8 +1891,7 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, - &perm, &shared); - - /* Format drivers may touch metadata even if the guest doesn't write */ -- /* TODO Take flags from reopen_queue */ -- if (bdrv_is_writable(bs)) { -+ if (bdrv_is_writable(bs, reopen_queue)) { - perm |= BLK_PERM_WRITE | BLK_PERM_RESIZE; - } - -@@ -2641,12 +2669,6 @@ BlockDriverState *bdrv_open(const char *filename, const char *reference, - NULL, errp); - } - --typedef struct BlockReopenQueueEntry { -- bool prepared; -- BDRVReopenState state; -- QSIMPLEQ_ENTRY(BlockReopenQueueEntry) entry; --} BlockReopenQueueEntry; -- - /* - * Adds a BlockDriverState to a simple queue for an atomic, transactional - * reopen of multiple devices. -diff --git a/include/block/block.h b/include/block/block.h -index ab80195..4d0d2da 100644 ---- a/include/block/block.h -+++ b/include/block/block.h -@@ -435,7 +435,6 @@ int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base, - int64_t offset, int64_t bytes, int64_t *pnum); - - bool bdrv_is_read_only(BlockDriverState *bs); --bool bdrv_is_writable(BlockDriverState *bs); - int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only, - bool ignore_allow_rdw, Error **errp); - int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp); --- -1.8.3.1 - diff --git a/SOURCES/kvm-block-Cancel-job-in-bdrv_close_all-callers.patch b/SOURCES/kvm-block-Cancel-job-in-bdrv_close_all-callers.patch new file mode 100644 index 0000000..1c03077 --- /dev/null +++ b/SOURCES/kvm-block-Cancel-job-in-bdrv_close_all-callers.patch @@ -0,0 +1,85 @@ +From 7ea7ac78a4d38bc1873df660406b25949515cf07 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:24 +0200 +Subject: [PATCH 55/89] block: Cancel job in bdrv_close_all() callers + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-42-kwolf@redhat.com> +Patchwork-id: 81098 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 41/73] block: Cancel job in bdrv_close_all() callers +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +Now that we cancel all jobs and not only block jobs on shutdown, doing +that in bdrv_close_all() isn't really appropriate any more. Move the +job_cancel_sync_all() call to the callers, and only assert that there +are no job running in bdrv_close_all(). + +Signed-off-by: Kevin Wolf +(cherry picked from commit b3b5299d58bce4366c647af40374e6b063f371eb) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block.c | 4 +--- + qemu-nbd.c | 8 +++++++- + vl.c | 1 + + 3 files changed, 9 insertions(+), 4 deletions(-) + +diff --git a/block.c b/block.c +index a83787f..afe30ca 100644 +--- a/block.c ++++ b/block.c +@@ -3374,9 +3374,7 @@ static void bdrv_close(BlockDriverState *bs) + + void bdrv_close_all(void) + { +- /* TODO We do want to cancel all jobs instead of just block jobs on +- * shutdown, but bdrv_close_all() isn't the right place any more. */ +- job_cancel_sync_all(); ++ assert(job_next(NULL) == NULL); + nbd_export_close_all(); + + /* Drop references from requests still in flight, such as canceled block +diff --git a/qemu-nbd.c b/qemu-nbd.c +index 0af0560..51b9d38 100644 +--- a/qemu-nbd.c ++++ b/qemu-nbd.c +@@ -482,6 +482,12 @@ static const char *socket_activation_validate_opts(const char *device, + return NULL; + } + ++static void qemu_nbd_shutdown(void) ++{ ++ job_cancel_sync_all(); ++ bdrv_close_all(); ++} ++ + int main(int argc, char **argv) + { + BlockBackend *blk; +@@ -928,7 +934,7 @@ int main(int argc, char **argv) + exit(EXIT_FAILURE); + } + bdrv_init(); +- atexit(bdrv_close_all); ++ atexit(qemu_nbd_shutdown); + + srcpath = argv[optind]; + if (imageOpts) { +diff --git a/vl.c b/vl.c +index f3acab3..713f899 100644 +--- a/vl.c ++++ b/vl.c +@@ -4772,6 +4772,7 @@ int main(int argc, char **argv, char **envp) + /* No more vcpu or device emulation activity beyond this point */ + vm_shutdown(); + ++ job_cancel_sync_all(); + bdrv_close_all(); + + res_free(); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Check-for-inserted-BlockDriverState-in-blk_io_.patch b/SOURCES/kvm-block-Check-for-inserted-BlockDriverState-in-blk_io_.patch deleted file mode 100644 index 766e307..0000000 --- a/SOURCES/kvm-block-Check-for-inserted-BlockDriverState-in-blk_io_.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 20f05f7cc0ae81aecad40e5c3c69d9c91d6d3687 Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Fri, 17 Nov 2017 11:19:05 +0100 -Subject: [PATCH 06/15] block: Check for inserted BlockDriverState in - blk_io_limits_disable() - -RH-Author: Stefan Hajnoczi -Message-id: <20171117111908.8815-7-stefanha@redhat.com> -Patchwork-id: 77741 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 6/9] block: Check for inserted BlockDriverState in blk_io_limits_disable() -Bugzilla: 1492295 -RH-Acked-by: John Snow -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth - -From: Alberto Garcia - -When you set I/O limits using block_set_io_throttle or the command -line throttling.* options they are kept in the BlockBackend regardless -of whether a BlockDriverState is attached to the backend or not. - -Therefore when removing the limits using blk_io_limits_disable() we -need to check if there's a BDS before attempting to drain it, else it -will crash QEMU. This can be reproduced very easily using HMP: - - (qemu) drive_add 0 if=none,throttling.iops-total=5000 - (qemu) drive_del none0 - -Reported-by: sochin jiang -Signed-off-by: Alberto Garcia -Reviewed-by: Max Reitz -Message-id: 0d3a67ce8d948bb33e08672564714dcfb76a3d8c.1510339534.git.berto@igalia.com -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit 48bf7ea81aa848027bad24f7e7791b503dff727d) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - block/block-backend.c | 14 ++++++++++---- - 1 file changed, 10 insertions(+), 4 deletions(-) - -diff --git a/block/block-backend.c b/block/block-backend.c -index 520f2b2..0bd439e 100644 ---- a/block/block-backend.c -+++ b/block/block-backend.c -@@ -1999,10 +1999,16 @@ void blk_set_io_limits(BlockBackend *blk, ThrottleConfig *cfg) - - void blk_io_limits_disable(BlockBackend *blk) - { -- assert(blk->public.throttle_group_member.throttle_state); -- bdrv_drained_begin(blk_bs(blk)); -- throttle_group_unregister_tgm(&blk->public.throttle_group_member); -- bdrv_drained_end(blk_bs(blk)); -+ BlockDriverState *bs = blk_bs(blk); -+ ThrottleGroupMember *tgm = &blk->public.throttle_group_member; -+ assert(tgm->throttle_state); -+ if (bs) { -+ bdrv_drained_begin(bs); -+ } -+ throttle_group_unregister_tgm(tgm); -+ if (bs) { -+ bdrv_drained_end(bs); -+ } - } - - /* should be called before blk_set_io_limits if a limit is set */ --- -1.8.3.1 - diff --git a/SOURCES/kvm-block-Clean-up-a-misuse-of-qobject_to-in-.bdrv_co_cr.patch b/SOURCES/kvm-block-Clean-up-a-misuse-of-qobject_to-in-.bdrv_co_cr.patch new file mode 100644 index 0000000..2e35356 --- /dev/null +++ b/SOURCES/kvm-block-Clean-up-a-misuse-of-qobject_to-in-.bdrv_co_cr.patch @@ -0,0 +1,241 @@ +From 48749c03c412fa59ca643bbd4defd341903c33c1 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Mon, 18 Jun 2018 08:43:19 +0200 +Subject: [PATCH 12/54] block: Clean up a misuse of qobject_to() in + .bdrv_co_create_opts() + +RH-Author: Markus Armbruster +Message-id: <20180618084330.30009-13-armbru@redhat.com> +Patchwork-id: 80733 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 12/23] block: Clean up a misuse of qobject_to() in .bdrv_co_create_opts() +Bugzilla: 1557995 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +The following pattern occurs in the .bdrv_co_create_opts() methods of +parallels, qcow, qcow2, qed, vhdx and vpc: + + qobj = qdict_crumple_for_keyval_qiv(qdict, errp); + qobject_unref(qdict); + qdict = qobject_to(QDict, qobj); + if (qdict == NULL) { + ret = -EINVAL; + goto done; + } + + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); + [...] + ret = 0; +done: + qobject_unref(qdict); + [...] + return ret; + +If qobject_to() fails, we return failure without setting errp. That's +wrong. As far as I can tell, it cannot fail here. Clean it up +anyway, by removing the useless conversion. + +Signed-off-by: Markus Armbruster +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit 92adf9dbcd3cf9cedddae995b04a99f5c42ae08c) +Signed-off-by: Miroslav Rezanina +--- + block/parallels.c | 9 ++++----- + block/qcow.c | 9 ++++----- + block/qcow2.c | 9 ++++----- + block/qed.c | 9 ++++----- + block/vhdx.c | 9 ++++----- + block/vpc.c | 9 ++++----- + 6 files changed, 24 insertions(+), 30 deletions(-) + +diff --git a/block/parallels.c b/block/parallels.c +index aa58955..1c96c39 100644 +--- a/block/parallels.c ++++ b/block/parallels.c +@@ -614,7 +614,7 @@ static int coroutine_fn parallels_co_create_opts(const char *filename, + BlockdevCreateOptions *create_options = NULL; + Error *local_err = NULL; + BlockDriverState *bs = NULL; +- QDict *qdict = NULL; ++ QDict *qdict; + QObject *qobj; + Visitor *v; + int ret; +@@ -652,14 +652,13 @@ static int coroutine_fn parallels_co_create_opts(const char *filename, + qdict_put_str(qdict, "file", bs->node_name); + + qobj = qdict_crumple_for_keyval_qiv(qdict, errp); +- qobject_unref(qdict); +- qdict = qobject_to(QDict, qobj); +- if (qdict == NULL) { ++ if (!qobj) { + ret = -EINVAL; + goto done; + } + +- v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); ++ v = qobject_input_visitor_new_keyval(qobj); ++ qobject_unref(qobj); + visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err); + visit_free(v); + +diff --git a/block/qcow.c b/block/qcow.c +index 14b7296..43a595a 100644 +--- a/block/qcow.c ++++ b/block/qcow.c +@@ -944,7 +944,7 @@ static int coroutine_fn qcow_co_create_opts(const char *filename, + { + BlockdevCreateOptions *create_options = NULL; + BlockDriverState *bs = NULL; +- QDict *qdict = NULL; ++ QDict *qdict; + QObject *qobj; + Visitor *v; + const char *val; +@@ -996,14 +996,13 @@ static int coroutine_fn qcow_co_create_opts(const char *filename, + qdict_put_str(qdict, "file", bs->node_name); + + qobj = qdict_crumple_for_keyval_qiv(qdict, errp); +- qobject_unref(qdict); +- qdict = qobject_to(QDict, qobj); +- if (qdict == NULL) { ++ if (!qobj) { + ret = -EINVAL; + goto fail; + } + +- v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); ++ v = qobject_input_visitor_new_keyval(qobj); ++ qobject_unref(qobj); + visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err); + visit_free(v); + +diff --git a/block/qcow2.c b/block/qcow2.c +index fa06b41..ede52a8 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -3067,7 +3067,7 @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt + Error **errp) + { + BlockdevCreateOptions *create_options = NULL; +- QDict *qdict = NULL; ++ QDict *qdict; + QObject *qobj; + Visitor *v; + BlockDriverState *bs = NULL; +@@ -3140,14 +3140,13 @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt + + /* Now get the QAPI type BlockdevCreateOptions */ + qobj = qdict_crumple_for_keyval_qiv(qdict, errp); +- qobject_unref(qdict); +- qdict = qobject_to(QDict, qobj); +- if (qdict == NULL) { ++ if (!qobj) { + ret = -EINVAL; + goto finish; + } + +- v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); ++ v = qobject_input_visitor_new_keyval(qobj); ++ qobject_unref(qobj); + visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err); + visit_free(v); + +diff --git a/block/qed.c b/block/qed.c +index d8810f5..3818888 100644 +--- a/block/qed.c ++++ b/block/qed.c +@@ -722,7 +722,7 @@ static int coroutine_fn bdrv_qed_co_create_opts(const char *filename, + Error **errp) + { + BlockdevCreateOptions *create_options = NULL; +- QDict *qdict = NULL; ++ QDict *qdict; + QObject *qobj; + Visitor *v; + BlockDriverState *bs = NULL; +@@ -764,14 +764,13 @@ static int coroutine_fn bdrv_qed_co_create_opts(const char *filename, + qdict_put_str(qdict, "file", bs->node_name); + + qobj = qdict_crumple_for_keyval_qiv(qdict, errp); +- qobject_unref(qdict); +- qdict = qobject_to(QDict, qobj); +- if (qdict == NULL) { ++ if (!qobj) { + ret = -EINVAL; + goto fail; + } + +- v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); ++ v = qobject_input_visitor_new_keyval(qobj); ++ qobject_unref(qobj); + visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err); + visit_free(v); + +diff --git a/block/vhdx.c b/block/vhdx.c +index 32939c4..728d8b3 100644 +--- a/block/vhdx.c ++++ b/block/vhdx.c +@@ -1963,7 +1963,7 @@ static int coroutine_fn vhdx_co_create_opts(const char *filename, + Error **errp) + { + BlockdevCreateOptions *create_options = NULL; +- QDict *qdict = NULL; ++ QDict *qdict; + QObject *qobj; + Visitor *v; + BlockDriverState *bs = NULL; +@@ -2004,14 +2004,13 @@ static int coroutine_fn vhdx_co_create_opts(const char *filename, + qdict_put_str(qdict, "file", bs->node_name); + + qobj = qdict_crumple_for_keyval_qiv(qdict, errp); +- qobject_unref(qdict); +- qdict = qobject_to(QDict, qobj); +- if (qdict == NULL) { ++ if (!qobj) { + ret = -EINVAL; + goto fail; + } + +- v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); ++ v = qobject_input_visitor_new_keyval(qobj); ++ qobject_unref(qobj); + visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err); + visit_free(v); + +diff --git a/block/vpc.c b/block/vpc.c +index 16178e5..a9bb041 100644 +--- a/block/vpc.c ++++ b/block/vpc.c +@@ -1081,7 +1081,7 @@ static int coroutine_fn vpc_co_create_opts(const char *filename, + QemuOpts *opts, Error **errp) + { + BlockdevCreateOptions *create_options = NULL; +- QDict *qdict = NULL; ++ QDict *qdict; + QObject *qobj; + Visitor *v; + BlockDriverState *bs = NULL; +@@ -1120,14 +1120,13 @@ static int coroutine_fn vpc_co_create_opts(const char *filename, + qdict_put_str(qdict, "file", bs->node_name); + + qobj = qdict_crumple_for_keyval_qiv(qdict, errp); +- qobject_unref(qdict); +- qdict = qobject_to(QDict, qobj); +- if (qdict == NULL) { ++ if (!qobj) { + ret = -EINVAL; + goto fail; + } + +- v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); ++ v = qobject_input_visitor_new_keyval(qobj); ++ qobject_unref(qobj); + visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err); + visit_free(v); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Convert-.bdrv_truncate-callback-to-coroutine_f.patch b/SOURCES/kvm-block-Convert-.bdrv_truncate-callback-to-coroutine_f.patch new file mode 100644 index 0000000..8860ef9 --- /dev/null +++ b/SOURCES/kvm-block-Convert-.bdrv_truncate-callback-to-coroutine_f.patch @@ -0,0 +1,865 @@ +From c557973bf44fa50d5ef2334a2179546698a9bbf0 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Thu, 12 Jul 2018 14:42:54 +0200 +Subject: [PATCH 35/89] block: Convert .bdrv_truncate callback to coroutine_fn + +RH-Author: Kevin Wolf +Message-id: <20180712144258.17303-3-kwolf@redhat.com> +Patchwork-id: 81327 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 2/6] block: Convert .bdrv_truncate callback to coroutine_fn +Bugzilla: 1595173 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: John Snow + +bdrv_truncate() is an operation that can block (even for a quite long +time, depending on the PreallocMode) in I/O paths that shouldn't block. +Convert it to a coroutine_fn so that we have the infrastructure for +drivers to make their .bdrv_co_truncate implementation asynchronous. + +This change could potentially introduce new race conditions because +bdrv_truncate() isn't necessarily executed atomically any more. Whether +this is a problem needs to be evaluated for each block driver that +supports truncate: + +* file-posix/win32, gluster, iscsi, nfs, rbd, ssh, sheepdog: The + protocol drivers are trivially safe because they don't actually yield + yet, so there is no change in behaviour. + +* copy-on-read, crypto, raw-format: Essentially just filter drivers that + pass the request to a child node, no problem. + +* qcow2: The implementation modifies metadata, so it needs to hold + s->lock to be safe with concurrent I/O requests. In order to avoid + double locking, this requires pulling the locking out into + preallocate_co() and using qcow2_write_caches() instead of + bdrv_flush(). + +* qed: Does a single header update, this is fine without locking. + +Signed-off-by: Kevin Wolf +Reviewed-by: Stefan Hajnoczi +(cherry picked from commit 061ca8a368165fae300748c17971824a089f521f) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block.c | 63 +++++++++++++++++++++++++++++++++++----- + block/copy-on-read.c | 8 ++--- + block/crypto.c | 9 +++--- + block/file-posix.c | 12 ++++---- + block/file-win32.c | 6 ++-- + block/gluster.c | 14 +++++---- + block/iscsi.c | 8 ++--- + block/nfs.c | 7 +++-- + block/qcow2.c | 74 ++++++++++++++++++++++++++++------------------- + block/qed.c | 8 +++-- + block/raw-format.c | 8 ++--- + block/rbd.c | 8 +++-- + block/sheepdog.c | 12 ++++---- + block/ssh.c | 6 ++-- + include/block/block.h | 4 +++ + include/block/block_int.h | 4 +-- + 16 files changed, 162 insertions(+), 89 deletions(-) + +diff --git a/block.c b/block.c +index 0516284..0af08ca 100644 +--- a/block.c ++++ b/block.c +@@ -3738,8 +3738,8 @@ exit: + /** + * Truncate file to 'offset' bytes (needed only for file protocols) + */ +-int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc, +- Error **errp) ++int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, ++ PreallocMode prealloc, Error **errp) + { + BlockDriverState *bs = child->bs; + BlockDriver *drv = bs->drv; +@@ -3757,23 +3757,28 @@ int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc, + return -EINVAL; + } + +- if (!drv->bdrv_truncate) { ++ bdrv_inc_in_flight(bs); ++ ++ if (!drv->bdrv_co_truncate) { + if (bs->file && drv->is_filter) { +- return bdrv_truncate(bs->file, offset, prealloc, errp); ++ ret = bdrv_co_truncate(bs->file, offset, prealloc, errp); ++ goto out; + } + error_setg(errp, "Image format driver does not support resize"); +- return -ENOTSUP; ++ ret = -ENOTSUP; ++ goto out; + } + if (bs->read_only) { + error_setg(errp, "Image is read-only"); +- return -EACCES; ++ ret = -EACCES; ++ goto out; + } + + assert(!(bs->open_flags & BDRV_O_INACTIVE)); + +- ret = drv->bdrv_truncate(bs, offset, prealloc, errp); ++ ret = drv->bdrv_co_truncate(bs, offset, prealloc, errp); + if (ret < 0) { +- return ret; ++ goto out; + } + ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS); + if (ret < 0) { +@@ -3784,9 +3789,51 @@ int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc, + bdrv_dirty_bitmap_truncate(bs, offset); + bdrv_parent_cb_resize(bs); + atomic_inc(&bs->write_gen); ++ ++out: ++ bdrv_dec_in_flight(bs); + return ret; + } + ++typedef struct TruncateCo { ++ BdrvChild *child; ++ int64_t offset; ++ PreallocMode prealloc; ++ Error **errp; ++ int ret; ++} TruncateCo; ++ ++static void coroutine_fn bdrv_truncate_co_entry(void *opaque) ++{ ++ TruncateCo *tco = opaque; ++ tco->ret = bdrv_co_truncate(tco->child, tco->offset, tco->prealloc, ++ tco->errp); ++} ++ ++int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc, ++ Error **errp) ++{ ++ Coroutine *co; ++ TruncateCo tco = { ++ .child = child, ++ .offset = offset, ++ .prealloc = prealloc, ++ .errp = errp, ++ .ret = NOT_DONE, ++ }; ++ ++ if (qemu_in_coroutine()) { ++ /* Fast-path if already in coroutine context */ ++ bdrv_truncate_co_entry(&tco); ++ } else { ++ co = qemu_coroutine_create(bdrv_truncate_co_entry, &tco); ++ qemu_coroutine_enter(co); ++ BDRV_POLL_WHILE(child->bs, tco.ret == NOT_DONE); ++ } ++ ++ return tco.ret; ++} ++ + /** + * Length of a allocated file in bytes. Sparse files are counted by actual + * allocated space. Return < 0 if error or unknown. +diff --git a/block/copy-on-read.c b/block/copy-on-read.c +index 6a97208..1dcdaee 100644 +--- a/block/copy-on-read.c ++++ b/block/copy-on-read.c +@@ -80,10 +80,10 @@ static int64_t cor_getlength(BlockDriverState *bs) + } + + +-static int cor_truncate(BlockDriverState *bs, int64_t offset, +- PreallocMode prealloc, Error **errp) ++static int coroutine_fn cor_co_truncate(BlockDriverState *bs, int64_t offset, ++ PreallocMode prealloc, Error **errp) + { +- return bdrv_truncate(bs->file, offset, prealloc, errp); ++ return bdrv_co_truncate(bs->file, offset, prealloc, errp); + } + + +@@ -147,7 +147,7 @@ BlockDriver bdrv_copy_on_read = { + .bdrv_child_perm = cor_child_perm, + + .bdrv_getlength = cor_getlength, +- .bdrv_truncate = cor_truncate, ++ .bdrv_co_truncate = cor_co_truncate, + + .bdrv_co_preadv = cor_co_preadv, + .bdrv_co_pwritev = cor_co_pwritev, +diff --git a/block/crypto.c b/block/crypto.c +index f5151f4..02f04f3 100644 +--- a/block/crypto.c ++++ b/block/crypto.c +@@ -357,8 +357,9 @@ static int block_crypto_co_create_generic(BlockDriverState *bs, + return ret; + } + +-static int block_crypto_truncate(BlockDriverState *bs, int64_t offset, +- PreallocMode prealloc, Error **errp) ++static int coroutine_fn ++block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, ++ PreallocMode prealloc, Error **errp) + { + BlockCrypto *crypto = bs->opaque; + uint64_t payload_offset = +@@ -371,7 +372,7 @@ static int block_crypto_truncate(BlockDriverState *bs, int64_t offset, + + offset += payload_offset; + +- return bdrv_truncate(bs->file, offset, prealloc, errp); ++ return bdrv_co_truncate(bs->file, offset, prealloc, errp); + } + + static void block_crypto_close(BlockDriverState *bs) +@@ -700,7 +701,7 @@ BlockDriver bdrv_crypto_luks = { + .bdrv_child_perm = bdrv_format_default_perms, + .bdrv_co_create = block_crypto_co_create_luks, + .bdrv_co_create_opts = block_crypto_co_create_opts_luks, +- .bdrv_truncate = block_crypto_truncate, ++ .bdrv_co_truncate = block_crypto_co_truncate, + .create_opts = &block_crypto_create_opts_luks, + + .bdrv_reopen_prepare = block_crypto_reopen_prepare, +diff --git a/block/file-posix.c b/block/file-posix.c +index cbf7c11..f8488ec 100644 +--- a/block/file-posix.c ++++ b/block/file-posix.c +@@ -1832,8 +1832,8 @@ out: + return result; + } + +-static int raw_truncate(BlockDriverState *bs, int64_t offset, +- PreallocMode prealloc, Error **errp) ++static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, ++ PreallocMode prealloc, Error **errp) + { + BDRVRawState *s = bs->opaque; + struct stat st; +@@ -2474,7 +2474,7 @@ BlockDriver bdrv_file = { + .bdrv_io_plug = raw_aio_plug, + .bdrv_io_unplug = raw_aio_unplug, + +- .bdrv_truncate = raw_truncate, ++ .bdrv_co_truncate = raw_co_truncate, + .bdrv_getlength = raw_getlength, + .bdrv_get_info = raw_get_info, + .bdrv_get_allocated_file_size +@@ -2953,7 +2953,7 @@ static BlockDriver bdrv_host_device = { + .bdrv_io_plug = raw_aio_plug, + .bdrv_io_unplug = raw_aio_unplug, + +- .bdrv_truncate = raw_truncate, ++ .bdrv_co_truncate = raw_co_truncate, + .bdrv_getlength = raw_getlength, + .bdrv_get_info = raw_get_info, + .bdrv_get_allocated_file_size +@@ -3074,7 +3074,7 @@ static BlockDriver bdrv_host_cdrom = { + .bdrv_io_plug = raw_aio_plug, + .bdrv_io_unplug = raw_aio_unplug, + +- .bdrv_truncate = raw_truncate, ++ .bdrv_co_truncate = raw_co_truncate, + .bdrv_getlength = raw_getlength, + .has_variable_length = true, + .bdrv_get_allocated_file_size +@@ -3204,7 +3204,7 @@ static BlockDriver bdrv_host_cdrom = { + .bdrv_io_plug = raw_aio_plug, + .bdrv_io_unplug = raw_aio_unplug, + +- .bdrv_truncate = raw_truncate, ++ .bdrv_co_truncate = raw_co_truncate, + .bdrv_getlength = raw_getlength, + .has_variable_length = true, + .bdrv_get_allocated_file_size +diff --git a/block/file-win32.c b/block/file-win32.c +index 2e2f746..6573338 100644 +--- a/block/file-win32.c ++++ b/block/file-win32.c +@@ -463,8 +463,8 @@ static void raw_close(BlockDriverState *bs) + } + } + +-static int raw_truncate(BlockDriverState *bs, int64_t offset, +- PreallocMode prealloc, Error **errp) ++static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, ++ PreallocMode prealloc, Error **errp) + { + BDRVRawState *s = bs->opaque; + LONG low, high; +@@ -636,7 +636,7 @@ BlockDriver bdrv_file = { + .bdrv_aio_writev = raw_aio_writev, + .bdrv_aio_flush = raw_aio_flush, + +- .bdrv_truncate = raw_truncate, ++ .bdrv_co_truncate = raw_co_truncate, + .bdrv_getlength = raw_getlength, + .bdrv_get_allocated_file_size + = raw_get_allocated_file_size, +diff --git a/block/gluster.c b/block/gluster.c +index 418bb73..cecfe09 100644 +--- a/block/gluster.c ++++ b/block/gluster.c +@@ -1177,8 +1177,10 @@ static coroutine_fn int qemu_gluster_co_rw(BlockDriverState *bs, + return acb.ret; + } + +-static int qemu_gluster_truncate(BlockDriverState *bs, int64_t offset, +- PreallocMode prealloc, Error **errp) ++static coroutine_fn int qemu_gluster_co_truncate(BlockDriverState *bs, ++ int64_t offset, ++ PreallocMode prealloc, ++ Error **errp) + { + BDRVGlusterState *s = bs->opaque; + return qemu_gluster_do_truncate(s->fd, offset, prealloc, errp); +@@ -1497,7 +1499,7 @@ static BlockDriver bdrv_gluster = { + .bdrv_co_create_opts = qemu_gluster_co_create_opts, + .bdrv_getlength = qemu_gluster_getlength, + .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size, +- .bdrv_truncate = qemu_gluster_truncate, ++ .bdrv_co_truncate = qemu_gluster_co_truncate, + .bdrv_co_readv = qemu_gluster_co_readv, + .bdrv_co_writev = qemu_gluster_co_writev, + .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk, +@@ -1526,7 +1528,7 @@ static BlockDriver bdrv_gluster_tcp = { + .bdrv_co_create_opts = qemu_gluster_co_create_opts, + .bdrv_getlength = qemu_gluster_getlength, + .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size, +- .bdrv_truncate = qemu_gluster_truncate, ++ .bdrv_co_truncate = qemu_gluster_co_truncate, + .bdrv_co_readv = qemu_gluster_co_readv, + .bdrv_co_writev = qemu_gluster_co_writev, + .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk, +@@ -1555,7 +1557,7 @@ static BlockDriver bdrv_gluster_unix = { + .bdrv_co_create_opts = qemu_gluster_co_create_opts, + .bdrv_getlength = qemu_gluster_getlength, + .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size, +- .bdrv_truncate = qemu_gluster_truncate, ++ .bdrv_co_truncate = qemu_gluster_co_truncate, + .bdrv_co_readv = qemu_gluster_co_readv, + .bdrv_co_writev = qemu_gluster_co_writev, + .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk, +@@ -1590,7 +1592,7 @@ static BlockDriver bdrv_gluster_rdma = { + .bdrv_co_create_opts = qemu_gluster_co_create_opts, + .bdrv_getlength = qemu_gluster_getlength, + .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size, +- .bdrv_truncate = qemu_gluster_truncate, ++ .bdrv_co_truncate = qemu_gluster_co_truncate, + .bdrv_co_readv = qemu_gluster_co_readv, + .bdrv_co_writev = qemu_gluster_co_writev, + .bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk, +diff --git a/block/iscsi.c b/block/iscsi.c +index 751884d..5047e83 100644 +--- a/block/iscsi.c ++++ b/block/iscsi.c +@@ -2085,8 +2085,8 @@ static void iscsi_reopen_commit(BDRVReopenState *reopen_state) + } + } + +-static int iscsi_truncate(BlockDriverState *bs, int64_t offset, +- PreallocMode prealloc, Error **errp) ++static int coroutine_fn iscsi_co_truncate(BlockDriverState *bs, int64_t offset, ++ PreallocMode prealloc, Error **errp) + { + IscsiLun *iscsilun = bs->opaque; + Error *local_err = NULL; +@@ -2431,7 +2431,7 @@ static BlockDriver bdrv_iscsi = { + + .bdrv_getlength = iscsi_getlength, + .bdrv_get_info = iscsi_get_info, +- .bdrv_truncate = iscsi_truncate, ++ .bdrv_co_truncate = iscsi_co_truncate, + .bdrv_refresh_limits = iscsi_refresh_limits, + + .bdrv_co_block_status = iscsi_co_block_status, +@@ -2468,7 +2468,7 @@ static BlockDriver bdrv_iser = { + + .bdrv_getlength = iscsi_getlength, + .bdrv_get_info = iscsi_get_info, +- .bdrv_truncate = iscsi_truncate, ++ .bdrv_co_truncate = iscsi_co_truncate, + .bdrv_refresh_limits = iscsi_refresh_limits, + + .bdrv_co_block_status = iscsi_co_block_status, +diff --git a/block/nfs.c b/block/nfs.c +index 743ca04..eab1a2c 100644 +--- a/block/nfs.c ++++ b/block/nfs.c +@@ -743,8 +743,9 @@ static int64_t nfs_get_allocated_file_size(BlockDriverState *bs) + return (task.ret < 0 ? task.ret : st.st_blocks * 512); + } + +-static int nfs_file_truncate(BlockDriverState *bs, int64_t offset, +- PreallocMode prealloc, Error **errp) ++static int coroutine_fn ++nfs_file_co_truncate(BlockDriverState *bs, int64_t offset, ++ PreallocMode prealloc, Error **errp) + { + NFSClient *client = bs->opaque; + int ret; +@@ -873,7 +874,7 @@ static BlockDriver bdrv_nfs = { + + .bdrv_has_zero_init = nfs_has_zero_init, + .bdrv_get_allocated_file_size = nfs_get_allocated_file_size, +- .bdrv_truncate = nfs_file_truncate, ++ .bdrv_co_truncate = nfs_file_co_truncate, + + .bdrv_file_open = nfs_file_open, + .bdrv_close = nfs_file_close, +diff --git a/block/qcow2.c b/block/qcow2.c +index dbd448c..c5c6ae9 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -2539,15 +2539,12 @@ static void coroutine_fn preallocate_co(void *opaque) + BlockDriverState *bs = params->bs; + uint64_t offset = params->offset; + uint64_t new_length = params->new_length; +- BDRVQcow2State *s = bs->opaque; + uint64_t bytes; + uint64_t host_offset = 0; + unsigned int cur_bytes; + int ret; + QCowL2Meta *meta; + +- qemu_co_mutex_lock(&s->lock); +- + assert(offset <= new_length); + bytes = new_length - offset; + +@@ -2600,7 +2597,6 @@ static void coroutine_fn preallocate_co(void *opaque) + ret = 0; + + done: +- qemu_co_mutex_unlock(&s->lock); + params->ret = ret; + } + +@@ -3037,7 +3033,11 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) + + /* And if we're supposed to preallocate metadata, do that now */ + if (qcow2_opts->preallocation != PREALLOC_MODE_OFF) { ++ BDRVQcow2State *s = blk_bs(blk)->opaque; ++ qemu_co_mutex_lock(&s->lock); + ret = preallocate(blk_bs(blk), 0, qcow2_opts->size); ++ qemu_co_mutex_unlock(&s->lock); ++ + if (ret < 0) { + error_setg_errno(errp, -ret, "Could not preallocate metadata"); + goto out; +@@ -3434,8 +3434,8 @@ fail: + return ret; + } + +-static int qcow2_truncate(BlockDriverState *bs, int64_t offset, +- PreallocMode prealloc, Error **errp) ++static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, ++ PreallocMode prealloc, Error **errp) + { + BDRVQcow2State *s = bs->opaque; + uint64_t old_length; +@@ -3455,17 +3455,21 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, + return -EINVAL; + } + ++ qemu_co_mutex_lock(&s->lock); ++ + /* cannot proceed if image has snapshots */ + if (s->nb_snapshots) { + error_setg(errp, "Can't resize an image which has snapshots"); +- return -ENOTSUP; ++ ret = -ENOTSUP; ++ goto fail; + } + + /* cannot proceed if image has bitmaps */ + if (s->nb_bitmaps) { + /* TODO: resize bitmaps in the image */ + error_setg(errp, "Can't resize an image which has bitmaps"); +- return -ENOTSUP; ++ ret = -ENOTSUP; ++ goto fail; + } + + old_length = bs->total_sectors * 512; +@@ -3476,7 +3480,8 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, + if (prealloc != PREALLOC_MODE_OFF) { + error_setg(errp, + "Preallocation can't be used for shrinking an image"); +- return -EINVAL; ++ ret = -EINVAL; ++ goto fail; + } + + ret = qcow2_cluster_discard(bs, ROUND_UP(offset, s->cluster_size), +@@ -3485,40 +3490,42 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, + QCOW2_DISCARD_ALWAYS, true); + if (ret < 0) { + error_setg_errno(errp, -ret, "Failed to discard cropped clusters"); +- return ret; ++ goto fail; + } + + ret = qcow2_shrink_l1_table(bs, new_l1_size); + if (ret < 0) { + error_setg_errno(errp, -ret, + "Failed to reduce the number of L2 tables"); +- return ret; ++ goto fail; + } + + ret = qcow2_shrink_reftable(bs); + if (ret < 0) { + error_setg_errno(errp, -ret, + "Failed to discard unused refblocks"); +- return ret; ++ goto fail; + } + + old_file_size = bdrv_getlength(bs->file->bs); + if (old_file_size < 0) { + error_setg_errno(errp, -old_file_size, + "Failed to inquire current file length"); +- return old_file_size; ++ ret = old_file_size; ++ goto fail; + } + last_cluster = qcow2_get_last_cluster(bs, old_file_size); + if (last_cluster < 0) { + error_setg_errno(errp, -last_cluster, + "Failed to find the last cluster"); +- return last_cluster; ++ ret = last_cluster; ++ goto fail; + } + if ((last_cluster + 1) * s->cluster_size < old_file_size) { + Error *local_err = NULL; + +- bdrv_truncate(bs->file, (last_cluster + 1) * s->cluster_size, +- PREALLOC_MODE_OFF, &local_err); ++ bdrv_co_truncate(bs->file, (last_cluster + 1) * s->cluster_size, ++ PREALLOC_MODE_OFF, &local_err); + if (local_err) { + warn_reportf_err(local_err, + "Failed to truncate the tail of the image: "); +@@ -3528,7 +3535,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, + ret = qcow2_grow_l1_table(bs, new_l1_size, true); + if (ret < 0) { + error_setg_errno(errp, -ret, "Failed to grow the L1 table"); +- return ret; ++ goto fail; + } + } + +@@ -3540,7 +3547,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, + ret = preallocate(bs, old_length, offset); + if (ret < 0) { + error_setg_errno(errp, -ret, "Preallocation failed"); +- return ret; ++ goto fail; + } + break; + +@@ -3556,7 +3563,8 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, + if (old_file_size < 0) { + error_setg_errno(errp, -old_file_size, + "Failed to inquire current file length"); +- return old_file_size; ++ ret = old_file_size; ++ goto fail; + } + old_file_size = ROUND_UP(old_file_size, s->cluster_size); + +@@ -3586,7 +3594,8 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, + if (allocation_start < 0) { + error_setg_errno(errp, -allocation_start, + "Failed to resize refcount structures"); +- return allocation_start; ++ ret = allocation_start; ++ goto fail; + } + + clusters_allocated = qcow2_alloc_clusters_at(bs, allocation_start, +@@ -3594,7 +3603,8 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, + if (clusters_allocated < 0) { + error_setg_errno(errp, -clusters_allocated, + "Failed to allocate data clusters"); +- return clusters_allocated; ++ ret = clusters_allocated; ++ goto fail; + } + + assert(clusters_allocated == nb_new_data_clusters); +@@ -3602,13 +3612,13 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, + /* Allocate the data area */ + new_file_size = allocation_start + + nb_new_data_clusters * s->cluster_size; +- ret = bdrv_truncate(bs->file, new_file_size, prealloc, errp); ++ ret = bdrv_co_truncate(bs->file, new_file_size, prealloc, errp); + if (ret < 0) { + error_prepend(errp, "Failed to resize underlying file: "); + qcow2_free_clusters(bs, allocation_start, + nb_new_data_clusters * s->cluster_size, + QCOW2_DISCARD_OTHER); +- return ret; ++ goto fail; + } + + /* Create the necessary L2 entries */ +@@ -3631,7 +3641,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, + qcow2_free_clusters(bs, host_offset, + nb_new_data_clusters * s->cluster_size, + QCOW2_DISCARD_OTHER); +- return ret; ++ goto fail; + } + + guest_offset += nb_clusters * s->cluster_size; +@@ -3647,11 +3657,11 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, + + if (prealloc != PREALLOC_MODE_OFF) { + /* Flush metadata before actually changing the image size */ +- ret = bdrv_flush(bs); ++ ret = qcow2_write_caches(bs); + if (ret < 0) { + error_setg_errno(errp, -ret, + "Failed to flush the preallocated area to disk"); +- return ret; ++ goto fail; + } + } + +@@ -3661,11 +3671,14 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, + &offset, sizeof(uint64_t)); + if (ret < 0) { + error_setg_errno(errp, -ret, "Failed to update the image size"); +- return ret; ++ goto fail; + } + + s->l1_vm_state_index = new_l1_size; +- return 0; ++ ret = 0; ++fail: ++ qemu_co_mutex_unlock(&s->lock); ++ return ret; + } + + /* XXX: put compressed sectors first, then all the cluster aligned +@@ -3689,7 +3702,8 @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset, + if (cluster_offset < 0) { + return cluster_offset; + } +- return bdrv_truncate(bs->file, cluster_offset, PREALLOC_MODE_OFF, NULL); ++ return bdrv_co_truncate(bs->file, cluster_offset, PREALLOC_MODE_OFF, ++ NULL); + } + + if (offset_into_cluster(s, offset)) { +@@ -4694,7 +4708,7 @@ BlockDriver bdrv_qcow2 = { + .bdrv_co_pdiscard = qcow2_co_pdiscard, + .bdrv_co_copy_range_from = qcow2_co_copy_range_from, + .bdrv_co_copy_range_to = qcow2_co_copy_range_to, +- .bdrv_truncate = qcow2_truncate, ++ .bdrv_co_truncate = qcow2_co_truncate, + .bdrv_co_pwritev_compressed = qcow2_co_pwritev_compressed, + .bdrv_make_empty = qcow2_make_empty, + +diff --git a/block/qed.c b/block/qed.c +index 4c5d7e8..34cccea 100644 +--- a/block/qed.c ++++ b/block/qed.c +@@ -1466,8 +1466,10 @@ static int coroutine_fn bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs, + QED_AIOCB_WRITE | QED_AIOCB_ZERO); + } + +-static int bdrv_qed_truncate(BlockDriverState *bs, int64_t offset, +- PreallocMode prealloc, Error **errp) ++static int coroutine_fn bdrv_qed_co_truncate(BlockDriverState *bs, ++ int64_t offset, ++ PreallocMode prealloc, ++ Error **errp) + { + BDRVQEDState *s = bs->opaque; + uint64_t old_image_size; +@@ -1677,7 +1679,7 @@ static BlockDriver bdrv_qed = { + .bdrv_co_readv = bdrv_qed_co_readv, + .bdrv_co_writev = bdrv_qed_co_writev, + .bdrv_co_pwrite_zeroes = bdrv_qed_co_pwrite_zeroes, +- .bdrv_truncate = bdrv_qed_truncate, ++ .bdrv_co_truncate = bdrv_qed_co_truncate, + .bdrv_getlength = bdrv_qed_getlength, + .bdrv_get_info = bdrv_qed_get_info, + .bdrv_refresh_limits = bdrv_qed_refresh_limits, +diff --git a/block/raw-format.c b/block/raw-format.c +index f2e468d..b78da56 100644 +--- a/block/raw-format.c ++++ b/block/raw-format.c +@@ -366,8 +366,8 @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp) + } + } + +-static int raw_truncate(BlockDriverState *bs, int64_t offset, +- PreallocMode prealloc, Error **errp) ++static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, ++ PreallocMode prealloc, Error **errp) + { + BDRVRawState *s = bs->opaque; + +@@ -383,7 +383,7 @@ static int raw_truncate(BlockDriverState *bs, int64_t offset, + + s->size = offset; + offset += s->offset; +- return bdrv_truncate(bs->file, offset, prealloc, errp); ++ return bdrv_co_truncate(bs->file, offset, prealloc, errp); + } + + static void raw_eject(BlockDriverState *bs, bool eject_flag) +@@ -545,7 +545,7 @@ BlockDriver bdrv_raw = { + .bdrv_co_block_status = &raw_co_block_status, + .bdrv_co_copy_range_from = &raw_co_copy_range_from, + .bdrv_co_copy_range_to = &raw_co_copy_range_to, +- .bdrv_truncate = &raw_truncate, ++ .bdrv_co_truncate = &raw_co_truncate, + .bdrv_getlength = &raw_getlength, + .has_variable_length = true, + .bdrv_measure = &raw_measure, +diff --git a/block/rbd.c b/block/rbd.c +index 3242bcd..b93046b 100644 +--- a/block/rbd.c ++++ b/block/rbd.c +@@ -987,8 +987,10 @@ static int64_t qemu_rbd_getlength(BlockDriverState *bs) + return info.size; + } + +-static int qemu_rbd_truncate(BlockDriverState *bs, int64_t offset, +- PreallocMode prealloc, Error **errp) ++static int coroutine_fn qemu_rbd_co_truncate(BlockDriverState *bs, ++ int64_t offset, ++ PreallocMode prealloc, ++ Error **errp) + { + BDRVRBDState *s = bs->opaque; + int r; +@@ -1180,7 +1182,7 @@ static BlockDriver bdrv_rbd = { + .bdrv_get_info = qemu_rbd_getinfo, + .create_opts = &qemu_rbd_create_opts, + .bdrv_getlength = qemu_rbd_getlength, +- .bdrv_truncate = qemu_rbd_truncate, ++ .bdrv_co_truncate = qemu_rbd_co_truncate, + .protocol_name = "rbd", + + .bdrv_aio_readv = qemu_rbd_aio_readv, +diff --git a/block/sheepdog.c b/block/sheepdog.c +index 933880c..14165d3 100644 +--- a/block/sheepdog.c ++++ b/block/sheepdog.c +@@ -2294,8 +2294,8 @@ static int64_t sd_getlength(BlockDriverState *bs) + return s->inode.vdi_size; + } + +-static int sd_truncate(BlockDriverState *bs, int64_t offset, +- PreallocMode prealloc, Error **errp) ++static int coroutine_fn sd_co_truncate(BlockDriverState *bs, int64_t offset, ++ PreallocMode prealloc, Error **errp) + { + BDRVSheepdogState *s = bs->opaque; + int ret, fd; +@@ -2609,7 +2609,7 @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num, + BDRVSheepdogState *s = bs->opaque; + + if (offset > s->inode.vdi_size) { +- ret = sd_truncate(bs, offset, PREALLOC_MODE_OFF, NULL); ++ ret = sd_co_truncate(bs, offset, PREALLOC_MODE_OFF, NULL); + if (ret < 0) { + return ret; + } +@@ -3229,7 +3229,7 @@ static BlockDriver bdrv_sheepdog = { + .bdrv_has_zero_init = bdrv_has_zero_init_1, + .bdrv_getlength = sd_getlength, + .bdrv_get_allocated_file_size = sd_get_allocated_file_size, +- .bdrv_truncate = sd_truncate, ++ .bdrv_co_truncate = sd_co_truncate, + + .bdrv_co_readv = sd_co_readv, + .bdrv_co_writev = sd_co_writev, +@@ -3266,7 +3266,7 @@ static BlockDriver bdrv_sheepdog_tcp = { + .bdrv_has_zero_init = bdrv_has_zero_init_1, + .bdrv_getlength = sd_getlength, + .bdrv_get_allocated_file_size = sd_get_allocated_file_size, +- .bdrv_truncate = sd_truncate, ++ .bdrv_co_truncate = sd_co_truncate, + + .bdrv_co_readv = sd_co_readv, + .bdrv_co_writev = sd_co_writev, +@@ -3303,7 +3303,7 @@ static BlockDriver bdrv_sheepdog_unix = { + .bdrv_has_zero_init = bdrv_has_zero_init_1, + .bdrv_getlength = sd_getlength, + .bdrv_get_allocated_file_size = sd_get_allocated_file_size, +- .bdrv_truncate = sd_truncate, ++ .bdrv_co_truncate = sd_co_truncate, + + .bdrv_co_readv = sd_co_readv, + .bdrv_co_writev = sd_co_writev, +diff --git a/block/ssh.c b/block/ssh.c +index aab6996..6a55d82 100644 +--- a/block/ssh.c ++++ b/block/ssh.c +@@ -1241,8 +1241,8 @@ static int64_t ssh_getlength(BlockDriverState *bs) + return length; + } + +-static int ssh_truncate(BlockDriverState *bs, int64_t offset, +- PreallocMode prealloc, Error **errp) ++static int coroutine_fn ssh_co_truncate(BlockDriverState *bs, int64_t offset, ++ PreallocMode prealloc, Error **errp) + { + BDRVSSHState *s = bs->opaque; + +@@ -1277,7 +1277,7 @@ static BlockDriver bdrv_ssh = { + .bdrv_co_readv = ssh_co_readv, + .bdrv_co_writev = ssh_co_writev, + .bdrv_getlength = ssh_getlength, +- .bdrv_truncate = ssh_truncate, ++ .bdrv_co_truncate = ssh_co_truncate, + .bdrv_co_flush_to_disk = ssh_co_flush, + .create_opts = &ssh_create_opts, + }; +diff --git a/include/block/block.h b/include/block/block.h +index e677080..c3cfb40 100644 +--- a/include/block/block.h ++++ b/include/block/block.h +@@ -300,8 +300,12 @@ int coroutine_fn bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset, + BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs, + const char *backing_file); + void bdrv_refresh_filename(BlockDriverState *bs); ++ ++int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, ++ PreallocMode prealloc, Error **errp); + int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc, + Error **errp); ++ + int64_t bdrv_nb_sectors(BlockDriverState *bs); + int64_t bdrv_getlength(BlockDriverState *bs); + int64_t bdrv_get_allocated_file_size(BlockDriverState *bs); +diff --git a/include/block/block_int.h b/include/block/block_int.h +index 3da86a7..46b2f87 100644 +--- a/include/block/block_int.h ++++ b/include/block/block_int.h +@@ -291,8 +291,8 @@ struct BlockDriver { + * bdrv_parse_filename. + */ + const char *protocol_name; +- int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset, +- PreallocMode prealloc, Error **errp); ++ int coroutine_fn (*bdrv_co_truncate)(BlockDriverState *bs, int64_t offset, ++ PreallocMode prealloc, Error **errp); + + int64_t (*bdrv_getlength)(BlockDriverState *bs); + bool has_variable_length; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Defer-.bdrv_drain_begin-callback-to-polling-ph.patch b/SOURCES/kvm-block-Defer-.bdrv_drain_begin-callback-to-polling-ph.patch new file mode 100644 index 0000000..3d25662 --- /dev/null +++ b/SOURCES/kvm-block-Defer-.bdrv_drain_begin-callback-to-polling-ph.patch @@ -0,0 +1,83 @@ +From 2e9423c192511fd2704eea357403f6817cb9aae7 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:12 +0200 +Subject: [PATCH 21/49] block: Defer .bdrv_drain_begin callback to polling + phase + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-15-kwolf@redhat.com> +Patchwork-id: 82166 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 14/42] block: Defer .bdrv_drain_begin callback to polling phase +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +We cannot allow aio_poll() in bdrv_drain_invoke(begin=true) until we're +done with propagating the drain through the graph and are doing the +single final BDRV_POLL_WHILE(). + +Just schedule the coroutine with the callback and increase bs->in_flight +to make sure that the polling phase will wait for it. + +Signed-off-by: Kevin Wolf +(cherry picked from commit 0109e7e6f83ae5166b81bbd9a4319d60be49985a) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/io.c | 28 +++++++++++++++++++++++----- + 1 file changed, 23 insertions(+), 5 deletions(-) + +diff --git a/block/io.c b/block/io.c +index 9c41ff9..23fe069 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -181,22 +181,40 @@ static void coroutine_fn bdrv_drain_invoke_entry(void *opaque) + + /* Set data->done before reading bs->wakeup. */ + atomic_mb_set(&data->done, true); +- bdrv_wakeup(bs); ++ bdrv_dec_in_flight(bs); ++ ++ if (data->begin) { ++ g_free(data); ++ } + } + + /* Recursively call BlockDriver.bdrv_co_drain_begin/end callbacks */ + static void bdrv_drain_invoke(BlockDriverState *bs, bool begin) + { +- BdrvCoDrainData data = { .bs = bs, .done = false, .begin = begin}; ++ BdrvCoDrainData *data; + + if (!bs->drv || (begin && !bs->drv->bdrv_co_drain_begin) || + (!begin && !bs->drv->bdrv_co_drain_end)) { + return; + } + +- data.co = qemu_coroutine_create(bdrv_drain_invoke_entry, &data); +- bdrv_coroutine_enter(bs, data.co); +- BDRV_POLL_WHILE(bs, !data.done); ++ data = g_new(BdrvCoDrainData, 1); ++ *data = (BdrvCoDrainData) { ++ .bs = bs, ++ .done = false, ++ .begin = begin ++ }; ++ ++ /* Make sure the driver callback completes during the polling phase for ++ * drain_begin. */ ++ bdrv_inc_in_flight(bs); ++ data->co = qemu_coroutine_create(bdrv_drain_invoke_entry, data); ++ aio_co_schedule(bdrv_get_aio_context(bs), data->co); ++ ++ if (!begin) { ++ BDRV_POLL_WHILE(bs, !data->done); ++ g_free(data); ++ } + } + + /* Returns true if BDRV_POLL_WHILE() should go into a blocking aio_poll() */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Don-t-manually-poll-in-bdrv_drain_all.patch b/SOURCES/kvm-block-Don-t-manually-poll-in-bdrv_drain_all.patch new file mode 100644 index 0000000..9f07da1 --- /dev/null +++ b/SOURCES/kvm-block-Don-t-manually-poll-in-bdrv_drain_all.patch @@ -0,0 +1,113 @@ +From 9006222a2f826c5760f305bbd879f1b7ce3563b6 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:02 +0200 +Subject: [PATCH 11/49] block: Don't manually poll in bdrv_drain_all() + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-5-kwolf@redhat.com> +Patchwork-id: 82157 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 04/42] block: Don't manually poll in bdrv_drain_all() +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +All involved nodes are already idle, we called bdrv_do_drain_begin() on +them. + +The comment in the code suggested that this was not correct because the +completion of a request on one node could spawn a new request on a +different node (which might have been drained before, so we wouldn't +drain the new request). In reality, new requests to different nodes +aren't spawned out of nothing, but only in the context of a parent +request, and they aren't submitted to random nodes, but only to child +nodes. As long as we still poll for the completion of the parent request +(which we do), draining each root node separately is good enough. + +Remove the additional polling code from bdrv_drain_all_begin() and +replace it with an assertion that all nodes are already idle after we +drained them separately. + +Signed-off-by: Kevin Wolf +Reviewed-by: Stefan Hajnoczi +(cherry picked from commit c13ad59f012cbbccb866a10477458e69bc868dbb) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/io.c | 41 ++++++++++++----------------------------- + 1 file changed, 12 insertions(+), 29 deletions(-) + +diff --git a/block/io.c b/block/io.c +index aa41f1e..e5fc42c 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -376,6 +376,16 @@ void bdrv_drain(BlockDriverState *bs) + bdrv_drained_end(bs); + } + ++static void bdrv_drain_assert_idle(BlockDriverState *bs) ++{ ++ BdrvChild *child, *next; ++ ++ assert(atomic_read(&bs->in_flight) == 0); ++ QLIST_FOREACH_SAFE(child, &bs->children, next, next) { ++ bdrv_drain_assert_idle(child->bs); ++ } ++} ++ + /* + * Wait for pending requests to complete across all BlockDriverStates + * +@@ -390,11 +400,8 @@ void bdrv_drain(BlockDriverState *bs) + */ + void bdrv_drain_all_begin(void) + { +- /* Always run first iteration so any pending completion BHs run */ +- bool waited = true; + BlockDriverState *bs; + BdrvNextIterator it; +- GSList *aio_ctxs = NULL, *ctx; + + /* BDRV_POLL_WHILE() for a node can only be called from its own I/O thread + * or the main loop AioContext. We potentially use BDRV_POLL_WHILE() on +@@ -408,35 +415,11 @@ void bdrv_drain_all_begin(void) + aio_context_acquire(aio_context); + bdrv_do_drained_begin(bs, true, NULL); + aio_context_release(aio_context); +- +- if (!g_slist_find(aio_ctxs, aio_context)) { +- aio_ctxs = g_slist_prepend(aio_ctxs, aio_context); +- } + } + +- /* Note that completion of an asynchronous I/O operation can trigger any +- * number of other I/O operations on other devices---for example a +- * coroutine can submit an I/O request to another device in response to +- * request completion. Therefore we must keep looping until there was no +- * more activity rather than simply draining each device independently. +- */ +- while (waited) { +- waited = false; +- +- for (ctx = aio_ctxs; ctx != NULL; ctx = ctx->next) { +- AioContext *aio_context = ctx->data; +- +- aio_context_acquire(aio_context); +- for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { +- if (aio_context == bdrv_get_aio_context(bs)) { +- waited |= bdrv_drain_recurse(bs); +- } +- } +- aio_context_release(aio_context); +- } ++ for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { ++ bdrv_drain_assert_idle(bs); + } +- +- g_slist_free(aio_ctxs); + } + + void bdrv_drain_all_end(void) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Don-t-poll-in-parent-drain-callbacks.patch b/SOURCES/kvm-block-Don-t-poll-in-parent-drain-callbacks.patch new file mode 100644 index 0000000..c2b4972 --- /dev/null +++ b/SOURCES/kvm-block-Don-t-poll-in-parent-drain-callbacks.patch @@ -0,0 +1,112 @@ +From 72f0fcad0938bba82537e78753e242d53f3f2583 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:10 +0200 +Subject: [PATCH 19/49] block: Don't poll in parent drain callbacks + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-13-kwolf@redhat.com> +Patchwork-id: 82164 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 12/42] block: Don't poll in parent drain callbacks +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +bdrv_do_drained_begin() is only safe if we have a single +BDRV_POLL_WHILE() after quiescing all affected nodes. We cannot allow +that parent callbacks introduce a nested polling loop that could cause +graph changes while we're traversing the graph. + +Split off bdrv_do_drained_begin_quiesce(), which only quiesces a single +node without waiting for its requests to complete. These requests will +be waited for in the BDRV_POLL_WHILE() call down the call chain. + +Signed-off-by: Kevin Wolf +(cherry picked from commit dcf94a23b1add0f856db51e9ff5ba0774e096076) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block.c | 2 +- + block/io.c | 24 ++++++++++++++++-------- + include/block/block.h | 9 +++++++++ + 3 files changed, 26 insertions(+), 9 deletions(-) + +diff --git a/block.c b/block.c +index 9afaf26..5a50de6 100644 +--- a/block.c ++++ b/block.c +@@ -818,7 +818,7 @@ static char *bdrv_child_get_parent_desc(BdrvChild *c) + static void bdrv_child_cb_drained_begin(BdrvChild *child) + { + BlockDriverState *bs = child->opaque; +- bdrv_drained_begin(bs); ++ bdrv_do_drained_begin_quiesce(bs, NULL); + } + + static bool bdrv_child_cb_drained_poll(BdrvChild *child) +diff --git a/block/io.c b/block/io.c +index 442ded1..9c41ff9 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -285,15 +285,10 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, + assert(data.done); + } + +-void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, +- BdrvChild *parent, bool poll) ++void bdrv_do_drained_begin_quiesce(BlockDriverState *bs, ++ BdrvChild *parent) + { +- BdrvChild *child, *next; +- +- if (qemu_in_coroutine()) { +- bdrv_co_yield_to_drain(bs, true, recursive, parent, poll); +- return; +- } ++ assert(!qemu_in_coroutine()); + + /* Stop things in parent-to-child order */ + if (atomic_fetch_inc(&bs->quiesce_counter) == 0) { +@@ -302,6 +297,19 @@ void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, + + bdrv_parent_drained_begin(bs, parent); + bdrv_drain_invoke(bs, true); ++} ++ ++static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, ++ BdrvChild *parent, bool poll) ++{ ++ BdrvChild *child, *next; ++ ++ if (qemu_in_coroutine()) { ++ bdrv_co_yield_to_drain(bs, true, recursive, parent, poll); ++ return; ++ } ++ ++ bdrv_do_drained_begin_quiesce(bs, parent); + + if (recursive) { + bs->recursive_quiesce_counter++; +diff --git a/include/block/block.h b/include/block/block.h +index 2bbea7c..43f29b5 100644 +--- a/include/block/block.h ++++ b/include/block/block.h +@@ -619,6 +619,15 @@ bool bdrv_drain_poll(BlockDriverState *bs, bool recursive, + void bdrv_drained_begin(BlockDriverState *bs); + + /** ++ * bdrv_do_drained_begin_quiesce: ++ * ++ * Quiesces a BDS like bdrv_drained_begin(), but does not wait for already ++ * running requests to complete. ++ */ ++void bdrv_do_drained_begin_quiesce(BlockDriverState *bs, ++ BdrvChild *parent); ++ ++/** + * Like bdrv_drained_begin, but recursively begins a quiesced section for + * exclusive access to all child nodes as well. + */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Don-t-request-I-O-permission-with-BDRV_O_NO_IO.patch b/SOURCES/kvm-block-Don-t-request-I-O-permission-with-BDRV_O_NO_IO.patch deleted file mode 100644 index 04fd644..0000000 --- a/SOURCES/kvm-block-Don-t-request-I-O-permission-with-BDRV_O_NO_IO.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 47357547c1040e029aec3e1d9e850d6249bc2bbb Mon Sep 17 00:00:00 2001 -From: Kevin Wolf -Date: Mon, 15 Jan 2018 11:23:36 +0100 -Subject: [PATCH 11/12] block: Don't request I/O permission with BDRV_O_NO_IO - -RH-Author: Kevin Wolf -Message-id: <20180115112337.20885-3-kwolf@redhat.com> -Patchwork-id: 78575 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH 2/3] block: Don't request I/O permission with BDRV_O_NO_IO -Bugzilla: 1515604 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Jeffrey Cody -RH-Acked-by: John Snow - -'qemu-img info' makes sense even when BLK_PERM_CONSISTENT_READ cannot be -granted because of a block job in a running qemu process. It already -sets BDRV_O_NO_IO to indicate that it doesn't access the guest visible -data at all. - -Check the BDRV_O_NO_IO flags in blk_new_open(), so that I/O related -permissions are not unnecessarily requested and 'qemu-img info' can work -even if BLK_PERM_CONSISTENT_READ cannot be granted. - -Signed-off-by: Kevin Wolf -Reviewed-by: Fam Zheng -Reviewed-by: Alberto Garcia -(cherry picked from commit 1f4ad7d3b8f7162ec0471506d86f57a5d77b8f76) -Signed-off-by: Kevin Wolf -Signed-off-by: Miroslav Rezanina ---- - block/block-backend.c | 10 ++++++---- - 1 file changed, 6 insertions(+), 4 deletions(-) - -diff --git a/block/block-backend.c b/block/block-backend.c -index 083e65f..dce8b96 100644 ---- a/block/block-backend.c -+++ b/block/block-backend.c -@@ -299,7 +299,7 @@ BlockBackend *blk_new_open(const char *filename, const char *reference, - { - BlockBackend *blk; - BlockDriverState *bs; -- uint64_t perm; -+ uint64_t perm = 0; - - /* blk_new_open() is mainly used in .bdrv_create implementations and the - * tools where sharing isn't a concern because the BDS stays private, so we -@@ -309,9 +309,11 @@ BlockBackend *blk_new_open(const char *filename, const char *reference, - * caller of blk_new_open() doesn't make use of the permissions, but they - * shouldn't hurt either. We can still share everything here because the - * guest devices will add their own blockers if they can't share. */ -- perm = BLK_PERM_CONSISTENT_READ; -- if (flags & BDRV_O_RDWR) { -- perm |= BLK_PERM_WRITE; -+ if ((flags & BDRV_O_NO_IO) == 0) { -+ perm |= BLK_PERM_CONSISTENT_READ; -+ if (flags & BDRV_O_RDWR) { -+ perm |= BLK_PERM_WRITE; -+ } - } - if (flags & BDRV_O_RESIZE) { - perm |= BLK_PERM_RESIZE; --- -1.8.3.1 - diff --git a/SOURCES/kvm-block-Don-t-silently-truncate-node-names.patch b/SOURCES/kvm-block-Don-t-silently-truncate-node-names.patch new file mode 100644 index 0000000..73463fa --- /dev/null +++ b/SOURCES/kvm-block-Don-t-silently-truncate-node-names.patch @@ -0,0 +1,148 @@ +From 524287dc348c81473dd19b275a0333dd2e888878 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Thu, 5 Jul 2018 16:47:51 +0200 +Subject: [PATCH 16/89] block: Don't silently truncate node names + +RH-Author: Kevin Wolf +Message-id: <20180705164751.15271-2-kwolf@redhat.com> +Patchwork-id: 81234 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 1/1] block: Don't silently truncate node names +Bugzilla: 1549654 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Max Reitz +RH-Acked-by: John Snow + +If the user passes a too long node name string, we silently truncate it +to fit into BlockDriverState.node_name, i.e. to 31 characters. Apart +from surprising the user when the node has a different name than +requested, this also bypasses the check for duplicate names, so that the +same name can be assigned to multiple nodes. + +Fix this by just making too long node names an error. + +Reported-by: Peter Krempa +Signed-off-by: Kevin Wolf +(cherry picked from commit 824808dd77821ceba05357cb1ee4069a6a95bebd) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block.c | 6 ++++++ + tests/qemu-iotests/051 | 15 +++++++++++++++ + tests/qemu-iotests/051.out | 23 +++++++++++++++++++++++ + tests/qemu-iotests/051.pc.out | 23 +++++++++++++++++++++++ + 4 files changed, 67 insertions(+) + +diff --git a/block.c b/block.c +index afe30ca..0516284 100644 +--- a/block.c ++++ b/block.c +@@ -1140,6 +1140,12 @@ static void bdrv_assign_node_name(BlockDriverState *bs, + goto out; + } + ++ /* Make sure that the node name isn't truncated */ ++ if (strlen(node_name) >= sizeof(bs->node_name)) { ++ error_setg(errp, "Node name too long"); ++ goto out; ++ } ++ + /* copy node name into the bs and insert it into the graph list */ + pstrcpy(bs->node_name, sizeof(bs->node_name), node_name); + QTAILQ_INSERT_TAIL(&graph_bdrv_states, bs, node_list); +diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051 +index 69d34eb..c5cc0ee 100755 +--- a/tests/qemu-iotests/051 ++++ b/tests/qemu-iotests/051 +@@ -100,6 +100,21 @@ run_qemu -drive file="$TEST_IMG",driver=raw,format=qcow2 + run_qemu -drive file="$TEST_IMG",driver=qcow2,format=qcow2 + + echo ++echo === Node names === ++echo ++ ++# Maximum length: 31 characters ++run_qemu -drive file="$TEST_IMG",node-name=x123456789012345678901234567890 ++run_qemu -drive file="$TEST_IMG",node-name=x1234567890123456789012345678901 ++ ++# First character must be alphabetic ++# Following characters alphanumeric or -._ ++run_qemu -drive file="$TEST_IMG",node-name=All-Types.of_all0wed_chars ++run_qemu -drive file="$TEST_IMG",node-name=123foo ++run_qemu -drive file="$TEST_IMG",node-name=_foo ++run_qemu -drive file="$TEST_IMG",node-name=foo#12 ++ ++echo + echo === Device without drive === + echo + +diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out +index dd9846d..b727350 100644 +--- a/tests/qemu-iotests/051.out ++++ b/tests/qemu-iotests/051.out +@@ -47,6 +47,29 @@ Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,format=qcow2 + QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=qcow2,format=qcow2: Cannot specify both 'driver' and 'format' + + ++=== Node names === ++ ++Testing: -drive file=TEST_DIR/t.qcow2,node-name=x123456789012345678901234567890 ++QEMU X.Y.Z monitor - type 'help' for more information ++(qemu) quit ++ ++Testing: -drive file=TEST_DIR/t.qcow2,node-name=x1234567890123456789012345678901 ++QEMU_PROG: -drive file=TEST_DIR/t.qcow2,node-name=x1234567890123456789012345678901: Node name too long ++ ++Testing: -drive file=TEST_DIR/t.qcow2,node-name=All-Types.of_all0wed_chars ++QEMU X.Y.Z monitor - type 'help' for more information ++(qemu) quit ++ ++Testing: -drive file=TEST_DIR/t.qcow2,node-name=123foo ++QEMU_PROG: -drive file=TEST_DIR/t.qcow2,node-name=123foo: Invalid node name ++ ++Testing: -drive file=TEST_DIR/t.qcow2,node-name=_foo ++QEMU_PROG: -drive file=TEST_DIR/t.qcow2,node-name=_foo: Invalid node name ++ ++Testing: -drive file=TEST_DIR/t.qcow2,node-name=foo#12 ++QEMU_PROG: -drive file=TEST_DIR/t.qcow2,node-name=foo#12: Invalid node name ++ ++ + === Device without drive === + + Testing: -device VIRTIO_SCSI -device scsi-hd +diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out +index b01f9a9..e9257fe 100644 +--- a/tests/qemu-iotests/051.pc.out ++++ b/tests/qemu-iotests/051.pc.out +@@ -47,6 +47,29 @@ Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,format=qcow2 + QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=qcow2,format=qcow2: Cannot specify both 'driver' and 'format' + + ++=== Node names === ++ ++Testing: -drive file=TEST_DIR/t.qcow2,node-name=x123456789012345678901234567890 ++QEMU X.Y.Z monitor - type 'help' for more information ++(qemu) quit ++ ++Testing: -drive file=TEST_DIR/t.qcow2,node-name=x1234567890123456789012345678901 ++QEMU_PROG: -drive file=TEST_DIR/t.qcow2,node-name=x1234567890123456789012345678901: Node name too long ++ ++Testing: -drive file=TEST_DIR/t.qcow2,node-name=All-Types.of_all0wed_chars ++QEMU X.Y.Z monitor - type 'help' for more information ++(qemu) quit ++ ++Testing: -drive file=TEST_DIR/t.qcow2,node-name=123foo ++QEMU_PROG: -drive file=TEST_DIR/t.qcow2,node-name=123foo: Invalid node name ++ ++Testing: -drive file=TEST_DIR/t.qcow2,node-name=_foo ++QEMU_PROG: -drive file=TEST_DIR/t.qcow2,node-name=_foo: Invalid node name ++ ++Testing: -drive file=TEST_DIR/t.qcow2,node-name=foo#12 ++QEMU_PROG: -drive file=TEST_DIR/t.qcow2,node-name=foo#12: Invalid node name ++ ++ + === Device without drive === + + Testing: -device VIRTIO_SCSI -device scsi-hd +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Don-t-use-BLK_PERM_CONSISTENT_READ-for-format-.patch b/SOURCES/kvm-block-Don-t-use-BLK_PERM_CONSISTENT_READ-for-format-.patch deleted file mode 100644 index b4954f5..0000000 --- a/SOURCES/kvm-block-Don-t-use-BLK_PERM_CONSISTENT_READ-for-format-.patch +++ /dev/null @@ -1,53 +0,0 @@ -From ab2ef6c7b0c99840a5b530899076998a7bbdf5df Mon Sep 17 00:00:00 2001 -From: Kevin Wolf -Date: Mon, 15 Jan 2018 11:23:35 +0100 -Subject: [PATCH 10/12] block: Don't use BLK_PERM_CONSISTENT_READ for format - probing - -RH-Author: Kevin Wolf -Message-id: <20180115112337.20885-2-kwolf@redhat.com> -Patchwork-id: 78573 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH 1/3] block: Don't use BLK_PERM_CONSISTENT_READ for format probing -Bugzilla: 1515604 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Jeffrey Cody -RH-Acked-by: John Snow - -For format probing, we don't really care whether all of the image -content is consistent. The only thing we're looking at is the image -header, and specifically the magic numbers that are expected to never -change, no matter how inconsistent the guest visible disk content is. - -Therefore, don't request BLK_PERM_CONSISTENT_READ. This allows to use -format probing, e.g. in the context of 'qemu-img info', even while the -guest visible data in the image is inconsistent during a running block -job. - -Signed-off-by: Kevin Wolf -Reviewed-by: Fam Zheng -(cherry picked from commit dacaa16238cc5915a609ddaab4b7f81c4bceb9ae) -Signed-off-by: Kevin Wolf -Signed-off-by: Miroslav Rezanina ---- - block.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/block.c b/block.c -index 17629ab..90a60bc 100644 ---- a/block.c -+++ b/block.c -@@ -2540,7 +2540,10 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, - goto fail; - } - if (file_bs != NULL) { -- file = blk_new(BLK_PERM_CONSISTENT_READ, BLK_PERM_ALL); -+ /* Not requesting BLK_PERM_CONSISTENT_READ because we're only -+ * looking at the header to guess the image format. This works even -+ * in cases where a guest would not see a consistent state. */ -+ file = blk_new(0, BLK_PERM_ALL); - blk_insert_bs(file, file_bs, &local_err); - bdrv_unref(file_bs); - if (local_err) { --- -1.8.3.1 - diff --git a/SOURCES/kvm-block-Drain-recursively-with-a-single-BDRV_POLL_WHIL.patch b/SOURCES/kvm-block-Drain-recursively-with-a-single-BDRV_POLL_WHIL.patch new file mode 100644 index 0000000..d3f6485 --- /dev/null +++ b/SOURCES/kvm-block-Drain-recursively-with-a-single-BDRV_POLL_WHIL.patch @@ -0,0 +1,242 @@ +From 3ff0f5aa671432b2c11c36818368ed1e40c95f5a Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:08 +0200 +Subject: [PATCH 17/49] block: Drain recursively with a single + BDRV_POLL_WHILE() + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-11-kwolf@redhat.com> +Patchwork-id: 82163 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 10/42] block: Drain recursively with a single BDRV_POLL_WHILE() +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +Anything can happen inside BDRV_POLL_WHILE(), including graph +changes that may interfere with its callers (e.g. child list iteration +in recursive callers of bdrv_do_drained_begin). + +Switch to a single BDRV_POLL_WHILE() call for the whole subtree at the +end of bdrv_do_drained_begin() to avoid such effects. The recursion +happens now inside the loop condition. As the graph can only change +between bdrv_drain_poll() calls, but not inside of it, doing the +recursion here is safe. + +Signed-off-by: Kevin Wolf +(cherry picked from commit fe4f0614ef9e361dae12012d3c400657444836cf) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block.c | 2 +- + block/io.c | 63 ++++++++++++++++++++++++++++++++++++--------------- + include/block/block.h | 9 +++++--- + 3 files changed, 52 insertions(+), 22 deletions(-) + +diff --git a/block.c b/block.c +index 0d9698a..9afaf26 100644 +--- a/block.c ++++ b/block.c +@@ -824,7 +824,7 @@ static void bdrv_child_cb_drained_begin(BdrvChild *child) + static bool bdrv_child_cb_drained_poll(BdrvChild *child) + { + BlockDriverState *bs = child->opaque; +- return bdrv_drain_poll(bs, NULL); ++ return bdrv_drain_poll(bs, false, NULL); + } + + static void bdrv_child_cb_drained_end(BdrvChild *child) +diff --git a/block/io.c b/block/io.c +index a0e3461..442ded1 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -164,6 +164,7 @@ typedef struct { + bool done; + bool begin; + bool recursive; ++ bool poll; + BdrvChild *parent; + } BdrvCoDrainData; + +@@ -199,27 +200,42 @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin) + } + + /* Returns true if BDRV_POLL_WHILE() should go into a blocking aio_poll() */ +-bool bdrv_drain_poll(BlockDriverState *bs, BdrvChild *ignore_parent) ++bool bdrv_drain_poll(BlockDriverState *bs, bool recursive, ++ BdrvChild *ignore_parent) + { ++ BdrvChild *child, *next; ++ + if (bdrv_parent_drained_poll(bs, ignore_parent)) { + return true; + } + +- return atomic_read(&bs->in_flight); ++ if (atomic_read(&bs->in_flight)) { ++ return true; ++ } ++ ++ if (recursive) { ++ QLIST_FOREACH_SAFE(child, &bs->children, next, next) { ++ if (bdrv_drain_poll(child->bs, recursive, child)) { ++ return true; ++ } ++ } ++ } ++ ++ return false; + } + +-static bool bdrv_drain_poll_top_level(BlockDriverState *bs, ++static bool bdrv_drain_poll_top_level(BlockDriverState *bs, bool recursive, + BdrvChild *ignore_parent) + { + /* Execute pending BHs first and check everything else only after the BHs + * have executed. */ + while (aio_poll(bs->aio_context, false)); + +- return bdrv_drain_poll(bs, ignore_parent); ++ return bdrv_drain_poll(bs, recursive, ignore_parent); + } + + static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, +- BdrvChild *parent); ++ BdrvChild *parent, bool poll); + static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive, + BdrvChild *parent); + +@@ -231,7 +247,7 @@ static void bdrv_co_drain_bh_cb(void *opaque) + + bdrv_dec_in_flight(bs); + if (data->begin) { +- bdrv_do_drained_begin(bs, data->recursive, data->parent); ++ bdrv_do_drained_begin(bs, data->recursive, data->parent, data->poll); + } else { + bdrv_do_drained_end(bs, data->recursive, data->parent); + } +@@ -242,7 +258,7 @@ static void bdrv_co_drain_bh_cb(void *opaque) + + static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, + bool begin, bool recursive, +- BdrvChild *parent) ++ BdrvChild *parent, bool poll) + { + BdrvCoDrainData data; + +@@ -257,6 +273,7 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, + .begin = begin, + .recursive = recursive, + .parent = parent, ++ .poll = poll, + }; + bdrv_inc_in_flight(bs); + aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), +@@ -269,12 +286,12 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, + } + + void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, +- BdrvChild *parent) ++ BdrvChild *parent, bool poll) + { + BdrvChild *child, *next; + + if (qemu_in_coroutine()) { +- bdrv_co_yield_to_drain(bs, true, recursive, parent); ++ bdrv_co_yield_to_drain(bs, true, recursive, parent, poll); + return; + } + +@@ -286,25 +303,35 @@ void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, + bdrv_parent_drained_begin(bs, parent); + bdrv_drain_invoke(bs, true); + +- /* Wait for drained requests to finish */ +- BDRV_POLL_WHILE(bs, bdrv_drain_poll_top_level(bs, parent)); +- + if (recursive) { + bs->recursive_quiesce_counter++; + QLIST_FOREACH_SAFE(child, &bs->children, next, next) { +- bdrv_do_drained_begin(child->bs, true, child); ++ bdrv_do_drained_begin(child->bs, true, child, false); + } + } ++ ++ /* ++ * Wait for drained requests to finish. ++ * ++ * Calling BDRV_POLL_WHILE() only once for the top-level node is okay: The ++ * call is needed so things in this AioContext can make progress even ++ * though we don't return to the main AioContext loop - this automatically ++ * includes other nodes in the same AioContext and therefore all child ++ * nodes. ++ */ ++ if (poll) { ++ BDRV_POLL_WHILE(bs, bdrv_drain_poll_top_level(bs, recursive, parent)); ++ } + } + + void bdrv_drained_begin(BlockDriverState *bs) + { +- bdrv_do_drained_begin(bs, false, NULL); ++ bdrv_do_drained_begin(bs, false, NULL, true); + } + + void bdrv_subtree_drained_begin(BlockDriverState *bs) + { +- bdrv_do_drained_begin(bs, true, NULL); ++ bdrv_do_drained_begin(bs, true, NULL, true); + } + + void bdrv_do_drained_end(BlockDriverState *bs, bool recursive, +@@ -314,7 +341,7 @@ void bdrv_do_drained_end(BlockDriverState *bs, bool recursive, + int old_quiesce_counter; + + if (qemu_in_coroutine()) { +- bdrv_co_yield_to_drain(bs, false, recursive, parent); ++ bdrv_co_yield_to_drain(bs, false, recursive, parent, false); + return; + } + assert(bs->quiesce_counter > 0); +@@ -350,7 +377,7 @@ void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent) + int i; + + for (i = 0; i < new_parent->recursive_quiesce_counter; i++) { +- bdrv_do_drained_begin(child->bs, true, child); ++ bdrv_do_drained_begin(child->bs, true, child, true); + } + } + +@@ -420,7 +447,7 @@ void bdrv_drain_all_begin(void) + AioContext *aio_context = bdrv_get_aio_context(bs); + + aio_context_acquire(aio_context); +- bdrv_do_drained_begin(bs, true, NULL); ++ bdrv_do_drained_begin(bs, true, NULL, true); + aio_context_release(aio_context); + } + +diff --git a/include/block/block.h b/include/block/block.h +index 8c91d4c..2bbea7c 100644 +--- a/include/block/block.h ++++ b/include/block/block.h +@@ -598,10 +598,13 @@ void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore); + /** + * bdrv_drain_poll: + * +- * Poll for pending requests in @bs and its parents (except for +- * @ignore_parent). This is part of bdrv_drained_begin. ++ * Poll for pending requests in @bs, its parents (except for @ignore_parent), ++ * and if @recursive is true its children as well. ++ * ++ * This is part of bdrv_drained_begin. + */ +-bool bdrv_drain_poll(BlockDriverState *bs, BdrvChild *ignore_parent); ++bool bdrv_drain_poll(BlockDriverState *bs, bool recursive, ++ BdrvChild *ignore_parent); + + /** + * bdrv_drained_begin: +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Expect-graph-changes-in-bdrv_parent_drained_be.patch b/SOURCES/kvm-block-Expect-graph-changes-in-bdrv_parent_drained_be.patch deleted file mode 100644 index 4c97b56..0000000 --- a/SOURCES/kvm-block-Expect-graph-changes-in-bdrv_parent_drained_be.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 2a9bf55a3db6b1a4a20c07fa030fde5ded02cf92 Mon Sep 17 00:00:00 2001 -From: Jeffrey Cody -Date: Thu, 30 Nov 2017 22:49:12 +0100 -Subject: [PATCH 08/21] block: Expect graph changes in - bdrv_parent_drained_begin/end - -RH-Author: Jeffrey Cody -Message-id: <09d305a1846240448bc742a53a49ea87950e427d.1511985875.git.jcody@redhat.com> -Patchwork-id: 78047 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 08/11] block: Expect graph changes in bdrv_parent_drained_begin/end -Bugzilla: 1506531 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: John Snow - -From: Kevin Wolf - -The .drained_begin/end callbacks can (directly or indirectly via -aio_poll()) cause block nodes to be removed or the current BdrvChild to -point to a different child node. - -Use QLIST_FOREACH_SAFE() to make sure we don't access invalid -BlockDriverStates or accidentally continue iterating the parents of the -new child node instead of the node we actually came from. - -Signed-off-by: Kevin Wolf -Tested-by: Jeff Cody -Reviewed-by: Stefan Hajnoczi -Reviewed-by: Jeff Cody -Reviewed-by: Alberto Garcia -Reviewed-by: Fam Zheng -Signed-off-by: Kevin Wolf -(cherry picked from commit 02d213009d571bcd7171e3ff9234722a11d30d1b) -Signed-off-by: Jeff Cody -Signed-off-by: Miroslav Rezanina ---- - block/io.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/block/io.c b/block/io.c -index 3a717bc..4ff2f25 100644 ---- a/block/io.c -+++ b/block/io.c -@@ -39,9 +39,9 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, - - void bdrv_parent_drained_begin(BlockDriverState *bs) - { -- BdrvChild *c; -+ BdrvChild *c, *next; - -- QLIST_FOREACH(c, &bs->parents, next_parent) { -+ QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) { - if (c->role->drained_begin) { - c->role->drained_begin(c); - } -@@ -50,9 +50,9 @@ void bdrv_parent_drained_begin(BlockDriverState *bs) - - void bdrv_parent_drained_end(BlockDriverState *bs) - { -- BdrvChild *c; -+ BdrvChild *c, *next; - -- QLIST_FOREACH(c, &bs->parents, next_parent) { -+ QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) { - if (c->role->drained_end) { - c->role->drained_end(c); - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-block-Factor-out-qobject_input_visitor_new_flat_conf.patch b/SOURCES/kvm-block-Factor-out-qobject_input_visitor_new_flat_conf.patch new file mode 100644 index 0000000..975e803 --- /dev/null +++ b/SOURCES/kvm-block-Factor-out-qobject_input_visitor_new_flat_conf.patch @@ -0,0 +1,465 @@ +From 8a66fde222f0192c1d9ce215f297964ab34235c7 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Mon, 18 Jun 2018 08:43:20 +0200 +Subject: [PATCH 13/54] block: Factor out + qobject_input_visitor_new_flat_confused() + +RH-Author: Markus Armbruster +Message-id: <20180618084330.30009-14-armbru@redhat.com> +Patchwork-id: 80728 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 13/23] block: Factor out qobject_input_visitor_new_flat_confused() +Bugzilla: 1557995 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Signed-off-by: Markus Armbruster +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit af91062ee1408f7f5bb58389d355d29a5040c648) +Signed-off-by: Miroslav Rezanina +--- + block/nbd.c | 7 ++----- + block/nfs.c | 7 ++----- + block/parallels.c | 7 ++----- + block/qcow.c | 7 ++----- + block/qcow2.c | 7 ++----- + block/qed.c | 7 ++----- + block/rbd.c | 7 ++----- + block/sheepdog.c | 14 ++++---------- + block/ssh.c | 7 ++----- + block/vhdx.c | 7 ++----- + block/vpc.c | 7 ++----- + include/block/qdict.h | 3 ++- + qobject/block-qdict.c | 28 +++++++++++++++++++++++++++- + 13 files changed, 53 insertions(+), 62 deletions(-) + +diff --git a/block/nbd.c b/block/nbd.c +index b0be357..10912c3 100644 +--- a/block/nbd.c ++++ b/block/nbd.c +@@ -263,7 +263,6 @@ static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options, + { + SocketAddress *saddr = NULL; + QDict *addr = NULL; +- QObject *crumpled_addr = NULL; + Visitor *iv = NULL; + Error *local_err = NULL; + +@@ -273,12 +272,11 @@ static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options, + goto done; + } + +- crumpled_addr = qdict_crumple_for_keyval_qiv(addr, errp); +- if (!crumpled_addr) { ++ iv = qobject_input_visitor_new_flat_confused(addr, errp); ++ if (!iv) { + goto done; + } + +- iv = qobject_input_visitor_new_keyval(crumpled_addr); + visit_type_SocketAddress(iv, NULL, &saddr, &local_err); + if (local_err) { + error_propagate(errp, local_err); +@@ -287,7 +285,6 @@ static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options, + + done: + qobject_unref(addr); +- qobject_unref(crumpled_addr); + visit_free(iv); + return saddr; + } +diff --git a/block/nfs.c b/block/nfs.c +index 4090d28..1e12958 100644 +--- a/block/nfs.c ++++ b/block/nfs.c +@@ -556,19 +556,16 @@ static BlockdevOptionsNfs *nfs_options_qdict_to_qapi(QDict *options, + Error **errp) + { + BlockdevOptionsNfs *opts = NULL; +- QObject *crumpled = NULL; + Visitor *v; + Error *local_err = NULL; + +- crumpled = qdict_crumple_for_keyval_qiv(options, errp); +- if (crumpled == NULL) { ++ v = qobject_input_visitor_new_flat_confused(options, errp); ++ if (!v) { + return NULL; + } + +- v = qobject_input_visitor_new_keyval(crumpled); + visit_type_BlockdevOptionsNfs(v, NULL, &opts, &local_err); + visit_free(v); +- qobject_unref(crumpled); + + if (local_err) { + return NULL; +diff --git a/block/parallels.c b/block/parallels.c +index 1c96c39..b6ebe36 100644 +--- a/block/parallels.c ++++ b/block/parallels.c +@@ -615,7 +615,6 @@ static int coroutine_fn parallels_co_create_opts(const char *filename, + Error *local_err = NULL; + BlockDriverState *bs = NULL; + QDict *qdict; +- QObject *qobj; + Visitor *v; + int ret; + +@@ -651,14 +650,12 @@ static int coroutine_fn parallels_co_create_opts(const char *filename, + qdict_put_str(qdict, "driver", "parallels"); + qdict_put_str(qdict, "file", bs->node_name); + +- qobj = qdict_crumple_for_keyval_qiv(qdict, errp); +- if (!qobj) { ++ v = qobject_input_visitor_new_flat_confused(qdict, errp); ++ if (!v) { + ret = -EINVAL; + goto done; + } + +- v = qobject_input_visitor_new_keyval(qobj); +- qobject_unref(qobj); + visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err); + visit_free(v); + +diff --git a/block/qcow.c b/block/qcow.c +index 43a595a..4b3bc31 100644 +--- a/block/qcow.c ++++ b/block/qcow.c +@@ -945,7 +945,6 @@ static int coroutine_fn qcow_co_create_opts(const char *filename, + BlockdevCreateOptions *create_options = NULL; + BlockDriverState *bs = NULL; + QDict *qdict; +- QObject *qobj; + Visitor *v; + const char *val; + Error *local_err = NULL; +@@ -995,14 +994,12 @@ static int coroutine_fn qcow_co_create_opts(const char *filename, + qdict_put_str(qdict, "driver", "qcow"); + qdict_put_str(qdict, "file", bs->node_name); + +- qobj = qdict_crumple_for_keyval_qiv(qdict, errp); +- if (!qobj) { ++ v = qobject_input_visitor_new_flat_confused(qdict, errp); ++ if (!v) { + ret = -EINVAL; + goto fail; + } + +- v = qobject_input_visitor_new_keyval(qobj); +- qobject_unref(qobj); + visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err); + visit_free(v); + +diff --git a/block/qcow2.c b/block/qcow2.c +index ede52a8..35842c5 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -3068,7 +3068,6 @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt + { + BlockdevCreateOptions *create_options = NULL; + QDict *qdict; +- QObject *qobj; + Visitor *v; + BlockDriverState *bs = NULL; + Error *local_err = NULL; +@@ -3139,14 +3138,12 @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt + qdict_put_str(qdict, "file", bs->node_name); + + /* Now get the QAPI type BlockdevCreateOptions */ +- qobj = qdict_crumple_for_keyval_qiv(qdict, errp); +- if (!qobj) { ++ v = qobject_input_visitor_new_flat_confused(qdict, errp); ++ if (!v) { + ret = -EINVAL; + goto finish; + } + +- v = qobject_input_visitor_new_keyval(qobj); +- qobject_unref(qobj); + visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err); + visit_free(v); + +diff --git a/block/qed.c b/block/qed.c +index 3818888..4c5d7e8 100644 +--- a/block/qed.c ++++ b/block/qed.c +@@ -723,7 +723,6 @@ static int coroutine_fn bdrv_qed_co_create_opts(const char *filename, + { + BlockdevCreateOptions *create_options = NULL; + QDict *qdict; +- QObject *qobj; + Visitor *v; + BlockDriverState *bs = NULL; + Error *local_err = NULL; +@@ -763,14 +762,12 @@ static int coroutine_fn bdrv_qed_co_create_opts(const char *filename, + qdict_put_str(qdict, "driver", "qed"); + qdict_put_str(qdict, "file", bs->node_name); + +- qobj = qdict_crumple_for_keyval_qiv(qdict, errp); +- if (!qobj) { ++ v = qobject_input_visitor_new_flat_confused(qdict, errp); ++ if (!v) { + ret = -EINVAL; + goto fail; + } + +- v = qobject_input_visitor_new_keyval(qobj); +- qobject_unref(qobj); + visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err); + visit_free(v); + +diff --git a/block/rbd.c b/block/rbd.c +index 0b5455f..c834d72 100644 +--- a/block/rbd.c ++++ b/block/rbd.c +@@ -623,7 +623,6 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags, + BDRVRBDState *s = bs->opaque; + BlockdevOptionsRbd *opts = NULL; + Visitor *v; +- QObject *crumpled = NULL; + const QDictEntry *e; + Error *local_err = NULL; + char *keypairs, *secretid; +@@ -640,16 +639,14 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags, + } + + /* Convert the remaining options into a QAPI object */ +- crumpled = qdict_crumple_for_keyval_qiv(options, errp); +- if (crumpled == NULL) { ++ v = qobject_input_visitor_new_flat_confused(options, errp); ++ if (!v) { + r = -EINVAL; + goto out; + } + +- v = qobject_input_visitor_new_keyval(crumpled); + visit_type_BlockdevOptionsRbd(v, NULL, &opts, &local_err); + visit_free(v); +- qobject_unref(crumpled); + + if (local_err) { + error_propagate(errp, local_err); +diff --git a/block/sheepdog.c b/block/sheepdog.c +index dd582d5..d1c9bf5 100644 +--- a/block/sheepdog.c ++++ b/block/sheepdog.c +@@ -539,19 +539,17 @@ static void sd_aio_setup(SheepdogAIOCB *acb, BDRVSheepdogState *s, + static SocketAddress *sd_server_config(QDict *options, Error **errp) + { + QDict *server = NULL; +- QObject *crumpled_server = NULL; + Visitor *iv = NULL; + SocketAddress *saddr = NULL; + Error *local_err = NULL; + + qdict_extract_subqdict(options, &server, "server."); + +- crumpled_server = qdict_crumple_for_keyval_qiv(server, errp); +- if (!crumpled_server) { ++ iv = qobject_input_visitor_new_flat_confused(server, errp); ++ if (!iv) { + goto done; + } + +- iv = qobject_input_visitor_new_keyval(crumpled_server); + visit_type_SocketAddress(iv, NULL, &saddr, &local_err); + if (local_err) { + error_propagate(errp, local_err); +@@ -560,7 +558,6 @@ static SocketAddress *sd_server_config(QDict *options, Error **errp) + + done: + visit_free(iv); +- qobject_unref(crumpled_server); + qobject_unref(server); + return saddr; + } +@@ -2174,7 +2171,6 @@ static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts, + { + BlockdevCreateOptions *create_options = NULL; + QDict *qdict, *location_qdict; +- QObject *crumpled; + Visitor *v; + const char *redundancy; + Error *local_err = NULL; +@@ -2210,16 +2206,14 @@ static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts, + } + + /* Get the QAPI object */ +- crumpled = qdict_crumple_for_keyval_qiv(qdict, errp); +- if (crumpled == NULL) { ++ v = qobject_input_visitor_new_flat_confused(qdict, errp); ++ if (!v) { + ret = -EINVAL; + goto fail; + } + +- v = qobject_input_visitor_new_keyval(crumpled); + visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err); + visit_free(v); +- qobject_unref(crumpled); + + if (local_err) { + error_propagate(errp, local_err); +diff --git a/block/ssh.c b/block/ssh.c +index 2fc7cd9..aab6996 100644 +--- a/block/ssh.c ++++ b/block/ssh.c +@@ -606,7 +606,6 @@ static BlockdevOptionsSsh *ssh_parse_options(QDict *options, Error **errp) + BlockdevOptionsSsh *result = NULL; + QemuOpts *opts = NULL; + Error *local_err = NULL; +- QObject *crumpled; + const QDictEntry *e; + Visitor *v; + +@@ -623,15 +622,13 @@ static BlockdevOptionsSsh *ssh_parse_options(QDict *options, Error **errp) + } + + /* Create the QAPI object */ +- crumpled = qdict_crumple_for_keyval_qiv(options, errp); +- if (crumpled == NULL) { ++ v = qobject_input_visitor_new_flat_confused(options, errp); ++ if (!v) { + goto fail; + } + +- v = qobject_input_visitor_new_keyval(crumpled); + visit_type_BlockdevOptionsSsh(v, NULL, &result, &local_err); + visit_free(v); +- qobject_unref(crumpled); + + if (local_err) { + error_propagate(errp, local_err); +diff --git a/block/vhdx.c b/block/vhdx.c +index 728d8b3..6731298 100644 +--- a/block/vhdx.c ++++ b/block/vhdx.c +@@ -1964,7 +1964,6 @@ static int coroutine_fn vhdx_co_create_opts(const char *filename, + { + BlockdevCreateOptions *create_options = NULL; + QDict *qdict; +- QObject *qobj; + Visitor *v; + BlockDriverState *bs = NULL; + Error *local_err = NULL; +@@ -2003,14 +2002,12 @@ static int coroutine_fn vhdx_co_create_opts(const char *filename, + qdict_put_str(qdict, "driver", "vhdx"); + qdict_put_str(qdict, "file", bs->node_name); + +- qobj = qdict_crumple_for_keyval_qiv(qdict, errp); +- if (!qobj) { ++ v = qobject_input_visitor_new_flat_confused(qdict, errp); ++ if (!v) { + ret = -EINVAL; + goto fail; + } + +- v = qobject_input_visitor_new_keyval(qobj); +- qobject_unref(qobj); + visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err); + visit_free(v); + +diff --git a/block/vpc.c b/block/vpc.c +index a9bb041..bf294ab 100644 +--- a/block/vpc.c ++++ b/block/vpc.c +@@ -1082,7 +1082,6 @@ static int coroutine_fn vpc_co_create_opts(const char *filename, + { + BlockdevCreateOptions *create_options = NULL; + QDict *qdict; +- QObject *qobj; + Visitor *v; + BlockDriverState *bs = NULL; + Error *local_err = NULL; +@@ -1119,14 +1118,12 @@ static int coroutine_fn vpc_co_create_opts(const char *filename, + qdict_put_str(qdict, "driver", "vpc"); + qdict_put_str(qdict, "file", bs->node_name); + +- qobj = qdict_crumple_for_keyval_qiv(qdict, errp); +- if (!qobj) { ++ v = qobject_input_visitor_new_flat_confused(qdict, errp); ++ if (!v) { + ret = -EINVAL; + goto fail; + } + +- v = qobject_input_visitor_new_keyval(qobj); +- qobject_unref(qobj); + visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err); + visit_free(v); + +diff --git a/include/block/qdict.h b/include/block/qdict.h +index 47d9638..d8cb502 100644 +--- a/include/block/qdict.h ++++ b/include/block/qdict.h +@@ -21,7 +21,6 @@ void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start); + void qdict_array_split(QDict *src, QList **dst); + int qdict_array_entries(QDict *src, const char *subqdict); + QObject *qdict_crumple(const QDict *src, Error **errp); +-QObject *qdict_crumple_for_keyval_qiv(QDict *qdict, Error **errp); + void qdict_flatten(QDict *qdict); + + typedef struct QDictRenames { +@@ -30,4 +29,6 @@ typedef struct QDictRenames { + } QDictRenames; + bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp); + ++Visitor *qobject_input_visitor_new_flat_confused(QDict *qdict, ++ Error **errp); + #endif +diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c +index aba372c..41f39ab 100644 +--- a/qobject/block-qdict.c ++++ b/qobject/block-qdict.c +@@ -13,6 +13,7 @@ + #include "qapi/qmp/qlist.h" + #include "qapi/qmp/qnum.h" + #include "qapi/qmp/qstring.h" ++#include "qapi/qobject-input-visitor.h" + #include "qemu/cutils.h" + #include "qapi/error.h" + +@@ -529,7 +530,7 @@ QObject *qdict_crumple(const QDict *src, Error **errp) + * used for anything else, and it should go away once the block + * subsystem has been cleaned up. + */ +-QObject *qdict_crumple_for_keyval_qiv(QDict *src, Error **errp) ++static QObject *qdict_crumple_for_keyval_qiv(QDict *src, Error **errp) + { + QDict *tmp = NULL; + char *buf; +@@ -695,3 +696,28 @@ bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp) + } + return true; + } ++ ++/* ++ * Create a QObject input visitor for flat @qdict with possibly ++ * confused scalar types. ++ * ++ * The block subsystem uses this function to visit its flat QDict with ++ * possibly confused scalar types. It should not be used for anything ++ * else, and it should go away once the block subsystem has been ++ * cleaned up. ++ */ ++Visitor *qobject_input_visitor_new_flat_confused(QDict *qdict, ++ Error **errp) ++{ ++ QObject *crumpled; ++ Visitor *v; ++ ++ crumpled = qdict_crumple_for_keyval_qiv(qdict, errp); ++ if (!crumpled) { ++ return NULL; ++ } ++ ++ v = qobject_input_visitor_new_keyval(crumpled); ++ qobject_unref(crumpled); ++ return v; ++} +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Fix-blockdev-blockdev-add-for-empty-objects-an.patch b/SOURCES/kvm-block-Fix-blockdev-blockdev-add-for-empty-objects-an.patch new file mode 100644 index 0000000..fed55e2 --- /dev/null +++ b/SOURCES/kvm-block-Fix-blockdev-blockdev-add-for-empty-objects-an.patch @@ -0,0 +1,278 @@ +From 91f887335e57e6cdd891d7341ac070ca9359ac82 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Mon, 18 Jun 2018 08:43:28 +0200 +Subject: [PATCH 21/54] block: Fix -blockdev / blockdev-add for empty objects + and arrays + +RH-Author: Markus Armbruster +Message-id: <20180618084330.30009-22-armbru@redhat.com> +Patchwork-id: 80726 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 21/23] block: Fix -blockdev / blockdev-add for empty objects and arrays +Bugzilla: 1557995 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +-blockdev and blockdev-add silently ignore empty objects and arrays in +their argument. That's because qmp_blockdev_add() converts the +argument to a flat QDict, and qdict_flatten() eats empty QDict and +QList members. For instance, we ignore an empty BlockdevOptions +member @cache. No real harm, as absent means the same as empty there. + +Thus, the flaw puts an artificial restriction on the QAPI schema: we +can't have potentially empty objects and arrays within +BlockdevOptions, except when they're optional and "empty" has the same +meaning as "absent". + +Our QAPI schema satisfies this restriction (I checked), but it's a +trap for the unwary, and a temptation to employ awkward workarounds +for the wary. Let's get rid of it. + +Change qdict_flatten() and qdict_crumple() to treat empty dictionaries +and lists exactly like scalars. + +Signed-off-by: Markus Armbruster +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit 2860b2b2cb883969c8f6464bd9f8bc88742c5c73) +Signed-off-by: Miroslav Rezanina +--- + qobject/block-qdict.c | 54 +++++++++++++++++++++++++++++------------------ + tests/check-block-qdict.c | 38 ++++++++++++++++++++++++++------- + 2 files changed, 63 insertions(+), 29 deletions(-) + +diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c +index e51a3d2..df83308 100644 +--- a/qobject/block-qdict.c ++++ b/qobject/block-qdict.c +@@ -56,6 +56,8 @@ static void qdict_flatten_qlist(QList *qlist, QDict *target, const char *prefix) + { + QObject *value; + const QListEntry *entry; ++ QDict *dict_val; ++ QList *list_val; + char *new_key; + int i; + +@@ -69,16 +71,18 @@ static void qdict_flatten_qlist(QList *qlist, QDict *target, const char *prefix) + + for (i = 0; entry; entry = qlist_next(entry), i++) { + value = qlist_entry_obj(entry); ++ dict_val = qobject_to(QDict, value); ++ list_val = qobject_to(QList, value); + new_key = g_strdup_printf("%s.%i", prefix, i); + + /* + * Flatten non-empty QDict and QList recursively into @target, + * copy other objects to @target + */ +- if (qobject_type(value) == QTYPE_QDICT) { +- qdict_flatten_qdict(qobject_to(QDict, value), target, new_key); +- } else if (qobject_type(value) == QTYPE_QLIST) { +- qdict_flatten_qlist(qobject_to(QList, value), target, new_key); ++ if (dict_val && qdict_size(dict_val)) { ++ qdict_flatten_qdict(dict_val, target, new_key); ++ } else if (list_val && !qlist_empty(list_val)) { ++ qdict_flatten_qlist(list_val, target, new_key); + } else { + qdict_put_obj(target, new_key, qobject_ref(value)); + } +@@ -91,6 +95,8 @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix) + { + QObject *value; + const QDictEntry *entry, *next; ++ QDict *dict_val; ++ QList *list_val; + char *new_key; + + entry = qdict_first(qdict); +@@ -98,6 +104,8 @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix) + while (entry != NULL) { + next = qdict_next(qdict, entry); + value = qdict_entry_value(entry); ++ dict_val = qobject_to(QDict, value); ++ list_val = qobject_to(QList, value); + new_key = NULL; + + if (prefix) { +@@ -108,12 +116,12 @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix) + * Flatten non-empty QDict and QList recursively into @target, + * copy other objects to @target + */ +- if (qobject_type(value) == QTYPE_QDICT) { +- qdict_flatten_qdict(qobject_to(QDict, value), target, ++ if (dict_val && qdict_size(dict_val)) { ++ qdict_flatten_qdict(dict_val, target, + new_key ? new_key : entry->key); + qdict_del(qdict, entry->key); +- } else if (qobject_type(value) == QTYPE_QLIST) { +- qdict_flatten_qlist(qobject_to(QList, value), target, ++ } else if (list_val && !qlist_empty(list_val)) { ++ qdict_flatten_qlist(list_val, target, + new_key ? new_key : entry->key); + qdict_del(qdict, entry->key); + } else if (target != qdict) { +@@ -127,10 +135,11 @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix) + } + + /** +- * qdict_flatten(): For each nested QDict with key x, all fields with key y +- * are moved to this QDict and their key is renamed to "x.y". For each nested +- * QList with key x, the field at index y is moved to this QDict with the key +- * "x.y" (i.e., the reverse of what qdict_array_split() does). ++ * qdict_flatten(): For each nested non-empty QDict with key x, all ++ * fields with key y are moved to this QDict and their key is renamed ++ * to "x.y". For each nested non-empty QList with key x, the field at ++ * index y is moved to this QDict with the key "x.y" (i.e., the ++ * reverse of what qdict_array_split() does). + * This operation is applied recursively for nested QDicts and QLists. + */ + void qdict_flatten(QDict *qdict) +@@ -361,8 +370,8 @@ static int qdict_is_list(QDict *maybe_list, Error **errp) + * @src: the original flat dictionary (only scalar values) to crumple + * + * Takes a flat dictionary whose keys use '.' separator to indicate +- * nesting, and values are scalars, and crumples it into a nested +- * structure. ++ * nesting, and values are scalars, empty dictionaries or empty lists, ++ * and crumples it into a nested structure. + * + * To include a literal '.' in a key name, it must be escaped as '..' + * +@@ -399,6 +408,8 @@ QObject *qdict_crumple(const QDict *src, Error **errp) + { + const QDictEntry *ent; + QDict *two_level, *multi_level = NULL, *child_dict; ++ QDict *dict_val; ++ QList *list_val; + QObject *dst = NULL, *child; + size_t i; + char *prefix = NULL; +@@ -409,10 +420,11 @@ QObject *qdict_crumple(const QDict *src, Error **errp) + + /* Step 1: split our totally flat dict into a two level dict */ + for (ent = qdict_first(src); ent != NULL; ent = qdict_next(src, ent)) { +- if (qobject_type(ent->value) == QTYPE_QDICT || +- qobject_type(ent->value) == QTYPE_QLIST) { +- error_setg(errp, "Value %s is not a scalar", +- ent->key); ++ dict_val = qobject_to(QDict, ent->value); ++ list_val = qobject_to(QList, ent->value); ++ if ((dict_val && qdict_size(dict_val)) ++ || (list_val && !qlist_empty(list_val))) { ++ error_setg(errp, "Value %s is not flat", ent->key); + goto error; + } + +@@ -451,9 +463,9 @@ QObject *qdict_crumple(const QDict *src, Error **errp) + multi_level = qdict_new(); + for (ent = qdict_first(two_level); ent != NULL; + ent = qdict_next(two_level, ent)) { +- QDict *dict = qobject_to(QDict, ent->value); +- if (dict) { +- child = qdict_crumple(dict, errp); ++ dict_val = qobject_to(QDict, ent->value); ++ if (dict_val && qdict_size(dict_val)) { ++ child = qdict_crumple(dict_val, errp); + if (!child) { + goto error; + } +diff --git a/tests/check-block-qdict.c b/tests/check-block-qdict.c +index 2da16f0..1d20fcc 100644 +--- a/tests/check-block-qdict.c ++++ b/tests/check-block-qdict.c +@@ -79,10 +79,10 @@ static void qdict_flatten_test(void) + * "e.1.2.b": 1, + * "f.c": 2, + * "f.d": 3, +- * "g": 4 ++ * "g": 4, ++ * "y.0": {}, ++ * "z.a": [] + * } +- * +- * Note that "y" and "z" get eaten. + */ + + qdict_put_int(e_1_2, "a", 0); +@@ -117,8 +117,10 @@ static void qdict_flatten_test(void) + g_assert(qdict_get_int(root, "f.c") == 2); + g_assert(qdict_get_int(root, "f.d") == 3); + g_assert(qdict_get_int(root, "g") == 4); ++ g_assert(!qdict_size(qdict_get_qdict(root, "y.0"))); ++ g_assert(qlist_empty(qdict_get_qlist(root, "z.a"))); + +- g_assert(qdict_size(root) == 8); ++ g_assert(qdict_size(root) == 10); + + qobject_unref(root); + } +@@ -387,7 +389,8 @@ static void qdict_join_test(void) + static void qdict_crumple_test_recursive(void) + { + QDict *src, *dst, *rule, *vnc, *acl, *listen; +- QList *rules; ++ QDict *empty, *empty_dict, *empty_list_0; ++ QList *rules, *empty_list, *empty_dict_a; + + src = qdict_new(); + qdict_put_str(src, "vnc.listen.addr", "127.0.0.1"); +@@ -399,10 +402,12 @@ static void qdict_crumple_test_recursive(void) + qdict_put_str(src, "vnc.acl.default", "deny"); + qdict_put_str(src, "vnc.acl..name", "acl0"); + qdict_put_str(src, "vnc.acl.rule..name", "acl0"); ++ qdict_put(src, "empty.dict.a", qlist_new()); ++ qdict_put(src, "empty.list.0", qdict_new()); + + dst = qobject_to(QDict, qdict_crumple(src, &error_abort)); + g_assert(dst); +- g_assert_cmpint(qdict_size(dst), ==, 1); ++ g_assert_cmpint(qdict_size(dst), ==, 2); + + vnc = qdict_get_qdict(dst, "vnc"); + g_assert(vnc); +@@ -440,6 +445,21 @@ static void qdict_crumple_test_recursive(void) + g_assert_cmpstr("acl0", ==, qdict_get_str(vnc, "acl.name")); + g_assert_cmpstr("acl0", ==, qdict_get_str(acl, "rule.name")); + ++ empty = qdict_get_qdict(dst, "empty"); ++ g_assert(empty); ++ g_assert_cmpint(qdict_size(empty), ==, 2); ++ empty_dict = qdict_get_qdict(empty, "dict"); ++ g_assert(empty_dict); ++ g_assert_cmpint(qdict_size(empty_dict), ==, 1); ++ empty_dict_a = qdict_get_qlist(empty_dict, "a"); ++ g_assert(empty_dict_a && qlist_empty(empty_dict_a)); ++ empty_list = qdict_get_qlist(empty, "list"); ++ g_assert(empty_list); ++ g_assert_cmpint(qlist_size(empty_list), ==, 1); ++ empty_list_0 = qobject_to(QDict, qlist_pop(empty_list)); ++ g_assert(empty_list_0); ++ g_assert_cmpint(qdict_size(empty_list_0), ==, 0); ++ + qobject_unref(src); + qobject_unref(dst); + } +@@ -587,7 +607,7 @@ static void qdict_rename_keys_test(void) + + static void qdict_crumple_test_bad_inputs(void) + { +- QDict *src; ++ QDict *src, *nested; + Error *error = NULL; + + src = qdict_new(); +@@ -614,7 +634,9 @@ static void qdict_crumple_test_bad_inputs(void) + + src = qdict_new(); + /* The input should be flat, ie no dicts or lists */ +- qdict_put(src, "rule.a", qdict_new()); ++ nested = qdict_new(); ++ qdict_put(nested, "x", qdict_new()); ++ qdict_put(src, "rule.a", nested); + qdict_put_str(src, "rule.b", "allow"); + + g_assert(qdict_crumple(src, &error) == NULL); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Fix-blockdev-for-certain-non-string-scalars.patch b/SOURCES/kvm-block-Fix-blockdev-for-certain-non-string-scalars.patch new file mode 100644 index 0000000..6c277e7 --- /dev/null +++ b/SOURCES/kvm-block-Fix-blockdev-for-certain-non-string-scalars.patch @@ -0,0 +1,302 @@ +From 26de0d4fe93a094dcf7aef4c2b139c46c1117a99 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Mon, 18 Jun 2018 08:43:17 +0200 +Subject: [PATCH 10/54] block: Fix -blockdev for certain non-string scalars + +RH-Author: Markus Armbruster +Message-id: <20180618084330.30009-11-armbru@redhat.com> +Patchwork-id: 80743 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 10/23] block: Fix -blockdev for certain non-string scalars +Bugzilla: 1557995 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Configuration flows through the block subsystem in a rather peculiar +way. Configuration made with -drive enters it as QemuOpts. +Configuration made with -blockdev / blockdev-add enters it as QAPI +type BlockdevOptions. The block subsystem uses QDict, QemuOpts and +QAPI types internally. The precise flow is next to impossible to +explain (I tried for this commit message, but gave up after wasting +several hours). What I can explain is a flaw in the BlockDriver +interface that leads to this bug: + + $ qemu-system-x86_64 -blockdev node-name=n1,driver=nfs,server.type=inet,server.host=localhost,path=/foo/bar,user=1234 + qemu-system-x86_64: -blockdev node-name=n1,driver=nfs,server.type=inet,server.host=localhost,path=/foo/bar,user=1234: Internal error: parameter user invalid + +QMP blockdev-add is broken the same way. + +Here's what happens. The block layer passes configuration represented +as flat QDict (with dotted keys) to BlockDriver methods +.bdrv_file_open(). The QDict's members are typed according to the +QAPI schema. + +nfs_file_open() converts it to QAPI type BlockdevOptionsNfs, with +qdict_crumple() and a qobject input visitor. + +This visitor comes in two flavors. The plain flavor requires scalars +to be typed according to the QAPI schema. That's the case here. The +keyval flavor requires string scalars. That's not the case here. +nfs_file_open() uses the latter, and promptly falls apart for members +@user, @group, @tcp-syn-count, @readahead-size, @page-cache-size, +@debug. + +Switching to the plain flavor would fix -blockdev, but break -drive, +because there the scalars arrive in nfs_file_open() as strings. + +The proper fix would be to replace the QDict by QAPI type +BlockdevOptions in the BlockDriver interface. Sadly, that's beyond my +reach right now. + +Next best would be to fix the block layer to always pass correctly +typed QDicts to the BlockDriver methods. Also beyond my reach. + +What I can do is throw another hack onto the pile: have +nfs_file_open() convert all members to string, so use of the keyval +flavor actually works, by replacing qdict_crumple() by new function +qdict_crumple_for_keyval_qiv(). + +The pattern "pass result of qdict_crumple() to +qobject_input_visitor_new_keyval()" occurs several times more: + +* qemu_rbd_open() + + Same issue as nfs_file_open(), but since BlockdevOptionsRbd has only + string members, its only a latent bug. Fix it anyway. + +* parallels_co_create_opts(), qcow_co_create_opts(), + qcow2_co_create_opts(), bdrv_qed_co_create_opts(), + sd_co_create_opts(), vhdx_co_create_opts(), vpc_co_create_opts() + + These work, because they create the QDict with + qemu_opts_to_qdict_filtered(), which creates only string scalars. + The function sports a TODO comment asking for better typing; that's + going to be fun. Use qdict_crumple_for_keyval_qiv() to be safe. + +Signed-off-by: Markus Armbruster +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit e5af0da1dcbfb1a4694150f9954554fb6df88819) +Signed-off-by: Miroslav Rezanina +--- + block/nfs.c | 2 +- + block/parallels.c | 2 +- + block/qcow.c | 2 +- + block/qcow2.c | 2 +- + block/qed.c | 2 +- + block/rbd.c | 2 +- + block/sheepdog.c | 2 +- + block/vhdx.c | 2 +- + block/vpc.c | 2 +- + include/block/qdict.h | 1 + + qobject/block-qdict.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 11 files changed, 67 insertions(+), 9 deletions(-) + +diff --git a/block/nfs.c b/block/nfs.c +index 5159ef0..4090d28 100644 +--- a/block/nfs.c ++++ b/block/nfs.c +@@ -560,7 +560,7 @@ static BlockdevOptionsNfs *nfs_options_qdict_to_qapi(QDict *options, + Visitor *v; + Error *local_err = NULL; + +- crumpled = qdict_crumple(options, errp); ++ crumpled = qdict_crumple_for_keyval_qiv(options, errp); + if (crumpled == NULL) { + return NULL; + } +diff --git a/block/parallels.c b/block/parallels.c +index 0ee1f6a..aa58955 100644 +--- a/block/parallels.c ++++ b/block/parallels.c +@@ -651,7 +651,7 @@ static int coroutine_fn parallels_co_create_opts(const char *filename, + qdict_put_str(qdict, "driver", "parallels"); + qdict_put_str(qdict, "file", bs->node_name); + +- qobj = qdict_crumple(qdict, errp); ++ qobj = qdict_crumple_for_keyval_qiv(qdict, errp); + qobject_unref(qdict); + qdict = qobject_to(QDict, qobj); + if (qdict == NULL) { +diff --git a/block/qcow.c b/block/qcow.c +index fb821ad..14b7296 100644 +--- a/block/qcow.c ++++ b/block/qcow.c +@@ -995,7 +995,7 @@ static int coroutine_fn qcow_co_create_opts(const char *filename, + qdict_put_str(qdict, "driver", "qcow"); + qdict_put_str(qdict, "file", bs->node_name); + +- qobj = qdict_crumple(qdict, errp); ++ qobj = qdict_crumple_for_keyval_qiv(qdict, errp); + qobject_unref(qdict); + qdict = qobject_to(QDict, qobj); + if (qdict == NULL) { +diff --git a/block/qcow2.c b/block/qcow2.c +index fa9f557..fa06b41 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -3139,7 +3139,7 @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt + qdict_put_str(qdict, "file", bs->node_name); + + /* Now get the QAPI type BlockdevCreateOptions */ +- qobj = qdict_crumple(qdict, errp); ++ qobj = qdict_crumple_for_keyval_qiv(qdict, errp); + qobject_unref(qdict); + qdict = qobject_to(QDict, qobj); + if (qdict == NULL) { +diff --git a/block/qed.c b/block/qed.c +index 9a8997a..d8810f5 100644 +--- a/block/qed.c ++++ b/block/qed.c +@@ -763,7 +763,7 @@ static int coroutine_fn bdrv_qed_co_create_opts(const char *filename, + qdict_put_str(qdict, "driver", "qed"); + qdict_put_str(qdict, "file", bs->node_name); + +- qobj = qdict_crumple(qdict, errp); ++ qobj = qdict_crumple_for_keyval_qiv(qdict, errp); + qobject_unref(qdict); + qdict = qobject_to(QDict, qobj); + if (qdict == NULL) { +diff --git a/block/rbd.c b/block/rbd.c +index e695cf2..0b5455f 100644 +--- a/block/rbd.c ++++ b/block/rbd.c +@@ -640,7 +640,7 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags, + } + + /* Convert the remaining options into a QAPI object */ +- crumpled = qdict_crumple(options, errp); ++ crumpled = qdict_crumple_for_keyval_qiv(options, errp); + if (crumpled == NULL) { + r = -EINVAL; + goto out; +diff --git a/block/sheepdog.c b/block/sheepdog.c +index fd3876f..821a3c4 100644 +--- a/block/sheepdog.c ++++ b/block/sheepdog.c +@@ -2218,7 +2218,7 @@ static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts, + } + + /* Get the QAPI object */ +- crumpled = qdict_crumple(qdict, errp); ++ crumpled = qdict_crumple_for_keyval_qiv(qdict, errp); + if (crumpled == NULL) { + ret = -EINVAL; + goto fail; +diff --git a/block/vhdx.c b/block/vhdx.c +index 26c05aa..32939c4 100644 +--- a/block/vhdx.c ++++ b/block/vhdx.c +@@ -2003,7 +2003,7 @@ static int coroutine_fn vhdx_co_create_opts(const char *filename, + qdict_put_str(qdict, "driver", "vhdx"); + qdict_put_str(qdict, "file", bs->node_name); + +- qobj = qdict_crumple(qdict, errp); ++ qobj = qdict_crumple_for_keyval_qiv(qdict, errp); + qobject_unref(qdict); + qdict = qobject_to(QDict, qobj); + if (qdict == NULL) { +diff --git a/block/vpc.c b/block/vpc.c +index 41c8c98..16178e5 100644 +--- a/block/vpc.c ++++ b/block/vpc.c +@@ -1119,7 +1119,7 @@ static int coroutine_fn vpc_co_create_opts(const char *filename, + qdict_put_str(qdict, "driver", "vpc"); + qdict_put_str(qdict, "file", bs->node_name); + +- qobj = qdict_crumple(qdict, errp); ++ qobj = qdict_crumple_for_keyval_qiv(qdict, errp); + qobject_unref(qdict); + qdict = qobject_to(QDict, qobj); + if (qdict == NULL) { +diff --git a/include/block/qdict.h b/include/block/qdict.h +index 71c037a..47d9638 100644 +--- a/include/block/qdict.h ++++ b/include/block/qdict.h +@@ -21,6 +21,7 @@ void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start); + void qdict_array_split(QDict *src, QList **dst); + int qdict_array_entries(QDict *src, const char *subqdict); + QObject *qdict_crumple(const QDict *src, Error **errp); ++QObject *qdict_crumple_for_keyval_qiv(QDict *qdict, Error **errp); + void qdict_flatten(QDict *qdict); + + typedef struct QDictRenames { +diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c +index fb92010..aba372c 100644 +--- a/qobject/block-qdict.c ++++ b/qobject/block-qdict.c +@@ -9,7 +9,10 @@ + + #include "qemu/osdep.h" + #include "block/qdict.h" ++#include "qapi/qmp/qbool.h" + #include "qapi/qmp/qlist.h" ++#include "qapi/qmp/qnum.h" ++#include "qapi/qmp/qstring.h" + #include "qemu/cutils.h" + #include "qapi/error.h" + +@@ -514,6 +517,60 @@ QObject *qdict_crumple(const QDict *src, Error **errp) + } + + /** ++ * qdict_crumple_for_keyval_qiv: ++ * @src: the flat dictionary (only scalar values) to crumple ++ * @errp: location to store error ++ * ++ * Like qdict_crumple(), but additionally transforms scalar values so ++ * the result can be passed to qobject_input_visitor_new_keyval(). ++ * ++ * The block subsystem uses this function to prepare its flat QDict ++ * with possibly confused scalar types for a visit. It should not be ++ * used for anything else, and it should go away once the block ++ * subsystem has been cleaned up. ++ */ ++QObject *qdict_crumple_for_keyval_qiv(QDict *src, Error **errp) ++{ ++ QDict *tmp = NULL; ++ char *buf; ++ const char *s; ++ const QDictEntry *ent; ++ QObject *dst; ++ ++ for (ent = qdict_first(src); ent; ent = qdict_next(src, ent)) { ++ buf = NULL; ++ switch (qobject_type(ent->value)) { ++ case QTYPE_QNULL: ++ case QTYPE_QSTRING: ++ continue; ++ case QTYPE_QNUM: ++ s = buf = qnum_to_string(qobject_to(QNum, ent->value)); ++ break; ++ case QTYPE_QDICT: ++ case QTYPE_QLIST: ++ /* @src isn't flat; qdict_crumple() will fail */ ++ continue; ++ case QTYPE_QBOOL: ++ s = qbool_get_bool(qobject_to(QBool, ent->value)) ++ ? "on" : "off"; ++ break; ++ default: ++ abort(); ++ } ++ ++ if (!tmp) { ++ tmp = qdict_clone_shallow(src); ++ } ++ qdict_put(tmp, ent->key, qstring_from_str(s)); ++ g_free(buf); ++ } ++ ++ dst = qdict_crumple(tmp ?: src, errp); ++ qobject_unref(tmp); ++ return dst; ++} ++ ++/** + * qdict_array_entries(): Returns the number of direct array entries if the + * sub-QDict of src specified by the prefix in subqdict (or src itself for + * prefix == "") is valid as an array, i.e. the length of the created list if +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Fix-copy-on-read-crash-with-partial-final-clus.patch b/SOURCES/kvm-block-Fix-copy-on-read-crash-with-partial-final-clus.patch new file mode 100644 index 0000000..5fbb5ff --- /dev/null +++ b/SOURCES/kvm-block-Fix-copy-on-read-crash-with-partial-final-clus.patch @@ -0,0 +1,94 @@ +From aa04dc32326b3c03f0af75dd9a87530691cd53bf Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Thu, 12 Jul 2018 15:00:08 +0200 +Subject: [PATCH 40/89] block: Fix copy-on-read crash with partial final + cluster + +RH-Author: Kevin Wolf +Message-id: <20180712150008.23662-2-kwolf@redhat.com> +Patchwork-id: 81331 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 1/1] block: Fix copy-on-read crash with partial final cluster +Bugzilla: 1590640 +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng +RH-Acked-by: John Snow +RH-Acked-by: Richard Jones + +If the virtual disk size isn't aligned to full clusters, +bdrv_co_do_copy_on_readv() may get pnum == 0 before having the full +cluster completed, which will let it run into an assertion failure: + +qemu-io: block/io.c:1203: bdrv_co_do_copy_on_readv: Assertion `skip_bytes < pnum' failed. + +Check for EOF, assert that we read at least as much as the read request +originally wanted to have (which is true at EOF because otherwise +bdrv_check_byte_request() would already have returned an error) and +return success early even though we couldn't copy the full cluster. + +Signed-off-by: Kevin Wolf +(cherry picked from commit b0ddcbbb36a66a605eb232b905cb49b1cc72e74e) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/io.c | 6 ++++++ + tests/qemu-iotests/197 | 9 +++++++++ + tests/qemu-iotests/197.out | 8 ++++++++ + 3 files changed, 23 insertions(+) + +diff --git a/block/io.c b/block/io.c +index ad8afc0..ac36d1c 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -1095,6 +1095,12 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child, + pnum = MIN(cluster_bytes, max_transfer); + } + ++ /* Stop at EOF if the image ends in the middle of the cluster */ ++ if (ret == 0 && pnum == 0) { ++ assert(progress >= bytes); ++ break; ++ } ++ + assert(skip_bytes < pnum); + + if (ret <= 0) { +diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197 +index 3ae4975..0369aa5 100755 +--- a/tests/qemu-iotests/197 ++++ b/tests/qemu-iotests/197 +@@ -109,6 +109,15 @@ $QEMU_IO -f qcow2 -c map "$TEST_WRAP" + _check_test_img + $QEMU_IMG compare -f $IMGFMT -F qcow2 "$TEST_IMG" "$TEST_WRAP" + ++echo ++echo '=== Partial final cluster ===' ++echo ++ ++_make_test_img 1024 ++$QEMU_IO -f $IMGFMT -C -c 'read 0 1024' "$TEST_IMG" | _filter_qemu_io ++$QEMU_IO -f $IMGFMT -c map "$TEST_IMG" ++_check_test_img ++ + # success, all done + echo '*** done' + status=0 +diff --git a/tests/qemu-iotests/197.out b/tests/qemu-iotests/197.out +index 52b4137..8febda5 100644 +--- a/tests/qemu-iotests/197.out ++++ b/tests/qemu-iotests/197.out +@@ -23,4 +23,12 @@ can't open device TEST_DIR/t.wrap.qcow2: Can't use copy-on-read on read-only dev + 1023.938 MiB (0x3fff0000) bytes not allocated at offset 3 GiB (0xc0010000) + No errors were found on the image. + Images are identical. ++ ++=== Partial final cluster === ++ ++Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1024 ++read 1024/1024 bytes at offset 0 ++1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++1 KiB (0x400) bytes allocated at offset 0 bytes (0x0) ++No errors were found on the image. + *** done +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Fix-drive-for-certain-non-string-scalars.patch b/SOURCES/kvm-block-Fix-drive-for-certain-non-string-scalars.patch new file mode 100644 index 0000000..898f96b --- /dev/null +++ b/SOURCES/kvm-block-Fix-drive-for-certain-non-string-scalars.patch @@ -0,0 +1,123 @@ +From 0a45c26f9838054d3f97b35e82877239d4e7c920 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Mon, 18 Jun 2018 08:43:18 +0200 +Subject: [PATCH 11/54] block: Fix -drive for certain non-string scalars + +RH-Author: Markus Armbruster +Message-id: <20180618084330.30009-12-armbru@redhat.com> +Patchwork-id: 80737 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 11/23] block: Fix -drive for certain non-string scalars +Bugzilla: 1557995 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +The previous commit fixed -blockdev breakage due to misuse of the +qobject input visitor's keyval flavor in bdrv_file_open(). The commit +message explain why using the plain flavor would be just as wrong; it +would break -drive. Turns out we break it in three places: +nbd_open(), sd_open() and ssh_file_open(). They are even marked +FIXME. Example breakage: + + $ qemu-system-x86 -drive node-name=n1,driver=nbd,server.type=inet,server.host=localhost,server.port=1234,server.numeric=off + qemu-system-x86: -drive node-name=n1,driver=nbd,server.type=inet,server.host=localhost,server.port=1234,server.numeric=off: Invalid parameter type for 'numeric', expected: boolean + +Fix it the same way: replace qdict_crumple() by +qdict_crumple_for_keyval_qiv(), and switch from plain to the keyval +flavor. + +Signed-off-by: Markus Armbruster +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit 374c52467a38c2e811f6c0db4edc9ea7d5f34341) +Signed-off-by: Miroslav Rezanina +--- + block/nbd.c | 12 ++---------- + block/sheepdog.c | 12 ++---------- + block/ssh.c | 12 ++---------- + 3 files changed, 6 insertions(+), 30 deletions(-) + +diff --git a/block/nbd.c b/block/nbd.c +index f499830..b0be357 100644 +--- a/block/nbd.c ++++ b/block/nbd.c +@@ -273,20 +273,12 @@ static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options, + goto done; + } + +- crumpled_addr = qdict_crumple(addr, errp); ++ crumpled_addr = qdict_crumple_for_keyval_qiv(addr, errp); + if (!crumpled_addr) { + goto done; + } + +- /* +- * FIXME .numeric, .to, .ipv4 or .ipv6 don't work with -drive +- * server.type=inet. .to doesn't matter, it's ignored anyway. +- * That's because when @options come from -blockdev or +- * blockdev_add, members are typed according to the QAPI schema, +- * but when they come from -drive, they're all QString. The +- * visitor expects the former. +- */ +- iv = qobject_input_visitor_new(crumpled_addr); ++ iv = qobject_input_visitor_new_keyval(crumpled_addr); + visit_type_SocketAddress(iv, NULL, &saddr, &local_err); + if (local_err) { + error_propagate(errp, local_err); +diff --git a/block/sheepdog.c b/block/sheepdog.c +index 821a3c4..dd582d5 100644 +--- a/block/sheepdog.c ++++ b/block/sheepdog.c +@@ -546,20 +546,12 @@ static SocketAddress *sd_server_config(QDict *options, Error **errp) + + qdict_extract_subqdict(options, &server, "server."); + +- crumpled_server = qdict_crumple(server, errp); ++ crumpled_server = qdict_crumple_for_keyval_qiv(server, errp); + if (!crumpled_server) { + goto done; + } + +- /* +- * FIXME .numeric, .to, .ipv4 or .ipv6 don't work with -drive +- * server.type=inet. .to doesn't matter, it's ignored anyway. +- * That's because when @options come from -blockdev or +- * blockdev_add, members are typed according to the QAPI schema, +- * but when they come from -drive, they're all QString. The +- * visitor expects the former. +- */ +- iv = qobject_input_visitor_new(crumpled_server); ++ iv = qobject_input_visitor_new_keyval(crumpled_server); + visit_type_SocketAddress(iv, NULL, &saddr, &local_err); + if (local_err) { + error_propagate(errp, local_err); +diff --git a/block/ssh.c b/block/ssh.c +index 5931064..2fc7cd9 100644 +--- a/block/ssh.c ++++ b/block/ssh.c +@@ -623,20 +623,12 @@ static BlockdevOptionsSsh *ssh_parse_options(QDict *options, Error **errp) + } + + /* Create the QAPI object */ +- crumpled = qdict_crumple(options, errp); ++ crumpled = qdict_crumple_for_keyval_qiv(options, errp); + if (crumpled == NULL) { + goto fail; + } + +- /* +- * FIXME .numeric, .to, .ipv4 or .ipv6 don't work with -drive. +- * .to doesn't matter, it's ignored anyway. +- * That's because when @options come from -blockdev or +- * blockdev_add, members are typed according to the QAPI schema, +- * but when they come from -drive, they're all QString. The +- * visitor expects the former. +- */ +- v = qobject_input_visitor_new(crumpled); ++ v = qobject_input_visitor_new_keyval(crumpled); + visit_type_BlockdevOptionsSsh(v, NULL, &result, &local_err); + visit_free(v); + qobject_unref(crumpled); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Fix-flags-in-reopen-queue.patch b/SOURCES/kvm-block-Fix-flags-in-reopen-queue.patch deleted file mode 100644 index f3ecaba..0000000 --- a/SOURCES/kvm-block-Fix-flags-in-reopen-queue.patch +++ /dev/null @@ -1,60 +0,0 @@ -From bf0e9a6374d872bde330fb3c4994697250ef235b Mon Sep 17 00:00:00 2001 -From: Fam Zheng -Date: Tue, 13 Mar 2018 15:27:54 +0100 -Subject: [PATCH 1/4] block: Fix flags in reopen queue - -RH-Author: Fam Zheng -Message-id: <20180313152755.31475-2-famz@redhat.com> -Patchwork-id: 79273 -O-Subject: [RHV7.5 qemu-kvm-ma PATCH v4 1/2] block: Fix flags in reopen queue -Bugzilla: 1557206 -RH-Acked-by: Max Reitz -RH-Acked-by: Kevin Wolf -RH-Acked-by: Stefan Hajnoczi - -Reopen flags are not synchronized according to the -bdrv_reopen_queue_child precedence until bdrv_reopen_prepare. It is a -bit too late: we already check the consistency in bdrv_check_perm before -that. - -This fixes the bug that when bdrv_reopen a RO node as RW, the flags for -backing child are wrong. Before, we could recurse with flags.rw=1; now, -role->inherit_options + update_flags_from_options will make sure to -clear the bit when necessary. Note that this will not clear an -explicitly set bit, as in the case of parallel block jobs (e.g. -test_stream_parallel in 030), because the explicit options include -'read-only=false' (for an intermediate node used by a different job). - -Signed-off-by: Fam Zheng -Reviewed-by: Max Reitz -Signed-off-by: Kevin Wolf -Signed-off-by: Fam Zheng -Signed-off-by: Miroslav Rezanina ---- - block.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/block.c b/block.c -index ca8a46b..a1084e7 100644 ---- a/block.c -+++ b/block.c -@@ -2759,8 +2759,16 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, - - /* Inherit from parent node */ - if (parent_options) { -+ QemuOpts *opts; -+ QDict *options_copy; - assert(!flags); - role->inherit_options(&flags, options, parent_flags, parent_options); -+ options_copy = qdict_clone_shallow(options); -+ opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort); -+ qemu_opts_absorb_qdict(opts, options_copy, NULL); -+ update_flags_from_options(&flags, opts); -+ qemu_opts_del(opts); -+ QDECREF(options_copy); - } - - /* Old values are used for options that aren't set yet */ --- -1.8.3.1 - diff --git a/SOURCES/kvm-block-Fix-parameter-checking-in-bdrv_co_copy_range_i.patch b/SOURCES/kvm-block-Fix-parameter-checking-in-bdrv_co_copy_range_i.patch new file mode 100644 index 0000000..d26fc5b --- /dev/null +++ b/SOURCES/kvm-block-Fix-parameter-checking-in-bdrv_co_copy_range_i.patch @@ -0,0 +1,101 @@ +From b8f1b4c9b03d2ec06ed69d0f6769499d197eccd8 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Tue, 24 Jul 2018 12:50:06 +0200 +Subject: [PATCH 65/89] block: Fix parameter checking in + bdrv_co_copy_range_internal + +RH-Author: John Snow +Message-id: <20180718225511.14878-15-jsnow@redhat.com> +Patchwork-id: 81411 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 14/35] block: Fix parameter checking in bdrv_co_copy_range_internal +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Fam Zheng + +src may be NULL if BDRV_REQ_ZERO_WRITE flag is set, in this case only +check dst and dst->bs. This bug was introduced when moving in the +request tracking code from bdrv_co_copy_range, in 37aec7d75eb. + +This especially fixes the possible segfault when initializing src_bs +with a NULL src. + +Signed-off-by: Fam Zheng +Message-id: 20180703023758.14422-2-famz@redhat.com +Reviewed-by: Jeff Cody +Signed-off-by: Jeff Cody +(cherry picked from commit d4d3e5a0d53a57282955e8a3ed7acc1ca90552d9) +Signed-off-by: John Snow +--- + block/io.c | 28 +++++++++++++++------------- + 1 file changed, 15 insertions(+), 13 deletions(-) + +diff --git a/block/io.c b/block/io.c +index 136a5d0..7981239 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -2848,17 +2848,11 @@ static int coroutine_fn bdrv_co_copy_range_internal(BdrvChild *src, + bool recurse_src) + { + BdrvTrackedRequest src_req, dst_req; +- BlockDriverState *src_bs = src->bs; +- BlockDriverState *dst_bs = dst->bs; + int ret; + +- if (!src || !dst || !src->bs || !dst->bs) { ++ if (!dst || !dst->bs) { + return -ENOMEDIUM; + } +- ret = bdrv_check_byte_request(src->bs, src_offset, bytes); +- if (ret) { +- return ret; +- } + + ret = bdrv_check_byte_request(dst->bs, dst_offset, bytes); + if (ret) { +@@ -2868,17 +2862,25 @@ static int coroutine_fn bdrv_co_copy_range_internal(BdrvChild *src, + return bdrv_co_pwrite_zeroes(dst, dst_offset, bytes, flags); + } + ++ if (!src || !src->bs) { ++ return -ENOMEDIUM; ++ } ++ ret = bdrv_check_byte_request(src->bs, src_offset, bytes); ++ if (ret) { ++ return ret; ++ } ++ + if (!src->bs->drv->bdrv_co_copy_range_from + || !dst->bs->drv->bdrv_co_copy_range_to + || src->bs->encrypted || dst->bs->encrypted) { + return -ENOTSUP; + } + +- bdrv_inc_in_flight(src_bs); +- bdrv_inc_in_flight(dst_bs); +- tracked_request_begin(&src_req, src_bs, src_offset, ++ bdrv_inc_in_flight(src->bs); ++ bdrv_inc_in_flight(dst->bs); ++ tracked_request_begin(&src_req, src->bs, src_offset, + bytes, BDRV_TRACKED_READ); +- tracked_request_begin(&dst_req, dst_bs, dst_offset, ++ tracked_request_begin(&dst_req, dst->bs, dst_offset, + bytes, BDRV_TRACKED_WRITE); + + wait_serialising_requests(&src_req); +@@ -2896,8 +2898,8 @@ static int coroutine_fn bdrv_co_copy_range_internal(BdrvChild *src, + } + tracked_request_end(&src_req); + tracked_request_end(&dst_req); +- bdrv_dec_in_flight(src_bs); +- bdrv_dec_in_flight(dst_bs); ++ bdrv_dec_in_flight(src->bs); ++ bdrv_dec_in_flight(dst->bs); + return ret; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Fix-permissions-after-bdrv_reopen.patch b/SOURCES/kvm-block-Fix-permissions-after-bdrv_reopen.patch deleted file mode 100644 index 92e14ec..0000000 --- a/SOURCES/kvm-block-Fix-permissions-after-bdrv_reopen.patch +++ /dev/null @@ -1,152 +0,0 @@ -From b87d11b7f13dd4725fe801b014d425fa7753b1d0 Mon Sep 17 00:00:00 2001 -From: Kevin Wolf -Date: Mon, 4 Dec 2017 12:10:05 +0100 -Subject: [PATCH 34/36] block: Fix permissions after bdrv_reopen() - -RH-Author: Kevin Wolf -Message-id: <20171204121007.12964-7-kwolf@redhat.com> -Patchwork-id: 78112 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 6/8] block: Fix permissions after bdrv_reopen() -Bugzilla: 1492178 -RH-Acked-by: Fam Zheng -RH-Acked-by: Max Reitz -RH-Acked-by: Jeffrey Cody - -If we switch between read-only and read-write, the permissions that -image format drivers need on bs->file change, too. Make sure to update -the permissions during bdrv_reopen(). - -Signed-off-by: Kevin Wolf -Reviewed-by: Eric Blake -(cherry picked from commit 3045025991ebeec77ce89c8ec56e83858950bbb3) -Signed-off-by: Miroslav Rezanina ---- - block.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++ - include/block/block.h | 1 + - 2 files changed, 65 insertions(+) - -diff --git a/block.c b/block.c -index 0a7e2c6..bc8b80b 100644 ---- a/block.c -+++ b/block.c -@@ -2780,6 +2780,10 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, - bs_entry->state.explicit_options = explicit_options; - bs_entry->state.flags = flags; - -+ /* This needs to be overwritten in bdrv_reopen_prepare() */ -+ bs_entry->state.perm = UINT64_MAX; -+ bs_entry->state.shared_perm = 0; -+ - QLIST_FOREACH(child, &bs->children, next) { - QDict *new_child_options; - char *child_key_dot; -@@ -2886,6 +2890,52 @@ int bdrv_reopen(BlockDriverState *bs, int bdrv_flags, Error **errp) - return ret; - } - -+static BlockReopenQueueEntry *find_parent_in_reopen_queue(BlockReopenQueue *q, -+ BdrvChild *c) -+{ -+ BlockReopenQueueEntry *entry; -+ -+ QSIMPLEQ_FOREACH(entry, q, entry) { -+ BlockDriverState *bs = entry->state.bs; -+ BdrvChild *child; -+ -+ QLIST_FOREACH(child, &bs->children, next) { -+ if (child == c) { -+ return entry; -+ } -+ } -+ } -+ -+ return NULL; -+} -+ -+static void bdrv_reopen_perm(BlockReopenQueue *q, BlockDriverState *bs, -+ uint64_t *perm, uint64_t *shared) -+{ -+ BdrvChild *c; -+ BlockReopenQueueEntry *parent; -+ uint64_t cumulative_perms = 0; -+ uint64_t cumulative_shared_perms = BLK_PERM_ALL; -+ -+ QLIST_FOREACH(c, &bs->parents, next_parent) { -+ parent = find_parent_in_reopen_queue(q, c); -+ if (!parent) { -+ cumulative_perms |= c->perm; -+ cumulative_shared_perms &= c->shared_perm; -+ } else { -+ uint64_t nperm, nshared; -+ -+ bdrv_child_perm(parent->state.bs, bs, c, c->role, q, -+ parent->state.perm, parent->state.shared_perm, -+ &nperm, &nshared); -+ -+ cumulative_perms |= nperm; -+ cumulative_shared_perms &= nshared; -+ } -+ } -+ *perm = cumulative_perms; -+ *shared = cumulative_shared_perms; -+} - - /* - * Prepares a BlockDriverState for reopen. All changes are staged in the -@@ -2951,6 +3001,9 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, - goto error; - } - -+ /* Calculate required permissions after reopening */ -+ bdrv_reopen_perm(queue, reopen_state->bs, -+ &reopen_state->perm, &reopen_state->shared_perm); - - ret = bdrv_flush(reopen_state->bs); - if (ret) { -@@ -3006,6 +3059,12 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, - } while ((entry = qdict_next(reopen_state->options, entry))); - } - -+ ret = bdrv_check_perm(reopen_state->bs, queue, reopen_state->perm, -+ reopen_state->shared_perm, NULL, errp); -+ if (ret < 0) { -+ goto error; -+ } -+ - ret = 0; - - error: -@@ -3046,6 +3105,9 @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state) - - bdrv_refresh_limits(bs, NULL); - -+ bdrv_set_perm(reopen_state->bs, reopen_state->perm, -+ reopen_state->shared_perm); -+ - new_can_write = - !bdrv_is_read_only(bs) && !(bdrv_get_flags(bs) & BDRV_O_INACTIVE); - if (!old_can_write && new_can_write && drv->bdrv_reopen_bitmaps_rw) { -@@ -3079,6 +3141,8 @@ void bdrv_reopen_abort(BDRVReopenState *reopen_state) - } - - QDECREF(reopen_state->explicit_options); -+ -+ bdrv_abort_perm_update(reopen_state->bs); - } - - -diff --git a/include/block/block.h b/include/block/block.h -index 4d0d2da..59a3077 100644 ---- a/include/block/block.h -+++ b/include/block/block.h -@@ -166,6 +166,7 @@ typedef QSIMPLEQ_HEAD(BlockReopenQueue, BlockReopenQueueEntry) BlockReopenQueue; - typedef struct BDRVReopenState { - BlockDriverState *bs; - int flags; -+ uint64_t perm, shared_perm; - QDict *options; - QDict *explicit_options; - void *opaque; --- -1.8.3.1 - diff --git a/SOURCES/kvm-block-Formats-don-t-need-CONSISTENT_READ-with-NO_IO.patch b/SOURCES/kvm-block-Formats-don-t-need-CONSISTENT_READ-with-NO_IO.patch deleted file mode 100644 index 0db4ba1..0000000 --- a/SOURCES/kvm-block-Formats-don-t-need-CONSISTENT_READ-with-NO_IO.patch +++ /dev/null @@ -1,58 +0,0 @@ -From a80280654277c361714ec5f3925d2d6b077eca7b Mon Sep 17 00:00:00 2001 -From: Kevin Wolf -Date: Mon, 15 Jan 2018 11:23:37 +0100 -Subject: [PATCH 12/12] block: Formats don't need CONSISTENT_READ with NO_IO - -RH-Author: Kevin Wolf -Message-id: <20180115112337.20885-4-kwolf@redhat.com> -Patchwork-id: 78574 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH 3/3] block: Formats don't need CONSISTENT_READ with NO_IO -Bugzilla: 1515604 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Jeffrey Cody -RH-Acked-by: John Snow - -Commit 1f4ad7d fixed 'qemu-img info' for raw images that are currently -in use as a mirror target. It is not enough for image formats, though, -as these still unconditionally request BLK_PERM_CONSISTENT_READ. - -As this permission is geared towards whether the guest-visible data is -consistent, and has no impact on whether the metadata is sane, and -'qemu-img info' does not read guest-visible data (except for the raw -format), it makes sense to not require BLK_PERM_CONSISTENT_READ if there -is not going to be any guest I/O performed, regardless of image format. - -Signed-off-by: Kevin Wolf -(cherry picked from commit 5fbfabd313b77e1cc7038ae8c4481c4b9f8b650a) -Signed-off-by: Miroslav Rezanina ---- - block.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/block.c b/block.c -index 90a60bc..ca8a46b 100644 ---- a/block.c -+++ b/block.c -@@ -1885,6 +1885,8 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, - assert(role == &child_backing || role == &child_file); - - if (!backing) { -+ int flags = bdrv_reopen_get_flags(reopen_queue, bs); -+ - /* Apart from the modifications below, the same permissions are - * forwarded and left alone as for filters */ - bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared, -@@ -1897,7 +1899,9 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, - - /* bs->file always needs to be consistent because of the metadata. We - * can never allow other users to resize or write to it. */ -- perm |= BLK_PERM_CONSISTENT_READ; -+ if (!(flags & BDRV_O_NO_IO)) { -+ perm |= BLK_PERM_CONSISTENT_READ; -+ } - shared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE); - } else { - /* We want consistent read from backing files if the parent needs it. --- -1.8.3.1 - diff --git a/SOURCES/kvm-block-Honour-BDRV_REQ_NO_SERIALISING-in-copy-range.patch b/SOURCES/kvm-block-Honour-BDRV_REQ_NO_SERIALISING-in-copy-range.patch new file mode 100644 index 0000000..ba120e1 --- /dev/null +++ b/SOURCES/kvm-block-Honour-BDRV_REQ_NO_SERIALISING-in-copy-range.patch @@ -0,0 +1,72 @@ +From d1de83879c75bd2d73e9c4f24d81bfc83b992f5a Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 18 Jul 2018 22:54:51 +0200 +Subject: [PATCH 66/89] block: Honour BDRV_REQ_NO_SERIALISING in copy range + +RH-Author: John Snow +Message-id: <20180718225511.14878-16-jsnow@redhat.com> +Patchwork-id: 81402 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 15/35] block: Honour BDRV_REQ_NO_SERIALISING in copy range +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Fam Zheng + +This semantics is needed by drive-backup so implement it before using +this API there. + +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Fam Zheng +Message-id: 20180703023758.14422-3-famz@redhat.com +Signed-off-by: Jeff Cody +(cherry picked from commit dee12de89380483656072f775f5ef99f4426f966) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/io.c | 6 ++++-- + include/block/block.h | 5 +++-- + 2 files changed, 7 insertions(+), 4 deletions(-) + +diff --git a/block/io.c b/block/io.c +index 7981239..b6754f3 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -2883,8 +2883,10 @@ static int coroutine_fn bdrv_co_copy_range_internal(BdrvChild *src, + tracked_request_begin(&dst_req, dst->bs, dst_offset, + bytes, BDRV_TRACKED_WRITE); + +- wait_serialising_requests(&src_req); +- wait_serialising_requests(&dst_req); ++ if (!(flags & BDRV_REQ_NO_SERIALISING)) { ++ wait_serialising_requests(&src_req); ++ wait_serialising_requests(&dst_req); ++ } + if (recurse_src) { + ret = src->bs->drv->bdrv_co_copy_range_from(src->bs, + src, src_offset, +diff --git a/include/block/block.h b/include/block/block.h +index c3cfb40..e1d5e47 100644 +--- a/include/block/block.h ++++ b/include/block/block.h +@@ -636,13 +636,14 @@ void bdrv_unregister_buf(BlockDriverState *bs, void *host); + * @dst: Destination child to copy data to + * @dst_offset: offset in @dst image to write data + * @bytes: number of bytes to copy +- * @flags: request flags. Must be one of: +- * 0 - actually read data from src; ++ * @flags: request flags. Supported flags: + * BDRV_REQ_ZERO_WRITE - treat the @src range as zero data and do zero + * write on @dst as if bdrv_co_pwrite_zeroes is + * called. Used to simplify caller code, or + * during BlockDriver.bdrv_co_copy_range_from() + * recursion. ++ * BDRV_REQ_NO_SERIALISING - do not serialize with other overlapping ++ * requests currently in flight. + * + * Returns: 0 if succeeded; negative error code if failed. + **/ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Introduce-API-for-copy-offloading.patch b/SOURCES/kvm-block-Introduce-API-for-copy-offloading.patch new file mode 100644 index 0000000..23ee180 --- /dev/null +++ b/SOURCES/kvm-block-Introduce-API-for-copy-offloading.patch @@ -0,0 +1,236 @@ +From 62cb216e19f41b1d1c4c5d4523df56dce865ab30 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 29 Jun 2018 06:11:41 +0200 +Subject: [PATCH 37/57] block: Introduce API for copy offloading + +RH-Author: Fam Zheng +Message-id: <20180629061153.12687-2-famz@redhat.com> +Patchwork-id: 81153 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v2 01/13] block: Introduce API for copy offloading +Bugzilla: 1482537 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Kevin Wolf + +Introduce the bdrv_co_copy_range() API for copy offloading. Block +drivers implementing this API support efficient copy operations that +avoid reading each block from the source device and writing it to the +destination devices. Examples of copy offload primitives are SCSI +EXTENDED COPY and Linux copy_file_range(2). + +Signed-off-by: Fam Zheng +Reviewed-by: Stefan Hajnoczi +Message-id: 20180601092648.24614-2-famz@redhat.com +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit fcc6767836efe1b160289905dce7228d594c123c) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/io.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++ + include/block/block.h | 32 ++++++++++++++++ + include/block/block_int.h | 38 +++++++++++++++++++ + 3 files changed, 167 insertions(+) + +diff --git a/block/io.c b/block/io.c +index fada4ef..5c043a4 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -2832,3 +2832,100 @@ void bdrv_unregister_buf(BlockDriverState *bs, void *host) + bdrv_unregister_buf(child->bs, host); + } + } ++ ++static int coroutine_fn bdrv_co_copy_range_internal(BdrvChild *src, ++ uint64_t src_offset, ++ BdrvChild *dst, ++ uint64_t dst_offset, ++ uint64_t bytes, ++ BdrvRequestFlags flags, ++ bool recurse_src) ++{ ++ int ret; ++ ++ if (!src || !dst || !src->bs || !dst->bs) { ++ return -ENOMEDIUM; ++ } ++ ret = bdrv_check_byte_request(src->bs, src_offset, bytes); ++ if (ret) { ++ return ret; ++ } ++ ++ ret = bdrv_check_byte_request(dst->bs, dst_offset, bytes); ++ if (ret) { ++ return ret; ++ } ++ if (flags & BDRV_REQ_ZERO_WRITE) { ++ return bdrv_co_pwrite_zeroes(dst, dst_offset, bytes, flags); ++ } ++ ++ if (!src->bs->drv->bdrv_co_copy_range_from ++ || !dst->bs->drv->bdrv_co_copy_range_to ++ || src->bs->encrypted || dst->bs->encrypted) { ++ return -ENOTSUP; ++ } ++ if (recurse_src) { ++ return src->bs->drv->bdrv_co_copy_range_from(src->bs, ++ src, src_offset, ++ dst, dst_offset, ++ bytes, flags); ++ } else { ++ return dst->bs->drv->bdrv_co_copy_range_to(dst->bs, ++ src, src_offset, ++ dst, dst_offset, ++ bytes, flags); ++ } ++} ++ ++/* Copy range from @src to @dst. ++ * ++ * See the comment of bdrv_co_copy_range for the parameter and return value ++ * semantics. */ ++int coroutine_fn bdrv_co_copy_range_from(BdrvChild *src, uint64_t src_offset, ++ BdrvChild *dst, uint64_t dst_offset, ++ uint64_t bytes, BdrvRequestFlags flags) ++{ ++ return bdrv_co_copy_range_internal(src, src_offset, dst, dst_offset, ++ bytes, flags, true); ++} ++ ++/* Copy range from @src to @dst. ++ * ++ * See the comment of bdrv_co_copy_range for the parameter and return value ++ * semantics. */ ++int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, uint64_t src_offset, ++ BdrvChild *dst, uint64_t dst_offset, ++ uint64_t bytes, BdrvRequestFlags flags) ++{ ++ return bdrv_co_copy_range_internal(src, src_offset, dst, dst_offset, ++ bytes, flags, false); ++} ++ ++int coroutine_fn bdrv_co_copy_range(BdrvChild *src, uint64_t src_offset, ++ BdrvChild *dst, uint64_t dst_offset, ++ uint64_t bytes, BdrvRequestFlags flags) ++{ ++ BdrvTrackedRequest src_req, dst_req; ++ BlockDriverState *src_bs = src->bs; ++ BlockDriverState *dst_bs = dst->bs; ++ int ret; ++ ++ bdrv_inc_in_flight(src_bs); ++ bdrv_inc_in_flight(dst_bs); ++ tracked_request_begin(&src_req, src_bs, src_offset, ++ bytes, BDRV_TRACKED_READ); ++ tracked_request_begin(&dst_req, dst_bs, dst_offset, ++ bytes, BDRV_TRACKED_WRITE); ++ ++ wait_serialising_requests(&src_req); ++ wait_serialising_requests(&dst_req); ++ ret = bdrv_co_copy_range_from(src, src_offset, ++ dst, dst_offset, ++ bytes, flags); ++ ++ tracked_request_end(&src_req); ++ tracked_request_end(&dst_req); ++ bdrv_dec_in_flight(src_bs); ++ bdrv_dec_in_flight(dst_bs); ++ return ret; ++} +diff --git a/include/block/block.h b/include/block/block.h +index 2d17b09..e677080 100644 +--- a/include/block/block.h ++++ b/include/block/block.h +@@ -613,4 +613,36 @@ bool bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name, + */ + void bdrv_register_buf(BlockDriverState *bs, void *host, size_t size); + void bdrv_unregister_buf(BlockDriverState *bs, void *host); ++ ++/** ++ * ++ * bdrv_co_copy_range: ++ * ++ * Do offloaded copy between two children. If the operation is not implemented ++ * by the driver, or if the backend storage doesn't support it, a negative ++ * error code will be returned. ++ * ++ * Note: block layer doesn't emulate or fallback to a bounce buffer approach ++ * because usually the caller shouldn't attempt offloaded copy any more (e.g. ++ * calling copy_file_range(2)) after the first error, thus it should fall back ++ * to a read+write path in the caller level. ++ * ++ * @src: Source child to copy data from ++ * @src_offset: offset in @src image to read data ++ * @dst: Destination child to copy data to ++ * @dst_offset: offset in @dst image to write data ++ * @bytes: number of bytes to copy ++ * @flags: request flags. Must be one of: ++ * 0 - actually read data from src; ++ * BDRV_REQ_ZERO_WRITE - treat the @src range as zero data and do zero ++ * write on @dst as if bdrv_co_pwrite_zeroes is ++ * called. Used to simplify caller code, or ++ * during BlockDriver.bdrv_co_copy_range_from() ++ * recursion. ++ * ++ * Returns: 0 if succeeded; negative error code if failed. ++ **/ ++int coroutine_fn bdrv_co_copy_range(BdrvChild *src, uint64_t src_offset, ++ BdrvChild *dst, uint64_t dst_offset, ++ uint64_t bytes, BdrvRequestFlags flags); + #endif +diff --git a/include/block/block_int.h b/include/block/block_int.h +index ad2b852..3da86a7 100644 +--- a/include/block/block_int.h ++++ b/include/block/block_int.h +@@ -206,6 +206,37 @@ struct BlockDriver { + int coroutine_fn (*bdrv_co_pdiscard)(BlockDriverState *bs, + int64_t offset, int bytes); + ++ /* Map [offset, offset + nbytes) range onto a child of @bs to copy from, ++ * and invoke bdrv_co_copy_range_from(child, ...), or invoke ++ * bdrv_co_copy_range_to() if @bs is the leaf child to copy data from. ++ * ++ * See the comment of bdrv_co_copy_range for the parameter and return value ++ * semantics. ++ */ ++ int coroutine_fn (*bdrv_co_copy_range_from)(BlockDriverState *bs, ++ BdrvChild *src, ++ uint64_t offset, ++ BdrvChild *dst, ++ uint64_t dst_offset, ++ uint64_t bytes, ++ BdrvRequestFlags flags); ++ ++ /* Map [offset, offset + nbytes) range onto a child of bs to copy data to, ++ * and invoke bdrv_co_copy_range_to(child, src, ...), or perform the copy ++ * operation if @bs is the leaf and @src has the same BlockDriver. Return ++ * -ENOTSUP if @bs is the leaf but @src has a different BlockDriver. ++ * ++ * See the comment of bdrv_co_copy_range for the parameter and return value ++ * semantics. ++ */ ++ int coroutine_fn (*bdrv_co_copy_range_to)(BlockDriverState *bs, ++ BdrvChild *src, ++ uint64_t src_offset, ++ BdrvChild *dst, ++ uint64_t dst_offset, ++ uint64_t bytes, ++ BdrvRequestFlags flags); ++ + /* + * Building block for bdrv_block_status[_above] and + * bdrv_is_allocated[_above]. The driver should answer only +@@ -1091,4 +1122,11 @@ void bdrv_dec_in_flight(BlockDriverState *bs); + + void blockdev_close_all_bdrv_states(void); + ++int coroutine_fn bdrv_co_copy_range_from(BdrvChild *src, uint64_t src_offset, ++ BdrvChild *dst, uint64_t dst_offset, ++ uint64_t bytes, BdrvRequestFlags flags); ++int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, uint64_t src_offset, ++ BdrvChild *dst, uint64_t dst_offset, ++ uint64_t bytes, BdrvRequestFlags flags); ++ + #endif /* BLOCK_INT_H */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Leave-valid-throttle-timers-when-removing-a-BD.patch b/SOURCES/kvm-block-Leave-valid-throttle-timers-when-removing-a-BD.patch deleted file mode 100644 index 9143117..0000000 --- a/SOURCES/kvm-block-Leave-valid-throttle-timers-when-removing-a-BD.patch +++ /dev/null @@ -1,110 +0,0 @@ -From d2461fce36126372a78f020f107389cd72395f15 Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Fri, 17 Nov 2017 11:19:06 +0100 -Subject: [PATCH 07/15] block: Leave valid throttle timers when removing a BDS - from a backend - -RH-Author: Stefan Hajnoczi -Message-id: <20171117111908.8815-8-stefanha@redhat.com> -Patchwork-id: 77742 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 7/9] block: Leave valid throttle timers when removing a BDS from a backend -Bugzilla: 1492295 -RH-Acked-by: John Snow -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth - -From: Alberto Garcia - -If a BlockBackend has I/O limits set then its ThrottleGroupMember -structure uses the AioContext from its attached BlockDriverState. -Those two contexts must be kept in sync manually. This is not -ideal and will be fixed in the future by removing the throttling -configuration from the BlockBackend and storing it in an implicit -filter node instead, but for now we have to live with this. - -When you remove the BlockDriverState from the backend then the -throttle timers are destroyed. If a new BlockDriverState is later -inserted then they are created again using the new AioContext. - -There are a couple of problems with this: - - a) The code manipulates the timers directly, leaving the - ThrottleGroupMember.aio_context field in an inconsisent state. - - b) If you remove the I/O limits (e.g by destroying the backend) - when the timers are gone then throttle_group_unregister_tgm() - will attempt to destroy them again, crashing QEMU. - -While b) could be fixed easily by allowing the timers to be freed -twice, this would result in a situation in which we can no longer -guarantee that a valid ThrottleState has a valid AioContext and -timers. - -This patch ensures that the timers and AioContext are always valid -when I/O limits are set, regardless of whether the BlockBackend has a -BlockDriverState inserted or not. - -[Fixed "There'a" typo as suggested by Max Reitz ---Stefan] - -Reported-by: sochin jiang -Signed-off-by: Alberto Garcia -Reviewed-by: Max Reitz -Message-id: e089c66e7c20289b046d782cea4373b765c5bc1d.1510339534.git.berto@igalia.com -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit c89bcf3af01e7a8834cca5344e098bf879e99999) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - block/block-backend.c | 16 ++++++++-------- - 1 file changed, 8 insertions(+), 8 deletions(-) - -diff --git a/block/block-backend.c b/block/block-backend.c -index 0bd439e..083e65f 100644 ---- a/block/block-backend.c -+++ b/block/block-backend.c -@@ -655,15 +655,15 @@ BlockBackend *blk_by_public(BlockBackendPublic *public) - */ - void blk_remove_bs(BlockBackend *blk) - { -+ ThrottleGroupMember *tgm = &blk->public.throttle_group_member; - BlockDriverState *bs; -- ThrottleTimers *tt; - - notifier_list_notify(&blk->remove_bs_notifiers, blk); -- if (blk->public.throttle_group_member.throttle_state) { -- tt = &blk->public.throttle_group_member.throttle_timers; -+ if (tgm->throttle_state) { - bs = blk_bs(blk); - bdrv_drained_begin(bs); -- throttle_timers_detach_aio_context(tt); -+ throttle_group_detach_aio_context(tgm); -+ throttle_group_attach_aio_context(tgm, qemu_get_aio_context()); - bdrv_drained_end(bs); - } - -@@ -678,6 +678,7 @@ void blk_remove_bs(BlockBackend *blk) - */ - int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp) - { -+ ThrottleGroupMember *tgm = &blk->public.throttle_group_member; - blk->root = bdrv_root_attach_child(bs, "root", &child_root, - blk->perm, blk->shared_perm, blk, errp); - if (blk->root == NULL) { -@@ -686,10 +687,9 @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp) - bdrv_ref(bs); - - notifier_list_notify(&blk->insert_bs_notifiers, blk); -- if (blk->public.throttle_group_member.throttle_state) { -- throttle_timers_attach_aio_context( -- &blk->public.throttle_group_member.throttle_timers, -- bdrv_get_aio_context(bs)); -+ if (tgm->throttle_state) { -+ throttle_group_detach_aio_context(tgm); -+ throttle_group_attach_aio_context(tgm, bdrv_get_aio_context(bs)); - } - - return 0; --- -1.8.3.1 - diff --git a/SOURCES/kvm-block-Make-bdrv_is_writable-public.patch b/SOURCES/kvm-block-Make-bdrv_is_writable-public.patch new file mode 100644 index 0000000..a64c204 --- /dev/null +++ b/SOURCES/kvm-block-Make-bdrv_is_writable-public.patch @@ -0,0 +1,97 @@ +From 77e6d5c8d54be29781b15bc7dbb816dd156812a0 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 18:00:53 +0200 +Subject: [PATCH 47/54] block: Make bdrv_is_writable() public + +RH-Author: Max Reitz +Message-id: <20180618180055.22739-2-mreitz@redhat.com> +Patchwork-id: 80792 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 1/3] block: Make bdrv_is_writable() public +Bugzilla: 1588039 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf +RH-Acked-by: John Snow + +This is a useful function for the whole block layer, so make it public. +At the same time, users outside of block.c probably do not need to make +use of the reopen functionality, so rename the current function to +bdrv_is_writable_after_reopen() create a new bdrv_is_writable() function +that just passes NULL to it for the reopen queue. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Max Reitz +Message-id: 20180606193702.7113-2-mreitz@redhat.com +Reviewed-by: John Snow +Reviewed-by: Jeff Cody +Signed-off-by: Max Reitz +(cherry picked from commit cc022140972f8b6ac3973c12ccf9dd6b1d2fd200) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + block.c | 17 ++++++++++++++--- + include/block/block.h | 1 + + 2 files changed, 15 insertions(+), 3 deletions(-) + +diff --git a/block.c b/block.c +index 3c3e8fd..982d54e 100644 +--- a/block.c ++++ b/block.c +@@ -1621,13 +1621,24 @@ static int bdrv_reopen_get_flags(BlockReopenQueue *q, BlockDriverState *bs) + + /* Returns whether the image file can be written to after the reopen queue @q + * has been successfully applied, or right now if @q is NULL. */ +-static bool bdrv_is_writable(BlockDriverState *bs, BlockReopenQueue *q) ++static bool bdrv_is_writable_after_reopen(BlockDriverState *bs, ++ BlockReopenQueue *q) + { + int flags = bdrv_reopen_get_flags(q, bs); + + return (flags & (BDRV_O_RDWR | BDRV_O_INACTIVE)) == BDRV_O_RDWR; + } + ++/* ++ * Return whether the BDS can be written to. This is not necessarily ++ * the same as !bdrv_is_read_only(bs), as inactivated images may not ++ * be written to but do not count as read-only images. ++ */ ++bool bdrv_is_writable(BlockDriverState *bs) ++{ ++ return bdrv_is_writable_after_reopen(bs, NULL); ++} ++ + static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs, + BdrvChild *c, const BdrvChildRole *role, + BlockReopenQueue *reopen_queue, +@@ -1665,7 +1676,7 @@ static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q, + + /* Write permissions never work with read-only images */ + if ((cumulative_perms & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)) && +- !bdrv_is_writable(bs, q)) ++ !bdrv_is_writable_after_reopen(bs, q)) + { + error_setg(errp, "Block node is read-only"); + return -EPERM; +@@ -1957,7 +1968,7 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, + &perm, &shared); + + /* Format drivers may touch metadata even if the guest doesn't write */ +- if (bdrv_is_writable(bs, reopen_queue)) { ++ if (bdrv_is_writable_after_reopen(bs, reopen_queue)) { + perm |= BLK_PERM_WRITE | BLK_PERM_RESIZE; + } + +diff --git a/include/block/block.h b/include/block/block.h +index 3894edd..06cd772 100644 +--- a/include/block/block.h ++++ b/include/block/block.h +@@ -407,6 +407,7 @@ bool bdrv_is_read_only(BlockDriverState *bs); + int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only, + bool ignore_allow_rdw, Error **errp); + int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp); ++bool bdrv_is_writable(BlockDriverState *bs); + bool bdrv_is_sg(BlockDriverState *bs); + bool bdrv_is_inserted(BlockDriverState *bs); + void bdrv_lock_medium(BlockDriverState *bs, bool locked); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Make-remaining-uses-of-qobject-input-visitor-m.patch b/SOURCES/kvm-block-Make-remaining-uses-of-qobject-input-visitor-m.patch new file mode 100644 index 0000000..14fc793 --- /dev/null +++ b/SOURCES/kvm-block-Make-remaining-uses-of-qobject-input-visitor-m.patch @@ -0,0 +1,121 @@ +From e5c3237d56ab85fdf98265ad9893bb532b5575ff Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Mon, 18 Jun 2018 08:43:21 +0200 +Subject: [PATCH 14/54] block: Make remaining uses of qobject input visitor + more robust + +RH-Author: Markus Armbruster +Message-id: <20180618084330.30009-15-armbru@redhat.com> +Patchwork-id: 80730 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 14/23] block: Make remaining uses of qobject input visitor more robust +Bugzilla: 1557995 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Remaining uses of qobject_input_visitor_new_keyval() in the block +subsystem: + +* block_crypto_open_opts_init() + Currently doesn't visit any non-string scalars, thus safe. It's + called from + - block_crypto_open_luks() + Creates the QDict with qemu_opts_to_qdict_filtered(), which + creates only string scalars, but has a TODO asking for other types. + - qcow_open() + - qcow2_open(), qcow2_co_invalidate_cache(), qcow2_reopen_prepare() + +* block_crypto_create_opts_init(), called from + - block_crypto_co_create_opts_luks() + Also creates the QDict with qemu_opts_to_qdict_filtered(). + +* vdi_co_create_opts() + Also creates the QDict with qemu_opts_to_qdict_filtered(). + +Replace these uses by qobject_input_visitor_new_flat_confused() for +robustness. This adds crumpling. Right now, that's a no-op, but if +we ever extend these things in non-flat ways, crumpling will be +needed. + +Signed-off-by: Markus Armbruster +Signed-off-by: Kevin Wolf +(cherry picked from commit f853465aacb45dbb07e4cc9815e39b55e10dc690) +Signed-off-by: Miroslav Rezanina +--- + block/crypto.c | 12 +++++++++--- + block/vdi.c | 8 ++++++-- + 2 files changed, 15 insertions(+), 5 deletions(-) + +diff --git a/block/crypto.c b/block/crypto.c +index 7e7ad2d..f5151f4 100644 +--- a/block/crypto.c ++++ b/block/crypto.c +@@ -21,11 +21,11 @@ + #include "qemu/osdep.h" + + #include "block/block_int.h" ++#include "block/qdict.h" + #include "sysemu/block-backend.h" + #include "crypto/block.h" + #include "qapi/opts-visitor.h" + #include "qapi/qapi-visit-crypto.h" +-#include "qapi/qmp/qdict.h" + #include "qapi/qobject-input-visitor.h" + #include "qapi/error.h" + #include "qemu/option.h" +@@ -159,7 +159,10 @@ block_crypto_open_opts_init(QCryptoBlockFormat format, + ret = g_new0(QCryptoBlockOpenOptions, 1); + ret->format = format; + +- v = qobject_input_visitor_new_keyval(QOBJECT(opts)); ++ v = qobject_input_visitor_new_flat_confused(opts, &local_err); ++ if (local_err) { ++ goto out; ++ } + + visit_start_struct(v, NULL, NULL, 0, &local_err); + if (local_err) { +@@ -210,7 +213,10 @@ block_crypto_create_opts_init(QCryptoBlockFormat format, + ret = g_new0(QCryptoBlockCreateOptions, 1); + ret->format = format; + +- v = qobject_input_visitor_new_keyval(QOBJECT(opts)); ++ v = qobject_input_visitor_new_flat_confused(opts, &local_err); ++ if (local_err) { ++ goto out; ++ } + + visit_start_struct(v, NULL, NULL, 0, &local_err); + if (local_err) { +diff --git a/block/vdi.c b/block/vdi.c +index 96a22b8..41859a8 100644 +--- a/block/vdi.c ++++ b/block/vdi.c +@@ -51,10 +51,10 @@ + + #include "qemu/osdep.h" + #include "qapi/error.h" +-#include "qapi/qmp/qdict.h" + #include "qapi/qobject-input-visitor.h" + #include "qapi/qapi-visit-block-core.h" + #include "block/block_int.h" ++#include "block/qdict.h" + #include "sysemu/block-backend.h" + #include "qemu/module.h" + #include "qemu/option.h" +@@ -933,7 +933,11 @@ static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts, + } + + /* Get the QAPI object */ +- v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); ++ v = qobject_input_visitor_new_flat_confused(qdict, errp); ++ if (!v) { ++ ret = -EINVAL; ++ goto done; ++ } + visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err); + visit_free(v); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Move-bdrv_drain_all_begin-out-of-coroutine-con.patch b/SOURCES/kvm-block-Move-bdrv_drain_all_begin-out-of-coroutine-con.patch new file mode 100644 index 0000000..e18aece --- /dev/null +++ b/SOURCES/kvm-block-Move-bdrv_drain_all_begin-out-of-coroutine-con.patch @@ -0,0 +1,78 @@ +From 13f0c32e5c77278207f63ade463035d8aaa4898d Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:15 +0200 +Subject: [PATCH 24/49] block: Move bdrv_drain_all_begin() out of coroutine + context + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-18-kwolf@redhat.com> +Patchwork-id: 82169 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 17/42] block: Move bdrv_drain_all_begin() out of coroutine context +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +Before we can introduce a single polling loop for all nodes in +bdrv_drain_all_begin(), we must make sure to run it outside of coroutine +context like we already do for bdrv_do_drained_begin(). + +Signed-off-by: Kevin Wolf +(cherry picked from commit c8ca33d06def97d909a8511377b82994ae4e5981) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/io.c | 22 +++++++++++++++++----- + 1 file changed, 17 insertions(+), 5 deletions(-) + +diff --git a/block/io.c b/block/io.c +index 23fe069..b58c91b 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -263,11 +263,16 @@ static void bdrv_co_drain_bh_cb(void *opaque) + Coroutine *co = data->co; + BlockDriverState *bs = data->bs; + +- bdrv_dec_in_flight(bs); +- if (data->begin) { +- bdrv_do_drained_begin(bs, data->recursive, data->parent, data->poll); ++ if (bs) { ++ bdrv_dec_in_flight(bs); ++ if (data->begin) { ++ bdrv_do_drained_begin(bs, data->recursive, data->parent, data->poll); ++ } else { ++ bdrv_do_drained_end(bs, data->recursive, data->parent); ++ } + } else { +- bdrv_do_drained_end(bs, data->recursive, data->parent); ++ assert(data->begin); ++ bdrv_drain_all_begin(); + } + + data->done = true; +@@ -293,7 +298,9 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, + .parent = parent, + .poll = poll, + }; +- bdrv_inc_in_flight(bs); ++ if (bs) { ++ bdrv_inc_in_flight(bs); ++ } + aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), + bdrv_co_drain_bh_cb, &data); + +@@ -463,6 +470,11 @@ void bdrv_drain_all_begin(void) + BlockDriverState *bs; + BdrvNextIterator it; + ++ if (qemu_in_coroutine()) { ++ bdrv_co_yield_to_drain(NULL, true, false, NULL, true); ++ return; ++ } ++ + /* BDRV_POLL_WHILE() for a node can only be called from its own I/O thread + * or the main loop AioContext. We potentially use BDRV_POLL_WHILE() on + * nodes in several different AioContexts, so make sure we're in the main +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Move-bdrv_truncate-implementation-to-io.c.patch b/SOURCES/kvm-block-Move-bdrv_truncate-implementation-to-io.c.patch new file mode 100644 index 0000000..4127475 --- /dev/null +++ b/SOURCES/kvm-block-Move-bdrv_truncate-implementation-to-io.c.patch @@ -0,0 +1,297 @@ +From 630e021373d8b88a5d9698c843811a518463072a Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Thu, 12 Jul 2018 14:42:56 +0200 +Subject: [PATCH 37/89] block: Move bdrv_truncate() implementation to io.c + +RH-Author: Kevin Wolf +Message-id: <20180712144258.17303-5-kwolf@redhat.com> +Patchwork-id: 81328 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 4/6] block: Move bdrv_truncate() implementation to io.c +Bugzilla: 1595173 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: John Snow + +This moves the bdrv_truncate() implementation from block.c to block/io.c +so it can have access to the tracked requests infrastructure. + +This involves making refresh_total_sectors() public (in block_int.h). + +Signed-off-by: Kevin Wolf +Reviewed-by: Stefan Hajnoczi +(cherry picked from commit 3d9f2d2af63fda5f0404fb85ea80161837a4e4e3) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block.c | 111 +--------------------------------------------- + block/io.c | 109 +++++++++++++++++++++++++++++++++++++++++++++ + include/block/block_int.h | 2 + + 3 files changed, 112 insertions(+), 110 deletions(-) + +diff --git a/block.c b/block.c +index 0af08ca..10a1ece 100644 +--- a/block.c ++++ b/block.c +@@ -721,7 +721,7 @@ static int find_image_format(BlockBackend *file, const char *filename, + * Set the current 'total_sectors' value + * Return 0 on success, -errno on error. + */ +-static int refresh_total_sectors(BlockDriverState *bs, int64_t hint) ++int refresh_total_sectors(BlockDriverState *bs, int64_t hint) + { + BlockDriver *drv = bs->drv; + +@@ -2200,16 +2200,6 @@ static void bdrv_parent_cb_change_media(BlockDriverState *bs, bool load) + } + } + +-static void bdrv_parent_cb_resize(BlockDriverState *bs) +-{ +- BdrvChild *c; +- QLIST_FOREACH(c, &bs->parents, next_parent) { +- if (c->role->resize) { +- c->role->resize(c); +- } +- } +-} +- + /* + * Sets the backing file link of a BDS. A new reference is created; callers + * which don't need their own reference any more must call bdrv_unref(). +@@ -3736,105 +3726,6 @@ exit: + } + + /** +- * Truncate file to 'offset' bytes (needed only for file protocols) +- */ +-int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, +- PreallocMode prealloc, Error **errp) +-{ +- BlockDriverState *bs = child->bs; +- BlockDriver *drv = bs->drv; +- int ret; +- +- assert(child->perm & BLK_PERM_RESIZE); +- +- /* if bs->drv == NULL, bs is closed, so there's nothing to do here */ +- if (!drv) { +- error_setg(errp, "No medium inserted"); +- return -ENOMEDIUM; +- } +- if (offset < 0) { +- error_setg(errp, "Image size cannot be negative"); +- return -EINVAL; +- } +- +- bdrv_inc_in_flight(bs); +- +- if (!drv->bdrv_co_truncate) { +- if (bs->file && drv->is_filter) { +- ret = bdrv_co_truncate(bs->file, offset, prealloc, errp); +- goto out; +- } +- error_setg(errp, "Image format driver does not support resize"); +- ret = -ENOTSUP; +- goto out; +- } +- if (bs->read_only) { +- error_setg(errp, "Image is read-only"); +- ret = -EACCES; +- goto out; +- } +- +- assert(!(bs->open_flags & BDRV_O_INACTIVE)); +- +- ret = drv->bdrv_co_truncate(bs, offset, prealloc, errp); +- if (ret < 0) { +- goto out; +- } +- ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS); +- if (ret < 0) { +- error_setg_errno(errp, -ret, "Could not refresh total sector count"); +- } else { +- offset = bs->total_sectors * BDRV_SECTOR_SIZE; +- } +- bdrv_dirty_bitmap_truncate(bs, offset); +- bdrv_parent_cb_resize(bs); +- atomic_inc(&bs->write_gen); +- +-out: +- bdrv_dec_in_flight(bs); +- return ret; +-} +- +-typedef struct TruncateCo { +- BdrvChild *child; +- int64_t offset; +- PreallocMode prealloc; +- Error **errp; +- int ret; +-} TruncateCo; +- +-static void coroutine_fn bdrv_truncate_co_entry(void *opaque) +-{ +- TruncateCo *tco = opaque; +- tco->ret = bdrv_co_truncate(tco->child, tco->offset, tco->prealloc, +- tco->errp); +-} +- +-int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc, +- Error **errp) +-{ +- Coroutine *co; +- TruncateCo tco = { +- .child = child, +- .offset = offset, +- .prealloc = prealloc, +- .errp = errp, +- .ret = NOT_DONE, +- }; +- +- if (qemu_in_coroutine()) { +- /* Fast-path if already in coroutine context */ +- bdrv_truncate_co_entry(&tco); +- } else { +- co = qemu_coroutine_create(bdrv_truncate_co_entry, &tco); +- qemu_coroutine_enter(co); +- BDRV_POLL_WHILE(child->bs, tco.ret == NOT_DONE); +- } +- +- return tco.ret; +-} +- +-/** + * Length of a allocated file in bytes. Sparse files are counted by actual + * allocated space. Return < 0 if error or unknown. + */ +diff --git a/block/io.c b/block/io.c +index 5c043a4..32a82e3 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -2929,3 +2929,112 @@ int coroutine_fn bdrv_co_copy_range(BdrvChild *src, uint64_t src_offset, + bdrv_dec_in_flight(dst_bs); + return ret; + } ++ ++static void bdrv_parent_cb_resize(BlockDriverState *bs) ++{ ++ BdrvChild *c; ++ QLIST_FOREACH(c, &bs->parents, next_parent) { ++ if (c->role->resize) { ++ c->role->resize(c); ++ } ++ } ++} ++ ++/** ++ * Truncate file to 'offset' bytes (needed only for file protocols) ++ */ ++int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, ++ PreallocMode prealloc, Error **errp) ++{ ++ BlockDriverState *bs = child->bs; ++ BlockDriver *drv = bs->drv; ++ int ret; ++ ++ assert(child->perm & BLK_PERM_RESIZE); ++ ++ /* if bs->drv == NULL, bs is closed, so there's nothing to do here */ ++ if (!drv) { ++ error_setg(errp, "No medium inserted"); ++ return -ENOMEDIUM; ++ } ++ if (offset < 0) { ++ error_setg(errp, "Image size cannot be negative"); ++ return -EINVAL; ++ } ++ ++ bdrv_inc_in_flight(bs); ++ ++ if (!drv->bdrv_co_truncate) { ++ if (bs->file && drv->is_filter) { ++ ret = bdrv_co_truncate(bs->file, offset, prealloc, errp); ++ goto out; ++ } ++ error_setg(errp, "Image format driver does not support resize"); ++ ret = -ENOTSUP; ++ goto out; ++ } ++ if (bs->read_only) { ++ error_setg(errp, "Image is read-only"); ++ ret = -EACCES; ++ goto out; ++ } ++ ++ assert(!(bs->open_flags & BDRV_O_INACTIVE)); ++ ++ ret = drv->bdrv_co_truncate(bs, offset, prealloc, errp); ++ if (ret < 0) { ++ goto out; ++ } ++ ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS); ++ if (ret < 0) { ++ error_setg_errno(errp, -ret, "Could not refresh total sector count"); ++ } else { ++ offset = bs->total_sectors * BDRV_SECTOR_SIZE; ++ } ++ bdrv_dirty_bitmap_truncate(bs, offset); ++ bdrv_parent_cb_resize(bs); ++ atomic_inc(&bs->write_gen); ++ ++out: ++ bdrv_dec_in_flight(bs); ++ return ret; ++} ++ ++typedef struct TruncateCo { ++ BdrvChild *child; ++ int64_t offset; ++ PreallocMode prealloc; ++ Error **errp; ++ int ret; ++} TruncateCo; ++ ++static void coroutine_fn bdrv_truncate_co_entry(void *opaque) ++{ ++ TruncateCo *tco = opaque; ++ tco->ret = bdrv_co_truncate(tco->child, tco->offset, tco->prealloc, ++ tco->errp); ++} ++ ++int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc, ++ Error **errp) ++{ ++ Coroutine *co; ++ TruncateCo tco = { ++ .child = child, ++ .offset = offset, ++ .prealloc = prealloc, ++ .errp = errp, ++ .ret = NOT_DONE, ++ }; ++ ++ if (qemu_in_coroutine()) { ++ /* Fast-path if already in coroutine context */ ++ bdrv_truncate_co_entry(&tco); ++ } else { ++ co = qemu_coroutine_create(bdrv_truncate_co_entry, &tco); ++ qemu_coroutine_enter(co); ++ BDRV_POLL_WHILE(child->bs, tco.ret == NOT_DONE); ++ } ++ ++ return tco.ret; ++} +diff --git a/include/block/block_int.h b/include/block/block_int.h +index 46b2f87..6a844ec 100644 +--- a/include/block/block_int.h ++++ b/include/block/block_int.h +@@ -1129,4 +1129,6 @@ int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, uint64_t src_offset, + BdrvChild *dst, uint64_t dst_offset, + uint64_t bytes, BdrvRequestFlags flags); + ++int refresh_total_sectors(BlockDriverState *bs, int64_t hint); ++ + #endif /* BLOCK_INT_H */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Move-request-tracking-to-children-in-copy-offl.patch b/SOURCES/kvm-block-Move-request-tracking-to-children-in-copy-offl.patch new file mode 100644 index 0000000..5700f3a --- /dev/null +++ b/SOURCES/kvm-block-Move-request-tracking-to-children-in-copy-offl.patch @@ -0,0 +1,124 @@ +From fba2d77758d680a147862f26d57bb984d73f7700 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Tue, 24 Jul 2018 12:43:07 +0200 +Subject: [PATCH 64/89] block: Move request tracking to children in copy + offloading + +RH-Author: John Snow +Message-id: <20180718225511.14878-14-jsnow@redhat.com> +Patchwork-id: 81393 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 13/35] block: Move request tracking to children in copy offloading +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Fam Zheng + +in_flight and tracked requests need to be tracked in every layer during +recursion. For now the only user is qemu-img convert where overlapping +requests and IOThreads don't exist, therefore this change doesn't make +much difference form user point of view, but it is incorrect as part of +the API. Fix it. + +Reported-by: Kevin Wolf +Signed-off-by: Fam Zheng +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Kevin Wolf +(cherry picked from commit 37aec7d75eb0d035a0db4f2cf9ad8b1b0c10f91b) +Signed-off-by: John Snow +--- + block/io.c | 60 +++++++++++++++++++++++++++++------------------------------- + 1 file changed, 29 insertions(+), 31 deletions(-) + +diff --git a/block/io.c b/block/io.c +index ac36d1c..136a5d0 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -2847,6 +2847,9 @@ static int coroutine_fn bdrv_co_copy_range_internal(BdrvChild *src, + BdrvRequestFlags flags, + bool recurse_src) + { ++ BdrvTrackedRequest src_req, dst_req; ++ BlockDriverState *src_bs = src->bs; ++ BlockDriverState *dst_bs = dst->bs; + int ret; + + if (!src || !dst || !src->bs || !dst->bs) { +@@ -2870,17 +2873,32 @@ static int coroutine_fn bdrv_co_copy_range_internal(BdrvChild *src, + || src->bs->encrypted || dst->bs->encrypted) { + return -ENOTSUP; + } ++ ++ bdrv_inc_in_flight(src_bs); ++ bdrv_inc_in_flight(dst_bs); ++ tracked_request_begin(&src_req, src_bs, src_offset, ++ bytes, BDRV_TRACKED_READ); ++ tracked_request_begin(&dst_req, dst_bs, dst_offset, ++ bytes, BDRV_TRACKED_WRITE); ++ ++ wait_serialising_requests(&src_req); ++ wait_serialising_requests(&dst_req); + if (recurse_src) { +- return src->bs->drv->bdrv_co_copy_range_from(src->bs, +- src, src_offset, +- dst, dst_offset, +- bytes, flags); ++ ret = src->bs->drv->bdrv_co_copy_range_from(src->bs, ++ src, src_offset, ++ dst, dst_offset, ++ bytes, flags); + } else { +- return dst->bs->drv->bdrv_co_copy_range_to(dst->bs, +- src, src_offset, +- dst, dst_offset, +- bytes, flags); ++ ret = dst->bs->drv->bdrv_co_copy_range_to(dst->bs, ++ src, src_offset, ++ dst, dst_offset, ++ bytes, flags); + } ++ tracked_request_end(&src_req); ++ tracked_request_end(&dst_req); ++ bdrv_dec_in_flight(src_bs); ++ bdrv_dec_in_flight(dst_bs); ++ return ret; + } + + /* Copy range from @src to @dst. +@@ -2911,29 +2929,9 @@ int coroutine_fn bdrv_co_copy_range(BdrvChild *src, uint64_t src_offset, + BdrvChild *dst, uint64_t dst_offset, + uint64_t bytes, BdrvRequestFlags flags) + { +- BdrvTrackedRequest src_req, dst_req; +- BlockDriverState *src_bs = src->bs; +- BlockDriverState *dst_bs = dst->bs; +- int ret; +- +- bdrv_inc_in_flight(src_bs); +- bdrv_inc_in_flight(dst_bs); +- tracked_request_begin(&src_req, src_bs, src_offset, +- bytes, BDRV_TRACKED_READ); +- tracked_request_begin(&dst_req, dst_bs, dst_offset, +- bytes, BDRV_TRACKED_WRITE); +- +- wait_serialising_requests(&src_req); +- wait_serialising_requests(&dst_req); +- ret = bdrv_co_copy_range_from(src, src_offset, +- dst, dst_offset, +- bytes, flags); +- +- tracked_request_end(&src_req); +- tracked_request_end(&dst_req); +- bdrv_dec_in_flight(src_bs); +- bdrv_dec_in_flight(dst_bs); +- return ret; ++ return bdrv_co_copy_range_from(src, src_offset, ++ dst, dst_offset, ++ bytes, flags); + } + + static void bdrv_parent_cb_resize(BlockDriverState *bs) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Open-backing-image-in-force-share-mode-for-siz.patch b/SOURCES/kvm-block-Open-backing-image-in-force-share-mode-for-siz.patch deleted file mode 100644 index 6461257..0000000 --- a/SOURCES/kvm-block-Open-backing-image-in-force-share-mode-for-siz.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 20103e6ef28af483bb8aa54b1272fbd480b61aa4 Mon Sep 17 00:00:00 2001 -From: Fam Zheng -Date: Mon, 15 Jan 2018 06:15:18 +0100 -Subject: [PATCH 08/12] block: Open backing image in force share mode for size - probe - -RH-Author: Fam Zheng -Message-id: <20180115061518.16303-1-famz@redhat.com> -Patchwork-id: 78570 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH] block: Open backing image in force share mode for size probe -Bugzilla: 1526212 -RH-Acked-by: Kevin Wolf -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: John Snow - -Management tools create overlays of running guests with qemu-img: - - $ qemu-img create -b /image/in/use.qcow2 -f qcow2 /overlay/image.qcow2 - -but this doesn't work anymore due to image locking: - - qemu-img: /overlay/image.qcow2: Failed to get shared "write" lock - Is another process using the image? - Could not open backing image to determine size. -Use the force share option to allow this use case again. - -Cc: qemu-stable@nongnu.org -Signed-off-by: Fam Zheng -Reviewed-by: Eric Blake -Signed-off-by: Kevin Wolf -(cherry picked from commit cc954f01e3c004aad081aa36736a17e842b80211) -Signed-off-by: Fam Zheng -Signed-off-by: Miroslav Rezanina ---- - block.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/block.c b/block.c -index b5736dd..17629ab 100644 ---- a/block.c -+++ b/block.c -@@ -4515,10 +4515,11 @@ void bdrv_img_create(const char *filename, const char *fmt, - back_flags = flags; - back_flags &= ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING); - -+ backing_options = qdict_new(); - if (backing_fmt) { -- backing_options = qdict_new(); - qdict_put_str(backing_options, "driver", backing_fmt); - } -+ qdict_put_bool(backing_options, BDRV_OPT_FORCE_SHARE, true); - - bs = bdrv_open(full_backing, NULL, backing_options, back_flags, - &local_err); --- -1.8.3.1 - diff --git a/SOURCES/kvm-block-Poll-after-drain-on-attaching-a-node.patch b/SOURCES/kvm-block-Poll-after-drain-on-attaching-a-node.patch new file mode 100644 index 0000000..9b2d732 --- /dev/null +++ b/SOURCES/kvm-block-Poll-after-drain-on-attaching-a-node.patch @@ -0,0 +1,150 @@ +From b0c7fc7fbe64b234272db8316f81b92fe675a65a Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:19 +0200 +Subject: [PATCH 28/49] block: Poll after drain on attaching a node + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-22-kwolf@redhat.com> +Patchwork-id: 82173 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 21/42] block: Poll after drain on attaching a node +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +Commit dcf94a23b1 ('block: Don't poll in parent drain callbacks') +removed polling in bdrv_child_cb_drained_begin() on the grounds that the +original bdrv_drain() already will poll and BdrvChildRole.drained_begin +calls must not cause graph changes (and therefore must not call +aio_poll() or the recursion through the graph will break. + +This reasoning is correct for calls through bdrv_do_drained_begin(). +However, BdrvChildRole.drained_begin is also called when a node that is +already in a drained section (i.e. bdrv_do_drained_begin() has already +returned and therefore can't poll any more) is attached to a new parent. +In this case, we must explicitly poll to have all requests completed +before the drained new child can be attached to the parent. + +In bdrv_replace_child_noperm(), we know that we're not inside the +recursion of bdrv_do_drained_begin() because graph changes are not +allowed there, and bdrv_replace_child_noperm() is a graph change. The +call of BdrvChildRole.drained_begin() must therefore be followed by a +BDRV_POLL_WHILE() that waits for the completion of requests. + +Reported-by: Max Reitz +Signed-off-by: Kevin Wolf +(cherry picked from commit 4be6a6d118123340f16fb8b3bf45220d0f8ed6d4) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block.c | 2 +- + block/io.c | 26 ++++++++++++++++++++------ + include/block/block.h | 8 ++++++++ + include/block/block_int.h | 3 +++ + 4 files changed, 32 insertions(+), 7 deletions(-) + +diff --git a/block.c b/block.c +index eea9c6f..e89b5e3 100644 +--- a/block.c ++++ b/block.c +@@ -2072,7 +2072,7 @@ static void bdrv_replace_child_noperm(BdrvChild *child, + } + assert(num >= 0); + for (i = 0; i < num; i++) { +- child->role->drained_begin(child); ++ bdrv_parent_drained_begin_single(child, true); + } + } + +diff --git a/block/io.c b/block/io.c +index 38ae299..d404088 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -52,9 +52,7 @@ void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore, + if (c == ignore || (ignore_bds_parents && c->role->parent_is_bds)) { + continue; + } +- if (c->role->drained_begin) { +- c->role->drained_begin(c); +- } ++ bdrv_parent_drained_begin_single(c, false); + } + } + +@@ -73,6 +71,14 @@ void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore, + } + } + ++static bool bdrv_parent_drained_poll_single(BdrvChild *c) ++{ ++ if (c->role->drained_poll) { ++ return c->role->drained_poll(c); ++ } ++ return false; ++} ++ + static bool bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore, + bool ignore_bds_parents) + { +@@ -83,14 +89,22 @@ static bool bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore, + if (c == ignore || (ignore_bds_parents && c->role->parent_is_bds)) { + continue; + } +- if (c->role->drained_poll) { +- busy |= c->role->drained_poll(c); +- } ++ busy |= bdrv_parent_drained_poll_single(c); + } + + return busy; + } + ++void bdrv_parent_drained_begin_single(BdrvChild *c, bool poll) ++{ ++ if (c->role->drained_begin) { ++ c->role->drained_begin(c); ++ } ++ if (poll) { ++ BDRV_POLL_WHILE(c->bs, bdrv_parent_drained_poll_single(c)); ++ } ++} ++ + static void bdrv_merge_limits(BlockLimits *dst, const BlockLimits *src) + { + dst->opt_transfer = MAX(dst->opt_transfer, src->opt_transfer); +diff --git a/include/block/block.h b/include/block/block.h +index f9079ac..356712c 100644 +--- a/include/block/block.h ++++ b/include/block/block.h +@@ -590,6 +590,14 @@ void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore, + bool ignore_bds_parents); + + /** ++ * bdrv_parent_drained_begin_single: ++ * ++ * Begin a quiesced section for the parent of @c. If @poll is true, wait for ++ * any pending activity to cease. ++ */ ++void bdrv_parent_drained_begin_single(BdrvChild *c, bool poll); ++ ++/** + * bdrv_parent_drained_end: + * + * End a quiesced section of all users of @bs. This is part of +diff --git a/include/block/block_int.h b/include/block/block_int.h +index 9757d5e..b7806e3 100644 +--- a/include/block/block_int.h ++++ b/include/block/block_int.h +@@ -610,6 +610,9 @@ struct BdrvChildRole { + * requests after returning from .drained_begin() until .drained_end() is + * called. + * ++ * These functions must not change the graph (and therefore also must not ++ * call aio_poll(), which could change the graph indirectly). ++ * + * Note that this can be nested. If drained_begin() was called twice, new + * I/O is allowed only after drained_end() was called twice, too. + */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Really-pause-block-jobs-on-drain.patch b/SOURCES/kvm-block-Really-pause-block-jobs-on-drain.patch new file mode 100644 index 0000000..7f0cdc3 --- /dev/null +++ b/SOURCES/kvm-block-Really-pause-block-jobs-on-drain.patch @@ -0,0 +1,360 @@ +From 70365466a45a381ebb54e49cb03579b5fd6c76ef Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:05 +0200 +Subject: [PATCH 14/49] block: Really pause block jobs on drain + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-8-kwolf@redhat.com> +Patchwork-id: 82160 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 07/42] block: Really pause block jobs on drain +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +We already requested that block jobs be paused in .bdrv_drained_begin, +but no guarantee was made that the job was actually inactive at the +point where bdrv_drained_begin() returned. + +This introduces a new callback BdrvChildRole.bdrv_drained_poll() and +uses it to make bdrv_drain_poll() consider block jobs using the node to +be drained. + +For the test case to work as expected, we have to switch from +block_job_sleep_ns() to qemu_co_sleep_ns() so that the test job is even +considered active and must be waited for when draining the node. + +Signed-off-by: Kevin Wolf +(cherry picked from commit 89bd030533e3592ca0a995450dcfc5d53e459e20) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block.c | 9 +++++++++ + block/io.c | 40 ++++++++++++++++++++++++++++++++++------ + block/mirror.c | 8 ++++++++ + blockjob.c | 23 +++++++++++++++++++++++ + include/block/block.h | 8 ++++++++ + include/block/block_int.h | 7 +++++++ + include/block/blockjob_int.h | 8 ++++++++ + tests/test-bdrv-drain.c | 18 ++++++++++-------- + 8 files changed, 107 insertions(+), 14 deletions(-) + +diff --git a/block.c b/block.c +index 10a1ece..0d9698a 100644 +--- a/block.c ++++ b/block.c +@@ -821,6 +821,12 @@ static void bdrv_child_cb_drained_begin(BdrvChild *child) + bdrv_drained_begin(bs); + } + ++static bool bdrv_child_cb_drained_poll(BdrvChild *child) ++{ ++ BlockDriverState *bs = child->opaque; ++ return bdrv_drain_poll(bs, NULL); ++} ++ + static void bdrv_child_cb_drained_end(BdrvChild *child) + { + BlockDriverState *bs = child->opaque; +@@ -905,6 +911,7 @@ const BdrvChildRole child_file = { + .get_parent_desc = bdrv_child_get_parent_desc, + .inherit_options = bdrv_inherited_options, + .drained_begin = bdrv_child_cb_drained_begin, ++ .drained_poll = bdrv_child_cb_drained_poll, + .drained_end = bdrv_child_cb_drained_end, + .attach = bdrv_child_cb_attach, + .detach = bdrv_child_cb_detach, +@@ -929,6 +936,7 @@ const BdrvChildRole child_format = { + .get_parent_desc = bdrv_child_get_parent_desc, + .inherit_options = bdrv_inherited_fmt_options, + .drained_begin = bdrv_child_cb_drained_begin, ++ .drained_poll = bdrv_child_cb_drained_poll, + .drained_end = bdrv_child_cb_drained_end, + .attach = bdrv_child_cb_attach, + .detach = bdrv_child_cb_detach, +@@ -1048,6 +1056,7 @@ const BdrvChildRole child_backing = { + .detach = bdrv_backing_detach, + .inherit_options = bdrv_backing_options, + .drained_begin = bdrv_child_cb_drained_begin, ++ .drained_poll = bdrv_child_cb_drained_poll, + .drained_end = bdrv_child_cb_drained_end, + .inactivate = bdrv_child_cb_inactivate, + .update_filename = bdrv_backing_update_filename, +diff --git a/block/io.c b/block/io.c +index 4d332c3..e260394 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -69,6 +69,23 @@ void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore) + } + } + ++static bool bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore) ++{ ++ BdrvChild *c, *next; ++ bool busy = false; ++ ++ QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) { ++ if (c == ignore) { ++ continue; ++ } ++ if (c->role->drained_poll) { ++ busy |= c->role->drained_poll(c); ++ } ++ } ++ ++ return busy; ++} ++ + static void bdrv_merge_limits(BlockLimits *dst, const BlockLimits *src) + { + dst->opt_transfer = MAX(dst->opt_transfer, src->opt_transfer); +@@ -182,21 +199,32 @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin) + } + + /* Returns true if BDRV_POLL_WHILE() should go into a blocking aio_poll() */ +-static bool bdrv_drain_poll(BlockDriverState *bs) ++bool bdrv_drain_poll(BlockDriverState *bs, BdrvChild *ignore_parent) ++{ ++ if (bdrv_parent_drained_poll(bs, ignore_parent)) { ++ return true; ++ } ++ ++ return atomic_read(&bs->in_flight); ++} ++ ++static bool bdrv_drain_poll_top_level(BlockDriverState *bs, ++ BdrvChild *ignore_parent) + { + /* Execute pending BHs first and check everything else only after the BHs + * have executed. */ + while (aio_poll(bs->aio_context, false)); +- return atomic_read(&bs->in_flight); ++ ++ return bdrv_drain_poll(bs, ignore_parent); + } + +-static bool bdrv_drain_recurse(BlockDriverState *bs) ++static bool bdrv_drain_recurse(BlockDriverState *bs, BdrvChild *parent) + { + BdrvChild *child, *tmp; + bool waited; + + /* Wait for drained requests to finish */ +- waited = BDRV_POLL_WHILE(bs, bdrv_drain_poll(bs)); ++ waited = BDRV_POLL_WHILE(bs, bdrv_drain_poll_top_level(bs, parent)); + + QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) { + BlockDriverState *bs = child->bs; +@@ -213,7 +241,7 @@ static bool bdrv_drain_recurse(BlockDriverState *bs) + */ + bdrv_ref(bs); + } +- waited |= bdrv_drain_recurse(bs); ++ waited |= bdrv_drain_recurse(bs, child); + if (in_main_loop) { + bdrv_unref(bs); + } +@@ -289,7 +317,7 @@ void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, + + bdrv_parent_drained_begin(bs, parent); + bdrv_drain_invoke(bs, true); +- bdrv_drain_recurse(bs); ++ bdrv_drain_recurse(bs, parent); + + if (recursive) { + bs->recursive_quiesce_counter++; +diff --git a/block/mirror.c b/block/mirror.c +index 313e6e9..4b27f71 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -976,6 +976,12 @@ static void mirror_pause(Job *job) + mirror_wait_for_all_io(s); + } + ++static bool mirror_drained_poll(BlockJob *job) ++{ ++ MirrorBlockJob *s = container_of(job, MirrorBlockJob, common); ++ return !!s->in_flight; ++} ++ + static void mirror_attached_aio_context(BlockJob *job, AioContext *new_context) + { + MirrorBlockJob *s = container_of(job, MirrorBlockJob, common); +@@ -1011,6 +1017,7 @@ static const BlockJobDriver mirror_job_driver = { + .pause = mirror_pause, + .complete = mirror_complete, + }, ++ .drained_poll = mirror_drained_poll, + .attached_aio_context = mirror_attached_aio_context, + .drain = mirror_drain, + }; +@@ -1028,6 +1035,7 @@ static const BlockJobDriver commit_active_job_driver = { + .pause = mirror_pause, + .complete = mirror_complete, + }, ++ .drained_poll = mirror_drained_poll, + .attached_aio_context = mirror_attached_aio_context, + .drain = mirror_drain, + }; +diff --git a/blockjob.c b/blockjob.c +index 0306533..be5903a 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -155,6 +155,28 @@ static void child_job_drained_begin(BdrvChild *c) + job_pause(&job->job); + } + ++static bool child_job_drained_poll(BdrvChild *c) ++{ ++ BlockJob *bjob = c->opaque; ++ Job *job = &bjob->job; ++ const BlockJobDriver *drv = block_job_driver(bjob); ++ ++ /* An inactive or completed job doesn't have any pending requests. Jobs ++ * with !job->busy are either already paused or have a pause point after ++ * being reentered, so no job driver code will run before they pause. */ ++ if (!job->busy || job_is_completed(job) || job->deferred_to_main_loop) { ++ return false; ++ } ++ ++ /* Otherwise, assume that it isn't fully stopped yet, but allow the job to ++ * override this assumption. */ ++ if (drv->drained_poll) { ++ return drv->drained_poll(bjob); ++ } else { ++ return true; ++ } ++} ++ + static void child_job_drained_end(BdrvChild *c) + { + BlockJob *job = c->opaque; +@@ -164,6 +186,7 @@ static void child_job_drained_end(BdrvChild *c) + static const BdrvChildRole child_job = { + .get_parent_desc = child_job_get_parent_desc, + .drained_begin = child_job_drained_begin, ++ .drained_poll = child_job_drained_poll, + .drained_end = child_job_drained_end, + .stay_at_node = true, + }; +diff --git a/include/block/block.h b/include/block/block.h +index 8f87eea..8c91d4c 100644 +--- a/include/block/block.h ++++ b/include/block/block.h +@@ -596,6 +596,14 @@ void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore); + void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore); + + /** ++ * bdrv_drain_poll: ++ * ++ * Poll for pending requests in @bs and its parents (except for ++ * @ignore_parent). This is part of bdrv_drained_begin. ++ */ ++bool bdrv_drain_poll(BlockDriverState *bs, BdrvChild *ignore_parent); ++ ++/** + * bdrv_drained_begin: + * + * Begin a quiesced section for exclusive access to the BDS, by disabling +diff --git a/include/block/block_int.h b/include/block/block_int.h +index 341cbe8..beeacde 100644 +--- a/include/block/block_int.h ++++ b/include/block/block_int.h +@@ -610,6 +610,13 @@ struct BdrvChildRole { + void (*drained_begin)(BdrvChild *child); + void (*drained_end)(BdrvChild *child); + ++ /* ++ * Returns whether the parent has pending requests for the child. This ++ * callback is polled after .drained_begin() has been called until all ++ * activity on the child has stopped. ++ */ ++ bool (*drained_poll)(BdrvChild *child); ++ + /* Notifies the parent that the child has been activated/inactivated (e.g. + * when migration is completing) and it can start/stop requesting + * permissions and doing I/O on it. */ +diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h +index 5cd50c6..e4a318d 100644 +--- a/include/block/blockjob_int.h ++++ b/include/block/blockjob_int.h +@@ -39,6 +39,14 @@ struct BlockJobDriver { + JobDriver job_driver; + + /* ++ * Returns whether the job has pending requests for the child or will ++ * submit new requests before the next pause point. This callback is polled ++ * in the context of draining a job node after requesting that the job be ++ * paused, until all activity on the child has stopped. ++ */ ++ bool (*drained_poll)(BlockJob *job); ++ ++ /* + * If the callback is not NULL, it will be invoked before the job is + * resumed in a new AioContext. This is the place to move any resources + * besides job->blk to the new AioContext. +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index f5d85c9..49786ea 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -681,7 +681,11 @@ static int coroutine_fn test_job_run(Job *job, Error **errp) + + job_transition_to_ready(&s->common.job); + while (!s->should_complete) { +- job_sleep_ns(&s->common.job, 100000); ++ /* Avoid block_job_sleep_ns() because it marks the job as !busy. We ++ * want to emulate some actual activity (probably some I/O) here so ++ * that drain has to wait for this acitivity to stop. */ ++ qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000); ++ job_pause_point(&s->common.job); + } + + return 0; +@@ -728,7 +732,7 @@ static void test_blockjob_common(enum drain_type drain_type) + + g_assert_cmpint(job->job.pause_count, ==, 0); + g_assert_false(job->job.paused); +- g_assert_false(job->job.busy); /* We're in job_sleep_ns() */ ++ g_assert_true(job->job.busy); /* We're in job_sleep_ns() */ + + do_drain_begin(drain_type, src); + +@@ -738,15 +742,14 @@ static void test_blockjob_common(enum drain_type drain_type) + } else { + g_assert_cmpint(job->job.pause_count, ==, 1); + } +- /* XXX We don't wait until the job is actually paused. Is this okay? */ +- /* g_assert_true(job->job.paused); */ ++ g_assert_true(job->job.paused); + g_assert_false(job->job.busy); /* The job is paused */ + + do_drain_end(drain_type, src); + + g_assert_cmpint(job->job.pause_count, ==, 0); + g_assert_false(job->job.paused); +- g_assert_false(job->job.busy); /* We're in job_sleep_ns() */ ++ g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */ + + do_drain_begin(drain_type, target); + +@@ -756,15 +759,14 @@ static void test_blockjob_common(enum drain_type drain_type) + } else { + g_assert_cmpint(job->job.pause_count, ==, 1); + } +- /* XXX We don't wait until the job is actually paused. Is this okay? */ +- /* g_assert_true(job->job.paused); */ ++ g_assert_true(job->job.paused); + g_assert_false(job->job.busy); /* The job is paused */ + + do_drain_end(drain_type, target); + + g_assert_cmpint(job->job.pause_count, ==, 0); + g_assert_false(job->job.paused); +- g_assert_false(job->job.busy); /* We're in job_sleep_ns() */ ++ g_assert_true(job->job.busy); /* We're in job_sleep_ns() */ + + ret = job_complete_sync(&job->job, &error_abort); + g_assert_cmpint(ret, ==, 0); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Remove-aio_poll-in-bdrv_drain_poll-variants.patch b/SOURCES/kvm-block-Remove-aio_poll-in-bdrv_drain_poll-variants.patch new file mode 100644 index 0000000..83dc6a5 --- /dev/null +++ b/SOURCES/kvm-block-Remove-aio_poll-in-bdrv_drain_poll-variants.patch @@ -0,0 +1,62 @@ +From 78a927e7c583a7556604e55b5d27d4c4c082fb64 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:37 +0200 +Subject: [PATCH 46/49] block: Remove aio_poll() in bdrv_drain_poll variants + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-40-kwolf@redhat.com> +Patchwork-id: 82191 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 39/42] block: Remove aio_poll() in bdrv_drain_poll variants +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +bdrv_drain_poll_top_level() was buggy because it didn't release the +AioContext lock of the node to be drained before calling aio_poll(). +This way, callbacks called by aio_poll() would possibly take the lock a +second time and run into a deadlock with a nested AIO_WAIT_WHILE() call. + +However, it turns out that the aio_poll() call isn't actually needed any +more. It was introduced in commit 91af091f923, which is effectively +reverted by this patch. The cases it was supposed to fix are now covered +by bdrv_drain_poll(), which waits for block jobs to reach a quiescent +state. + +Signed-off-by: Kevin Wolf +Reviewed-by: Fam Zheng +Reviewed-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + block/io.c | 8 -------- + 1 file changed, 8 deletions(-) + +diff --git a/block/io.c b/block/io.c +index 19db35e..3313958 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -266,10 +266,6 @@ bool bdrv_drain_poll(BlockDriverState *bs, bool recursive, + static bool bdrv_drain_poll_top_level(BlockDriverState *bs, bool recursive, + BdrvChild *ignore_parent) + { +- /* Execute pending BHs first and check everything else only after the BHs +- * have executed. */ +- while (aio_poll(bs->aio_context, false)); +- + return bdrv_drain_poll(bs, recursive, ignore_parent, false); + } + +@@ -509,10 +505,6 @@ static bool bdrv_drain_all_poll(void) + BlockDriverState *bs = NULL; + bool result = false; + +- /* Execute pending BHs first (may modify the graph) and check everything +- * else only after the BHs have executed. */ +- while (aio_poll(qemu_get_aio_context(), false)); +- + /* bdrv_drain_poll() can't make changes to the graph and we are holding the + * main AioContext lock, so iterating bdrv_next_all_states() is safe. */ + while ((bs = bdrv_next_all_states(bs))) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Remove-bdrv_drain_recurse.patch b/SOURCES/kvm-block-Remove-bdrv_drain_recurse.patch new file mode 100644 index 0000000..89901b1 --- /dev/null +++ b/SOURCES/kvm-block-Remove-bdrv_drain_recurse.patch @@ -0,0 +1,91 @@ +From 6d4f47108b6e121924f7bf12c97cbabb674dee1b Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:06 +0200 +Subject: [PATCH 15/49] block: Remove bdrv_drain_recurse() + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-9-kwolf@redhat.com> +Patchwork-id: 82161 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 08/42] block: Remove bdrv_drain_recurse() +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +For bdrv_drain(), recursively waiting for child node requests is +pointless because we didn't quiesce their parents, so new requests could +come in anyway. Letting the function work only on a single node makes it +more consistent. + +For subtree drains and drain_all, we already have the recursion in +bdrv_do_drained_begin(), so the extra recursion doesn't add anything +either. + +Remove the useless code. + +Signed-off-by: Kevin Wolf +Reviewed-by: Stefan Hajnoczi +(cherry picked from commit d30b8e64b7b282da785307504ada59efa8096fb1) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/io.c | 36 +++--------------------------------- + 1 file changed, 3 insertions(+), 33 deletions(-) + +diff --git a/block/io.c b/block/io.c +index e260394..a0e3461 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -218,38 +218,6 @@ static bool bdrv_drain_poll_top_level(BlockDriverState *bs, + return bdrv_drain_poll(bs, ignore_parent); + } + +-static bool bdrv_drain_recurse(BlockDriverState *bs, BdrvChild *parent) +-{ +- BdrvChild *child, *tmp; +- bool waited; +- +- /* Wait for drained requests to finish */ +- waited = BDRV_POLL_WHILE(bs, bdrv_drain_poll_top_level(bs, parent)); +- +- QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) { +- BlockDriverState *bs = child->bs; +- bool in_main_loop = +- qemu_get_current_aio_context() == qemu_get_aio_context(); +- assert(bs->refcnt > 0); +- if (in_main_loop) { +- /* In case the recursive bdrv_drain_recurse processes a +- * block_job_defer_to_main_loop BH and modifies the graph, +- * let's hold a reference to bs until we are done. +- * +- * IOThread doesn't have such a BH, and it is not safe to call +- * bdrv_unref without BQL, so skip doing it there. +- */ +- bdrv_ref(bs); +- } +- waited |= bdrv_drain_recurse(bs, child); +- if (in_main_loop) { +- bdrv_unref(bs); +- } +- } +- +- return waited; +-} +- + static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, + BdrvChild *parent); + static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive, +@@ -317,7 +285,9 @@ void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, + + bdrv_parent_drained_begin(bs, parent); + bdrv_drain_invoke(bs, true); +- bdrv_drain_recurse(bs, parent); ++ ++ /* Wait for drained requests to finish */ ++ BDRV_POLL_WHILE(bs, bdrv_drain_poll_top_level(bs, parent)); + + if (recursive) { + bs->recursive_quiesce_counter++; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Remove-recursive-parameter-from-bdrv_drain_inv.patch b/SOURCES/kvm-block-Remove-recursive-parameter-from-bdrv_drain_inv.patch new file mode 100644 index 0000000..8da965b --- /dev/null +++ b/SOURCES/kvm-block-Remove-recursive-parameter-from-bdrv_drain_inv.patch @@ -0,0 +1,75 @@ +From 6ba43fc7c323ae3f0ee66262db96e22c261c1bbe Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:01 +0200 +Subject: [PATCH 10/49] block: Remove 'recursive' parameter from + bdrv_drain_invoke() + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-4-kwolf@redhat.com> +Patchwork-id: 82155 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 03/42] block: Remove 'recursive' parameter from bdrv_drain_invoke() +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +All callers pass false for the 'recursive' parameter now. Remove it. + +Signed-off-by: Kevin Wolf +Reviewed-by: Stefan Hajnoczi +(cherry picked from commit 7d40d9ef9dfb4948a857bfc6ec8408eed1d1d9e7) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/io.c | 13 +++---------- + 1 file changed, 3 insertions(+), 10 deletions(-) + +diff --git a/block/io.c b/block/io.c +index 230b551..aa41f1e 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -167,9 +167,8 @@ static void coroutine_fn bdrv_drain_invoke_entry(void *opaque) + } + + /* Recursively call BlockDriver.bdrv_co_drain_begin/end callbacks */ +-static void bdrv_drain_invoke(BlockDriverState *bs, bool begin, bool recursive) ++static void bdrv_drain_invoke(BlockDriverState *bs, bool begin) + { +- BdrvChild *child, *tmp; + BdrvCoDrainData data = { .bs = bs, .done = false, .begin = begin}; + + if (!bs->drv || (begin && !bs->drv->bdrv_co_drain_begin) || +@@ -180,12 +179,6 @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin, bool recursive) + data.co = qemu_coroutine_create(bdrv_drain_invoke_entry, &data); + bdrv_coroutine_enter(bs, data.co); + BDRV_POLL_WHILE(bs, !data.done); +- +- if (recursive) { +- QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) { +- bdrv_drain_invoke(child->bs, begin, true); +- } +- } + } + + static bool bdrv_drain_recurse(BlockDriverState *bs) +@@ -286,7 +279,7 @@ void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, + } + + bdrv_parent_drained_begin(bs, parent); +- bdrv_drain_invoke(bs, true, false); ++ bdrv_drain_invoke(bs, true); + bdrv_drain_recurse(bs); + + if (recursive) { +@@ -321,7 +314,7 @@ void bdrv_do_drained_end(BlockDriverState *bs, bool recursive, + old_quiesce_counter = atomic_fetch_dec(&bs->quiesce_counter); + + /* Re-enable things in child-to-parent order */ +- bdrv_drain_invoke(bs, false, false); ++ bdrv_drain_invoke(bs, false); + bdrv_parent_drained_end(bs, parent); + if (old_quiesce_counter == 1) { + aio_enable_external(bdrv_get_aio_context(bs)); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Set-BDRV_REQ_WRITE_UNCHANGED-for-COR-writes.patch b/SOURCES/kvm-block-Set-BDRV_REQ_WRITE_UNCHANGED-for-COR-writes.patch new file mode 100644 index 0000000..6585adb --- /dev/null +++ b/SOURCES/kvm-block-Set-BDRV_REQ_WRITE_UNCHANGED-for-COR-writes.patch @@ -0,0 +1,52 @@ +From 5e44d51d7631be589579e5e3c4dece9f651257ab Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 16:12:07 +0200 +Subject: [PATCH 31/54] block: Set BDRV_REQ_WRITE_UNCHANGED for COR writes + +RH-Author: Max Reitz +Message-id: <20180618161212.14444-6-mreitz@redhat.com> +Patchwork-id: 80766 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 05/10] block: Set BDRV_REQ_WRITE_UNCHANGED for COR writes +Bugzilla: 1518738 +RH-Acked-by: John Snow +RH-Acked-by: Kevin Wolf +RH-Acked-by: Miroslav Rezanina + +Signed-off-by: Max Reitz +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Alberto Garcia +Message-id: 20180421132929.21610-5-mreitz@redhat.com +Reviewed-by: Kevin Wolf +Signed-off-by: Max Reitz +(cherry picked from commit 7adcf59fecf3c8ce9330430187350b53f9e50cf7) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + block/io.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/block/io.c b/block/io.c +index 134b2a4..fada4ef 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -1115,13 +1115,15 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child, + /* FIXME: Should we (perhaps conditionally) be setting + * BDRV_REQ_MAY_UNMAP, if it will allow for a sparser copy + * that still correctly reads as zero? */ +- ret = bdrv_co_do_pwrite_zeroes(bs, cluster_offset, pnum, 0); ++ ret = bdrv_co_do_pwrite_zeroes(bs, cluster_offset, pnum, ++ BDRV_REQ_WRITE_UNCHANGED); + } else { + /* This does not change the data on the disk, it is not + * necessary to flush even in cache=writethrough mode. + */ + ret = bdrv_driver_pwritev(bs, cluster_offset, pnum, +- &local_qiov, 0); ++ &local_qiov, ++ BDRV_REQ_WRITE_UNCHANGED); + } + + if (ret < 0) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Support-BDRV_REQ_WRITE_UNCHANGED-in-filters.patch b/SOURCES/kvm-block-Support-BDRV_REQ_WRITE_UNCHANGED-in-filters.patch new file mode 100644 index 0000000..691760a --- /dev/null +++ b/SOURCES/kvm-block-Support-BDRV_REQ_WRITE_UNCHANGED-in-filters.patch @@ -0,0 +1,173 @@ +From faab0229fc583ca730c337b1d37d66872f4198ec Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 16:12:09 +0200 +Subject: [PATCH 33/54] block: Support BDRV_REQ_WRITE_UNCHANGED in filters + +RH-Author: Max Reitz +Message-id: <20180618161212.14444-8-mreitz@redhat.com> +Patchwork-id: 80767 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 07/10] block: Support BDRV_REQ_WRITE_UNCHANGED in filters +Bugzilla: 1518738 +RH-Acked-by: John Snow +RH-Acked-by: Kevin Wolf +RH-Acked-by: Miroslav Rezanina + +Update the rest of the filter drivers to support +BDRV_REQ_WRITE_UNCHANGED. They already forward write request flags to +their children, so we just have to announce support for it. + +This patch does not cover the replication driver because that currently +does not support flags at all, and because it just grabs the WRITE +permission for its children when it can, so we should be fine just +submitting the incoming WRITE_UNCHANGED requests as normal writes. + +It also does not cover format drivers for similar reasons. They all use +bdrv_format_default_perms() as their .bdrv_child_perm() implementation +so they just always grab the WRITE permission for their file children +whenever possible. In addition, it often would be difficult to +ascertain whether incoming unchanging writes end up as unchanging writes +in their files. So we just leave them as normal potentially changing +writes. + +Signed-off-by: Max Reitz +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Alberto Garcia +Message-id: 20180421132929.21610-7-mreitz@redhat.com +Reviewed-by: Kevin Wolf +Signed-off-by: Max Reitz +(cherry picked from commit 228345bf5db8bc97d1c64f062e138d389065d1ab) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + block/blkdebug.c | 9 +++++---- + block/blkreplay.c | 3 +++ + block/blkverify.c | 3 +++ + block/copy-on-read.c | 10 ++++++---- + block/mirror.c | 2 ++ + block/raw-format.c | 9 +++++---- + block/throttle.c | 6 ++++-- + 7 files changed, 28 insertions(+), 14 deletions(-) + +diff --git a/block/blkdebug.c b/block/blkdebug.c +index 053372c..526af2a 100644 +--- a/block/blkdebug.c ++++ b/block/blkdebug.c +@@ -398,10 +398,11 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags, + goto out; + } + +- bs->supported_write_flags = BDRV_REQ_FUA & +- bs->file->bs->supported_write_flags; +- bs->supported_zero_flags = (BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) & +- bs->file->bs->supported_zero_flags; ++ 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) & ++ bs->file->bs->supported_zero_flags); + ret = -EINVAL; + + /* Set alignment overrides */ +diff --git a/block/blkreplay.c b/block/blkreplay.c +index fe5a9b4..b016dbe 100755 +--- a/block/blkreplay.c ++++ b/block/blkreplay.c +@@ -35,6 +35,9 @@ static int blkreplay_open(BlockDriverState *bs, QDict *options, int flags, + goto fail; + } + ++ bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED; ++ bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED; ++ + ret = 0; + fail: + return ret; +diff --git a/block/blkverify.c b/block/blkverify.c +index 754cc9e..da97ee5 100644 +--- a/block/blkverify.c ++++ b/block/blkverify.c +@@ -141,6 +141,9 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags, + goto fail; + } + ++ bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED; ++ bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED; ++ + ret = 0; + fail: + qemu_opts_del(opts); +diff --git a/block/copy-on-read.c b/block/copy-on-read.c +index 823ec75..6a97208 100644 +--- a/block/copy-on-read.c ++++ b/block/copy-on-read.c +@@ -33,11 +33,13 @@ static int cor_open(BlockDriverState *bs, QDict *options, int flags, + return -EINVAL; + } + +- bs->supported_write_flags = BDRV_REQ_FUA & +- bs->file->bs->supported_write_flags; ++ bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED | ++ (BDRV_REQ_FUA & ++ bs->file->bs->supported_write_flags); + +- bs->supported_zero_flags = (BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) & +- bs->file->bs->supported_zero_flags; ++ bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED | ++ ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) & ++ bs->file->bs->supported_zero_flags); + + return 0; + } +diff --git a/block/mirror.c b/block/mirror.c +index 99da9c0..003f957 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -1152,6 +1152,8 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs, + mirror_top_bs->implicit = true; + } + mirror_top_bs->total_sectors = bs->total_sectors; ++ mirror_top_bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED; ++ mirror_top_bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED; + bdrv_set_aio_context(mirror_top_bs, bdrv_get_aio_context(bs)); + + /* bdrv_append takes ownership of the mirror_top_bs reference, need to keep +diff --git a/block/raw-format.c b/block/raw-format.c +index a378547..fe33693 100644 +--- a/block/raw-format.c ++++ b/block/raw-format.c +@@ -415,10 +415,11 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, + } + + bs->sg = bs->file->bs->sg; +- bs->supported_write_flags = BDRV_REQ_FUA & +- bs->file->bs->supported_write_flags; +- bs->supported_zero_flags = (BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) & +- bs->file->bs->supported_zero_flags; ++ 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) & ++ bs->file->bs->supported_zero_flags); + + if (bs->probed && !bdrv_is_read_only(bs)) { + fprintf(stderr, +diff --git a/block/throttle.c b/block/throttle.c +index 95ed06a..e298827 100644 +--- a/block/throttle.c ++++ b/block/throttle.c +@@ -81,8 +81,10 @@ static int throttle_open(BlockDriverState *bs, QDict *options, + if (!bs->file) { + return -EINVAL; + } +- bs->supported_write_flags = bs->file->bs->supported_write_flags; +- bs->supported_zero_flags = bs->file->bs->supported_zero_flags; ++ bs->supported_write_flags = bs->file->bs->supported_write_flags | ++ BDRV_REQ_WRITE_UNCHANGED; ++ bs->supported_zero_flags = bs->file->bs->supported_zero_flags | ++ BDRV_REQ_WRITE_UNCHANGED; + + return throttle_configure_tgm(bs, tgm, options, errp); + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Use-a-single-global-AioWait.patch b/SOURCES/kvm-block-Use-a-single-global-AioWait.patch new file mode 100644 index 0000000..16cf302 --- /dev/null +++ b/SOURCES/kvm-block-Use-a-single-global-AioWait.patch @@ -0,0 +1,335 @@ +From 54d30086f066f1094871c4886f3a6dee51263d76 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 21 Sep 2018 12:46:29 +0200 +Subject: [PATCH 2/3] block: Use a single global AioWait + +RH-Author: Kevin Wolf +Message-id: <20180921124630.29036-3-kwolf@redhat.com> +Patchwork-id: 82231 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 2/3] block: Use a single global AioWait +Bugzilla: 1618584 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Paolo Bonzini +RH-Acked-by: John Snow +RH-Acked-by: Eric Blake + +When draining a block node, we recurse to its parent and for subtree +drains also to its children. A single AIO_WAIT_WHILE() is then used to +wait for bdrv_drain_poll() to become true, which depends on all of the +nodes we recursed to. However, if the respective child or parent becomes +quiescent and calls bdrv_wakeup(), only the AioWait of the child/parent +is checked, while AIO_WAIT_WHILE() depends on the AioWait of the +original node. + +Fix this by using a single AioWait for all callers of AIO_WAIT_WHILE(). + +This may mean that the draining thread gets a few more unnecessary +wakeups because an unrelated operation got completed, but we already +wake it up when something _could_ have changed rather than only if it +has certainly changed. + +Apart from that, drain is a slow path anyway. In theory it would be +possible to use wakeups more selectively and still correctly, but the +gains are likely not worth the additional complexity. In fact, this +patch is a nice simplification for some places in the code. + +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block.c | 5 ----- + block/block-backend.c | 11 ++++------- + block/io.c | 7 ++----- + blockjob.c | 13 +------------ + include/block/aio-wait.h | 11 +++++------ + include/block/block.h | 6 +----- + include/block/block_int.h | 3 --- + include/block/blockjob.h | 10 ---------- + job.c | 3 +-- + util/aio-wait.c | 11 ++++++----- + 10 files changed, 20 insertions(+), 60 deletions(-) + +diff --git a/block.c b/block.c +index e89b5e3..fbd569c 100644 +--- a/block.c ++++ b/block.c +@@ -4847,11 +4847,6 @@ AioContext *bdrv_get_aio_context(BlockDriverState *bs) + return bs ? bs->aio_context : qemu_get_aio_context(); + } + +-AioWait *bdrv_get_aio_wait(BlockDriverState *bs) +-{ +- return bs ? &bs->wait : NULL; +-} +- + void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co) + { + aio_co_enter(bdrv_get_aio_context(bs), co); +diff --git a/block/block-backend.c b/block/block-backend.c +index 466bc27..36922d1 100644 +--- a/block/block-backend.c ++++ b/block/block-backend.c +@@ -88,7 +88,6 @@ struct BlockBackend { + * Accessed with atomic ops. + */ + unsigned int in_flight; +- AioWait wait; + }; + + typedef struct BlockBackendAIOCB { +@@ -1300,7 +1299,7 @@ static void blk_inc_in_flight(BlockBackend *blk) + static void blk_dec_in_flight(BlockBackend *blk) + { + atomic_dec(&blk->in_flight); +- aio_wait_kick(&blk->wait); ++ aio_wait_kick(); + } + + static void error_callback_bh(void *opaque) +@@ -1609,9 +1608,8 @@ void blk_drain(BlockBackend *blk) + } + + /* We may have -ENOMEDIUM completions in flight */ +- AIO_WAIT_WHILE(&blk->wait, +- blk_get_aio_context(blk), +- atomic_mb_read(&blk->in_flight) > 0); ++ AIO_WAIT_WHILE(blk_get_aio_context(blk), ++ atomic_mb_read(&blk->in_flight) > 0); + + if (bs) { + bdrv_drained_end(bs); +@@ -1630,8 +1628,7 @@ void blk_drain_all(void) + aio_context_acquire(ctx); + + /* We may have -ENOMEDIUM completions in flight */ +- AIO_WAIT_WHILE(&blk->wait, ctx, +- atomic_mb_read(&blk->in_flight) > 0); ++ AIO_WAIT_WHILE(ctx, atomic_mb_read(&blk->in_flight) > 0); + + aio_context_release(ctx); + } +diff --git a/block/io.c b/block/io.c +index 3313958..7a99f7b 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -38,8 +38,6 @@ + /* Maximum bounce buffer for copy-on-read and write zeroes, in bytes */ + #define MAX_BOUNCE_BUFFER (32768 << BDRV_SECTOR_BITS) + +-static AioWait drain_all_aio_wait; +- + static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, + int64_t offset, int bytes, BdrvRequestFlags flags); + +@@ -555,7 +553,7 @@ void bdrv_drain_all_begin(void) + } + + /* Now poll the in-flight requests */ +- AIO_WAIT_WHILE(&drain_all_aio_wait, NULL, bdrv_drain_all_poll()); ++ AIO_WAIT_WHILE(NULL, bdrv_drain_all_poll()); + + while ((bs = bdrv_next_all_states(bs))) { + bdrv_drain_assert_idle(bs); +@@ -709,8 +707,7 @@ void bdrv_inc_in_flight(BlockDriverState *bs) + + void bdrv_wakeup(BlockDriverState *bs) + { +- aio_wait_kick(bdrv_get_aio_wait(bs)); +- aio_wait_kick(&drain_all_aio_wait); ++ aio_wait_kick(); + } + + void bdrv_dec_in_flight(BlockDriverState *bs) +diff --git a/blockjob.c b/blockjob.c +index 617d86f..06f2429 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -221,20 +221,9 @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs, + return 0; + } + +-void block_job_wakeup_all_bdrv(BlockJob *job) +-{ +- GSList *l; +- +- for (l = job->nodes; l; l = l->next) { +- BdrvChild *c = l->data; +- bdrv_wakeup(c->bs); +- } +-} +- + static void block_job_on_idle(Notifier *n, void *opaque) + { +- BlockJob *job = opaque; +- block_job_wakeup_all_bdrv(job); ++ aio_wait_kick(); + } + + bool block_job_is_internal(BlockJob *job) +diff --git a/include/block/aio-wait.h b/include/block/aio-wait.h +index 600fad1..46f86f9 100644 +--- a/include/block/aio-wait.h ++++ b/include/block/aio-wait.h +@@ -54,9 +54,10 @@ typedef struct { + unsigned num_waiters; + } AioWait; + ++extern AioWait global_aio_wait; ++ + /** + * AIO_WAIT_WHILE: +- * @wait: the aio wait object + * @ctx: the aio context, or NULL if multiple aio contexts (for which the + * caller does not hold a lock) are involved in the polling condition. + * @cond: wait while this conditional expression is true +@@ -72,9 +73,9 @@ typedef struct { + * wait on conditions between two IOThreads since that could lead to deadlock, + * go via the main loop instead. + */ +-#define AIO_WAIT_WHILE(wait, ctx, cond) ({ \ ++#define AIO_WAIT_WHILE(ctx, cond) ({ \ + bool waited_ = false; \ +- AioWait *wait_ = (wait); \ ++ AioWait *wait_ = &global_aio_wait; \ + AioContext *ctx_ = (ctx); \ + /* Increment wait_->num_waiters before evaluating cond. */ \ + atomic_inc(&wait_->num_waiters); \ +@@ -102,14 +103,12 @@ typedef struct { + + /** + * aio_wait_kick: +- * @wait: the aio wait object that should re-evaluate its condition +- * + * Wake up the main thread if it is waiting on AIO_WAIT_WHILE(). During + * synchronous operations performed in an IOThread, the main thread lets the + * IOThread's event loop run, waiting for the operation to complete. A + * aio_wait_kick() call will wake up the main thread. + */ +-void aio_wait_kick(AioWait *wait); ++void aio_wait_kick(void); + + /** + * aio_wait_bh_oneshot: +diff --git a/include/block/block.h b/include/block/block.h +index 356712c..8e78daf 100644 +--- a/include/block/block.h ++++ b/include/block/block.h +@@ -406,13 +406,9 @@ void bdrv_drain_all_begin(void); + void bdrv_drain_all_end(void); + void bdrv_drain_all(void); + +-/* Returns NULL when bs == NULL */ +-AioWait *bdrv_get_aio_wait(BlockDriverState *bs); +- + #define BDRV_POLL_WHILE(bs, cond) ({ \ + BlockDriverState *bs_ = (bs); \ +- AIO_WAIT_WHILE(bdrv_get_aio_wait(bs_), \ +- bdrv_get_aio_context(bs_), \ ++ AIO_WAIT_WHILE(bdrv_get_aio_context(bs_), \ + cond); }) + + int bdrv_pdiscard(BlockDriverState *bs, int64_t offset, int bytes); +diff --git a/include/block/block_int.h b/include/block/block_int.h +index b7806e3..ff923b7 100644 +--- a/include/block/block_int.h ++++ b/include/block/block_int.h +@@ -782,9 +782,6 @@ struct BlockDriverState { + unsigned int in_flight; + unsigned int serialising_in_flight; + +- /* Kicked to signal main loop when a request completes. */ +- AioWait wait; +- + /* counter for nested bdrv_io_plug. + * Accessed with atomic ops. + */ +diff --git a/include/block/blockjob.h b/include/block/blockjob.h +index 2290bbb..ede0bd8 100644 +--- a/include/block/blockjob.h ++++ b/include/block/blockjob.h +@@ -122,16 +122,6 @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs, + void block_job_remove_all_bdrv(BlockJob *job); + + /** +- * block_job_wakeup_all_bdrv: +- * @job: The block job +- * +- * Calls bdrv_wakeup() for all BlockDriverStates that have been added to the +- * job. This function is to be called whenever child_job_drained_poll() would +- * go from true to false to notify waiting drain requests. +- */ +-void block_job_wakeup_all_bdrv(BlockJob *job); +- +-/** + * block_job_set_speed: + * @job: The job to set the speed for. + * @speed: The new value +diff --git a/job.c b/job.c +index 5b53e43..3a7db59 100644 +--- a/job.c ++++ b/job.c +@@ -973,7 +973,6 @@ void job_complete(Job *job, Error **errp) + int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp) + { + Error *local_err = NULL; +- AioWait dummy_wait = {}; + int ret; + + job_ref(job); +@@ -987,7 +986,7 @@ int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp) + return -EBUSY; + } + +- AIO_WAIT_WHILE(&dummy_wait, job->aio_context, ++ AIO_WAIT_WHILE(job->aio_context, + (job_drain(job), !job_is_completed(job))); + + ret = (job_is_cancelled(job) && job->ret == 0) ? -ECANCELED : job->ret; +diff --git a/util/aio-wait.c b/util/aio-wait.c +index b8a8f86..b487749 100644 +--- a/util/aio-wait.c ++++ b/util/aio-wait.c +@@ -26,21 +26,22 @@ + #include "qemu/main-loop.h" + #include "block/aio-wait.h" + ++AioWait global_aio_wait; ++ + static void dummy_bh_cb(void *opaque) + { + /* The point is to make AIO_WAIT_WHILE()'s aio_poll() return */ + } + +-void aio_wait_kick(AioWait *wait) ++void aio_wait_kick(void) + { + /* The barrier (or an atomic op) is in the caller. */ +- if (atomic_read(&wait->num_waiters)) { ++ if (atomic_read(&global_aio_wait.num_waiters)) { + aio_bh_schedule_oneshot(qemu_get_aio_context(), dummy_bh_cb, NULL); + } + } + + typedef struct { +- AioWait wait; + bool done; + QEMUBHFunc *cb; + void *opaque; +@@ -54,7 +55,7 @@ static void aio_wait_bh(void *opaque) + data->cb(data->opaque); + + data->done = true; +- aio_wait_kick(&data->wait); ++ aio_wait_kick(); + } + + void aio_wait_bh_oneshot(AioContext *ctx, QEMUBHFunc *cb, void *opaque) +@@ -67,5 +68,5 @@ void aio_wait_bh_oneshot(AioContext *ctx, QEMUBHFunc *cb, void *opaque) + assert(qemu_get_current_aio_context() == qemu_get_aio_context()); + + aio_bh_schedule_oneshot(ctx, aio_wait_bh, &data); +- AIO_WAIT_WHILE(&data.wait, ctx, !data.done); ++ AIO_WAIT_WHILE(ctx, !data.done); + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Use-bdrv_do_drain_begin-end-in-bdrv_drain_all.patch b/SOURCES/kvm-block-Use-bdrv_do_drain_begin-end-in-bdrv_drain_all.patch new file mode 100644 index 0000000..ac2c3b6 --- /dev/null +++ b/SOURCES/kvm-block-Use-bdrv_do_drain_begin-end-in-bdrv_drain_all.patch @@ -0,0 +1,113 @@ +From 21362b70047568949d14388b254e4b87674a2730 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:00 +0200 +Subject: [PATCH 09/49] block: Use bdrv_do_drain_begin/end in bdrv_drain_all() + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-3-kwolf@redhat.com> +Patchwork-id: 82154 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 02/42] block: Use bdrv_do_drain_begin/end in bdrv_drain_all() +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +bdrv_do_drain_begin/end() implement already everything that +bdrv_drain_all_begin/end() need and currently still do manually: Disable +external events, call parent drain callbacks, call block driver +callbacks. + +It also does two more things: + +The first is incrementing bs->quiesce_counter. bdrv_drain_all() already +stood out in the test case by behaving different from the other drain +variants. Adding this is not only safe, but in fact a bug fix. + +The second is calling bdrv_drain_recurse(). We already do that later in +the same function in a loop, so basically doing an early first iteration +doesn't hurt. + +Signed-off-by: Kevin Wolf +Reviewed-by: Stefan Hajnoczi +(cherry picked from commit 79ab8b21dc19c08adc407504e456ff64b9dacb66) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/io.c | 10 ++-------- + tests/test-bdrv-drain.c | 14 ++++---------- + 2 files changed, 6 insertions(+), 18 deletions(-) + +diff --git a/block/io.c b/block/io.c +index 7e0a169..230b551 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -412,11 +412,8 @@ void bdrv_drain_all_begin(void) + for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { + AioContext *aio_context = bdrv_get_aio_context(bs); + +- /* Stop things in parent-to-child order */ + aio_context_acquire(aio_context); +- aio_disable_external(aio_context); +- bdrv_parent_drained_begin(bs, NULL); +- bdrv_drain_invoke(bs, true, true); ++ bdrv_do_drained_begin(bs, true, NULL); + aio_context_release(aio_context); + + if (!g_slist_find(aio_ctxs, aio_context)) { +@@ -457,11 +454,8 @@ void bdrv_drain_all_end(void) + for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { + AioContext *aio_context = bdrv_get_aio_context(bs); + +- /* Re-enable things in child-to-parent order */ + aio_context_acquire(aio_context); +- bdrv_drain_invoke(bs, false, true); +- bdrv_parent_drained_end(bs, NULL); +- aio_enable_external(aio_context); ++ bdrv_do_drained_end(bs, true, NULL); + aio_context_release(aio_context); + } + } +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index dee0a10..f1276a1 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -276,8 +276,7 @@ static void test_quiesce_common(enum drain_type drain_type, bool recursive) + + static void test_quiesce_drain_all(void) + { +- // XXX drain_all doesn't quiesce +- //test_quiesce_common(BDRV_DRAIN_ALL, true); ++ test_quiesce_common(BDRV_DRAIN_ALL, true); + } + + static void test_quiesce_drain(void) +@@ -319,12 +318,7 @@ static void test_nested(void) + + for (outer = 0; outer < DRAIN_TYPE_MAX; outer++) { + for (inner = 0; inner < DRAIN_TYPE_MAX; inner++) { +- /* XXX bdrv_drain_all() doesn't increase the quiesce_counter */ +- int bs_quiesce = (outer != BDRV_DRAIN_ALL) + +- (inner != BDRV_DRAIN_ALL); +- int backing_quiesce = (outer == BDRV_SUBTREE_DRAIN) + +- (inner == BDRV_SUBTREE_DRAIN); +- int backing_cb_cnt = (outer != BDRV_DRAIN) + ++ int backing_quiesce = (outer != BDRV_DRAIN) + + (inner != BDRV_DRAIN); + + g_assert_cmpint(bs->quiesce_counter, ==, 0); +@@ -335,10 +329,10 @@ static void test_nested(void) + do_drain_begin(outer, bs); + do_drain_begin(inner, bs); + +- g_assert_cmpint(bs->quiesce_counter, ==, bs_quiesce); ++ g_assert_cmpint(bs->quiesce_counter, ==, 2); + g_assert_cmpint(backing->quiesce_counter, ==, backing_quiesce); + g_assert_cmpint(s->drain_count, ==, 2); +- g_assert_cmpint(backing_s->drain_count, ==, backing_cb_cnt); ++ g_assert_cmpint(backing_s->drain_count, ==, backing_quiesce); + + do_drain_end(inner, bs); + do_drain_end(outer, bs); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-Use-tracked-request-for-truncate.patch b/SOURCES/kvm-block-Use-tracked-request-for-truncate.patch new file mode 100644 index 0000000..f9023e0 --- /dev/null +++ b/SOURCES/kvm-block-Use-tracked-request-for-truncate.patch @@ -0,0 +1,104 @@ +From 309929687960d52f77df69a745bd1c351023febb Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Thu, 12 Jul 2018 14:42:57 +0200 +Subject: [PATCH 38/89] block: Use tracked request for truncate + +RH-Author: Kevin Wolf +Message-id: <20180712144258.17303-6-kwolf@redhat.com> +Patchwork-id: 81326 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 5/6] block: Use tracked request for truncate +Bugzilla: 1595173 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: John Snow + +When growing an image, block drivers (especially protocol drivers) may +initialise the newly added area. I/O requests to the same area need to +wait for this initialisation to be completed so that data writes don't +get overwritten and reads don't read uninitialised data. + +To avoid overhead in the fast I/O path by adding new locking in the +protocol drivers and to restrict the impact to requests that actually +touch the new area, reuse the existing tracked request infrastructure in +block/io.c and mark all discard requests as serialising. + +With this change, it is safe for protocol drivers to make +.bdrv_co_truncate actually asynchronous. + +Signed-off-by: Kevin Wolf +Reviewed-by: Stefan Hajnoczi +(cherry picked from commit 1bc5f09f2e1b2be8f6f737b8d5352b438fc41492) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/io.c | 25 +++++++++++++++++++++++++ + include/block/block_int.h | 1 + + 2 files changed, 26 insertions(+) + +diff --git a/block/io.c b/block/io.c +index 32a82e3..ad8afc0 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -2948,6 +2948,8 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, + { + BlockDriverState *bs = child->bs; + BlockDriver *drv = bs->drv; ++ BdrvTrackedRequest req; ++ int64_t old_size, new_bytes; + int ret; + + assert(child->perm & BLK_PERM_RESIZE); +@@ -2962,7 +2964,28 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, + return -EINVAL; + } + ++ old_size = bdrv_getlength(bs); ++ if (old_size < 0) { ++ error_setg_errno(errp, -old_size, "Failed to get old image size"); ++ return old_size; ++ } ++ ++ if (offset > old_size) { ++ new_bytes = offset - old_size; ++ } else { ++ new_bytes = 0; ++ } ++ + bdrv_inc_in_flight(bs); ++ tracked_request_begin(&req, bs, offset, new_bytes, BDRV_TRACKED_TRUNCATE); ++ ++ /* If we are growing the image and potentially using preallocation for the ++ * new area, we need to make sure that no write requests are made to it ++ * concurrently or they might be overwritten by preallocation. */ ++ if (new_bytes) { ++ mark_request_serialising(&req, 1); ++ wait_serialising_requests(&req); ++ } + + if (!drv->bdrv_co_truncate) { + if (bs->file && drv->is_filter) { +@@ -2996,7 +3019,9 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, + atomic_inc(&bs->write_gen); + + out: ++ tracked_request_end(&req); + bdrv_dec_in_flight(bs); ++ + return ret; + } + +diff --git a/include/block/block_int.h b/include/block/block_int.h +index 6a844ec..27e168f 100644 +--- a/include/block/block_int.h ++++ b/include/block/block_int.h +@@ -63,6 +63,7 @@ enum BdrvTrackedRequestType { + BDRV_TRACKED_READ, + BDRV_TRACKED_WRITE, + BDRV_TRACKED_DISCARD, ++ BDRV_TRACKED_TRUNCATE, + }; + + typedef struct BdrvTrackedRequest { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-add-BDRV_REQ_SERIALISING-flag.patch b/SOURCES/kvm-block-add-BDRV_REQ_SERIALISING-flag.patch new file mode 100644 index 0000000..3ebed8a --- /dev/null +++ b/SOURCES/kvm-block-add-BDRV_REQ_SERIALISING-flag.patch @@ -0,0 +1,137 @@ +From 0ea414a81a3e1372257a54c8756a643b91ae773a Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 18 Jul 2018 22:54:57 +0200 +Subject: [PATCH 72/89] block: add BDRV_REQ_SERIALISING flag + +RH-Author: John Snow +Message-id: <20180718225511.14878-22-jsnow@redhat.com> +Patchwork-id: 81421 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 21/35] block: add BDRV_REQ_SERIALISING flag +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Vladimir Sementsov-Ogievskiy + +Serialized writes should be used in copy-on-write of backup(sync=none) +for image fleecing scheme. + +We need to change an assert in bdrv_aligned_pwritev, added in +28de2dcd88de. The assert may fail now, because call to +wait_serialising_requests here may become first call to it for this +request with serializing flag set. It occurs if the request is aligned +(otherwise, we should already set serializing flag before calling +bdrv_aligned_pwritev and correspondingly waited for all intersecting +requests). However, for aligned requests, we should not care about +outdating of previously read data, as there no such data. Therefore, +let's just update an assert to not care about aligned requests. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: Fam Zheng +Signed-off-by: Kevin Wolf +(cherry picked from commit 09d2f948462f4979d18f573a0734d1daae8e67a9) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/io.c | 28 +++++++++++++++++++++++++++- + include/block/block.h | 14 +++++++++++++- + 2 files changed, 40 insertions(+), 2 deletions(-) + +diff --git a/block/io.c b/block/io.c +index 2d04289..bb617de 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -535,6 +535,18 @@ static void mark_request_serialising(BdrvTrackedRequest *req, uint64_t align) + req->overlap_bytes = MAX(req->overlap_bytes, overlap_bytes); + } + ++static bool is_request_serialising_and_aligned(BdrvTrackedRequest *req) ++{ ++ /* ++ * If the request is serialising, overlap_offset and overlap_bytes are set, ++ * so we can check if the request is aligned. Otherwise, don't care and ++ * return false. ++ */ ++ ++ return req->serialising && (req->offset == req->overlap_offset) && ++ (req->bytes == req->overlap_bytes); ++} ++ + /** + * Round a region to cluster boundaries + */ +@@ -1206,6 +1218,9 @@ static int coroutine_fn bdrv_aligned_preadv(BdrvChild *child, + mark_request_serialising(req, bdrv_get_cluster_size(bs)); + } + ++ /* BDRV_REQ_SERIALISING is only for write operation */ ++ assert(!(flags & BDRV_REQ_SERIALISING)); ++ + if (!(flags & BDRV_REQ_NO_SERIALISING)) { + wait_serialising_requests(req); + } +@@ -1507,8 +1522,14 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child, + + /* BDRV_REQ_NO_SERIALISING is only for read operation */ + assert(!(flags & BDRV_REQ_NO_SERIALISING)); ++ ++ if (flags & BDRV_REQ_SERIALISING) { ++ mark_request_serialising(req, bdrv_get_cluster_size(bs)); ++ } ++ + waited = wait_serialising_requests(req); +- assert(!waited || !req->serialising); ++ assert(!waited || !req->serialising || ++ is_request_serialising_and_aligned(req)); + assert(req->overlap_offset <= offset); + assert(offset + bytes <= req->overlap_offset + req->overlap_bytes); + if (flags & BDRV_REQ_WRITE_UNCHANGED) { +@@ -2881,6 +2902,8 @@ static int coroutine_fn bdrv_co_copy_range_internal( + tracked_request_begin(&req, src->bs, src_offset, bytes, + BDRV_TRACKED_READ); + ++ /* BDRV_REQ_SERIALISING is only for write operation */ ++ assert(!(read_flags & BDRV_REQ_SERIALISING)); + if (!(read_flags & BDRV_REQ_NO_SERIALISING)) { + wait_serialising_requests(&req); + } +@@ -2900,6 +2923,9 @@ static int coroutine_fn bdrv_co_copy_range_internal( + + /* BDRV_REQ_NO_SERIALISING is only for read operation */ + assert(!(write_flags & BDRV_REQ_NO_SERIALISING)); ++ if (write_flags & BDRV_REQ_SERIALISING) { ++ mark_request_serialising(&req, bdrv_get_cluster_size(dst->bs)); ++ } + wait_serialising_requests(&req); + + ret = dst->bs->drv->bdrv_co_copy_range_to(dst->bs, +diff --git a/include/block/block.h b/include/block/block.h +index 409db21..8f87eea 100644 +--- a/include/block/block.h ++++ b/include/block/block.h +@@ -70,8 +70,20 @@ typedef enum { + * content. */ + BDRV_REQ_WRITE_UNCHANGED = 0x40, + ++ /* ++ * BDRV_REQ_SERIALISING forces request serialisation for writes. ++ * It is used to ensure that writes to the backing file of a backup process ++ * target cannot race with a read of the backup target that defers to the ++ * backing file. ++ * ++ * Note, that BDRV_REQ_SERIALISING is _not_ opposite in meaning to ++ * BDRV_REQ_NO_SERIALISING. A more descriptive name for the latter might be ++ * _DO_NOT_WAIT_FOR_SERIALISING, except that is too long. ++ */ ++ BDRV_REQ_SERIALISING = 0x80, ++ + /* Mask of valid flags */ +- BDRV_REQ_MASK = 0x7f, ++ BDRV_REQ_MASK = 0xff, + } BdrvRequestFlags; + + typedef struct BlockSizes { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-add-aio_context-field-in-ThrottleGroupMember.patch b/SOURCES/kvm-block-add-aio_context-field-in-ThrottleGroupMember.patch deleted file mode 100644 index 7d28b03..0000000 --- a/SOURCES/kvm-block-add-aio_context-field-in-ThrottleGroupMember.patch +++ /dev/null @@ -1,376 +0,0 @@ -From 5531090858f0cb3aabf6e95a948256b4eeb36e5a Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Fri, 17 Nov 2017 11:19:01 +0100 -Subject: [PATCH 02/15] block: add aio_context field in ThrottleGroupMember - -RH-Author: Stefan Hajnoczi -Message-id: <20171117111908.8815-3-stefanha@redhat.com> -Patchwork-id: 77735 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 2/9] block: add aio_context field in ThrottleGroupMember -Bugzilla: 1492295 -RH-Acked-by: John Snow -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth - -From: Manos Pitsidianakis - -timer_cb() needs to know about the current Aio context of the throttle -request that is woken up. In order to make ThrottleGroupMember backend -agnostic, this information is stored in an aio_context field instead of -accessing it from BlockBackend. - -Reviewed-by: Alberto Garcia -Reviewed-by: Stefan Hajnoczi -Signed-off-by: Manos Pitsidianakis -Signed-off-by: Kevin Wolf -(cherry picked from commit c61791fc23ecd96e6a1e038c379c4033ffd5f40c) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - block/block-backend.c | 15 ++++------ - block/throttle-groups.c | 38 ++++++++++++++++--------- - include/block/throttle-groups.h | 7 ++++- - tests/test-throttle.c | 63 +++++++++++++++++++++-------------------- - 4 files changed, 69 insertions(+), 54 deletions(-) - -diff --git a/block/block-backend.c b/block/block-backend.c -index e61f072..515be10 100644 ---- a/block/block-backend.c -+++ b/block/block-backend.c -@@ -1766,18 +1766,14 @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb) - void blk_set_aio_context(BlockBackend *blk, AioContext *new_context) - { - BlockDriverState *bs = blk_bs(blk); -- ThrottleTimers *tt; -+ ThrottleGroupMember *tgm = &blk->public.throttle_group_member; - - if (bs) { -- if (blk->public.throttle_group_member.throttle_state) { -- tt = &blk->public.throttle_group_member.throttle_timers; -- throttle_timers_detach_aio_context(tt); -+ if (tgm->throttle_state) { -+ throttle_group_detach_aio_context(tgm); -+ throttle_group_attach_aio_context(tgm, new_context); - } - bdrv_set_aio_context(bs, new_context); -- if (blk->public.throttle_group_member.throttle_state) { -- tt = &blk->public.throttle_group_member.throttle_timers; -- throttle_timers_attach_aio_context(tt, new_context); -- } - } - } - -@@ -2010,7 +2006,8 @@ void blk_io_limits_disable(BlockBackend *blk) - void blk_io_limits_enable(BlockBackend *blk, const char *group) - { - assert(!blk->public.throttle_group_member.throttle_state); -- throttle_group_register_tgm(&blk->public.throttle_group_member, group); -+ throttle_group_register_tgm(&blk->public.throttle_group_member, -+ group, blk_get_aio_context(blk)); - } - - void blk_io_limits_update_group(BlockBackend *blk, const char *group) -diff --git a/block/throttle-groups.c b/block/throttle-groups.c -index c8ed16d..3b07b25 100644 ---- a/block/throttle-groups.c -+++ b/block/throttle-groups.c -@@ -391,9 +391,6 @@ static void coroutine_fn throttle_group_restart_queue_entry(void *opaque) - - static void throttle_group_restart_queue(ThrottleGroupMember *tgm, bool is_write) - { -- BlockBackendPublic *blkp = container_of(tgm, BlockBackendPublic, -- throttle_group_member); -- BlockBackend *blk = blk_by_public(blkp); - Coroutine *co; - RestartData rd = { - .tgm = tgm, -@@ -401,7 +398,7 @@ static void throttle_group_restart_queue(ThrottleGroupMember *tgm, bool is_write - }; - - co = qemu_coroutine_create(throttle_group_restart_queue_entry, &rd); -- aio_co_enter(blk_get_aio_context(blk), co); -+ aio_co_enter(tgm->aio_context, co); - } - - void throttle_group_restart_tgm(ThrottleGroupMember *tgm) -@@ -449,13 +446,11 @@ void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg) - /* ThrottleTimers callback. This wakes up a request that was waiting - * because it had been throttled. - * -- * @blk: the BlockBackend whose request had been throttled -+ * @tgm: the ThrottleGroupMember whose request had been throttled - * @is_write: the type of operation (read/write) - */ --static void timer_cb(BlockBackend *blk, bool is_write) -+static void timer_cb(ThrottleGroupMember *tgm, bool is_write) - { -- BlockBackendPublic *blkp = blk_get_public(blk); -- ThrottleGroupMember *tgm = &blkp->throttle_group_member; - ThrottleState *ts = tgm->throttle_state; - ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts); - -@@ -484,18 +479,18 @@ static void write_timer_cb(void *opaque) - * - * @tgm: the ThrottleGroupMember to insert - * @groupname: the name of the group -+ * @ctx: the AioContext to use - */ - void throttle_group_register_tgm(ThrottleGroupMember *tgm, -- const char *groupname) -+ const char *groupname, -+ AioContext *ctx) - { - int i; -- BlockBackendPublic *blkp = container_of(tgm, BlockBackendPublic, -- throttle_group_member); -- BlockBackend *blk = blk_by_public(blkp); - ThrottleState *ts = throttle_group_incref(groupname); - ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts); - - tgm->throttle_state = ts; -+ tgm->aio_context = ctx; - - qemu_mutex_lock(&tg->lock); - /* If the ThrottleGroup is new set this ThrottleGroupMember as the token */ -@@ -508,11 +503,11 @@ void throttle_group_register_tgm(ThrottleGroupMember *tgm, - QLIST_INSERT_HEAD(&tg->head, tgm, round_robin); - - throttle_timers_init(&tgm->throttle_timers, -- blk_get_aio_context(blk), -+ tgm->aio_context, - tg->clock_type, - read_timer_cb, - write_timer_cb, -- blk); -+ tgm); - - qemu_mutex_unlock(&tg->lock); - } -@@ -559,6 +554,21 @@ void throttle_group_unregister_tgm(ThrottleGroupMember *tgm) - tgm->throttle_state = NULL; - } - -+void throttle_group_attach_aio_context(ThrottleGroupMember *tgm, -+ AioContext *new_context) -+{ -+ ThrottleTimers *tt = &tgm->throttle_timers; -+ throttle_timers_attach_aio_context(tt, new_context); -+ tgm->aio_context = new_context; -+} -+ -+void throttle_group_detach_aio_context(ThrottleGroupMember *tgm) -+{ -+ ThrottleTimers *tt = &tgm->throttle_timers; -+ throttle_timers_detach_aio_context(tt); -+ tgm->aio_context = NULL; -+} -+ - static void throttle_groups_init(void) - { - qemu_mutex_init(&throttle_groups_lock); -diff --git a/include/block/throttle-groups.h b/include/block/throttle-groups.h -index 1a6bcda..a0f27ca 100644 ---- a/include/block/throttle-groups.h -+++ b/include/block/throttle-groups.h -@@ -33,6 +33,7 @@ - */ - - typedef struct ThrottleGroupMember { -+ AioContext *aio_context; - /* throttled_reqs_lock protects the CoQueues for throttled requests. */ - CoMutex throttled_reqs_lock; - CoQueue throttled_reqs[2]; -@@ -61,12 +62,16 @@ void throttle_group_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg); - void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg); - - void throttle_group_register_tgm(ThrottleGroupMember *tgm, -- const char *groupname); -+ const char *groupname, -+ AioContext *ctx); - void throttle_group_unregister_tgm(ThrottleGroupMember *tgm); - void throttle_group_restart_tgm(ThrottleGroupMember *tgm); - - void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember *tgm, - unsigned int bytes, - bool is_write); -+void throttle_group_attach_aio_context(ThrottleGroupMember *tgm, -+ AioContext *new_context); -+void throttle_group_detach_aio_context(ThrottleGroupMember *tgm); - - #endif -diff --git a/tests/test-throttle.c b/tests/test-throttle.c -index 6e6d926..57cf5ba 100644 ---- a/tests/test-throttle.c -+++ b/tests/test-throttle.c -@@ -24,8 +24,9 @@ - static AioContext *ctx; - static LeakyBucket bkt; - static ThrottleConfig cfg; -+static ThrottleGroupMember tgm; - static ThrottleState ts; --static ThrottleTimers tt; -+static ThrottleTimers *tt; - - /* useful function */ - static bool double_cmp(double x, double y) -@@ -153,19 +154,21 @@ static void test_init(void) - { - int i; - -+ tt = &tgm.throttle_timers; -+ - /* fill the structures with crap */ - memset(&ts, 1, sizeof(ts)); -- memset(&tt, 1, sizeof(tt)); -+ memset(tt, 1, sizeof(*tt)); - - /* init structures */ - throttle_init(&ts); -- throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL, -+ throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL, - read_timer_cb, write_timer_cb, &ts); - - /* check initialized fields */ -- g_assert(tt.clock_type == QEMU_CLOCK_VIRTUAL); -- g_assert(tt.timers[0]); -- g_assert(tt.timers[1]); -+ g_assert(tt->clock_type == QEMU_CLOCK_VIRTUAL); -+ g_assert(tt->timers[0]); -+ g_assert(tt->timers[1]); - - /* check other fields where cleared */ - g_assert(!ts.previous_leak); -@@ -176,18 +179,18 @@ static void test_init(void) - g_assert(!ts.cfg.buckets[i].level); - } - -- throttle_timers_destroy(&tt); -+ throttle_timers_destroy(tt); - } - - static void test_destroy(void) - { - int i; - throttle_init(&ts); -- throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL, -+ throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL, - read_timer_cb, write_timer_cb, &ts); -- throttle_timers_destroy(&tt); -+ throttle_timers_destroy(tt); - for (i = 0; i < 2; i++) { -- g_assert(!tt.timers[i]); -+ g_assert(!tt->timers[i]); - } - } - -@@ -224,7 +227,7 @@ static void test_config_functions(void) - orig_cfg.op_size = 1; - - throttle_init(&ts); -- throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL, -+ throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL, - read_timer_cb, write_timer_cb, &ts); - /* structure reset by throttle_init previous_leak should be null */ - g_assert(!ts.previous_leak); -@@ -236,7 +239,7 @@ static void test_config_functions(void) - /* get back the fixed configuration */ - throttle_get_config(&ts, &final_cfg); - -- throttle_timers_destroy(&tt); -+ throttle_timers_destroy(tt); - - g_assert(final_cfg.buckets[THROTTLE_BPS_TOTAL].avg == 153); - g_assert(final_cfg.buckets[THROTTLE_BPS_READ].avg == 56); -@@ -417,45 +420,45 @@ static void test_have_timer(void) - { - /* zero structures */ - memset(&ts, 0, sizeof(ts)); -- memset(&tt, 0, sizeof(tt)); -+ memset(tt, 0, sizeof(*tt)); - - /* no timer set should return false */ -- g_assert(!throttle_timers_are_initialized(&tt)); -+ g_assert(!throttle_timers_are_initialized(tt)); - - /* init structures */ - throttle_init(&ts); -- throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL, -+ throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL, - read_timer_cb, write_timer_cb, &ts); - - /* timer set by init should return true */ -- g_assert(throttle_timers_are_initialized(&tt)); -+ g_assert(throttle_timers_are_initialized(tt)); - -- throttle_timers_destroy(&tt); -+ throttle_timers_destroy(tt); - } - - static void test_detach_attach(void) - { - /* zero structures */ - memset(&ts, 0, sizeof(ts)); -- memset(&tt, 0, sizeof(tt)); -+ memset(tt, 0, sizeof(*tt)); - - /* init the structure */ - throttle_init(&ts); -- throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL, -+ throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL, - read_timer_cb, write_timer_cb, &ts); - - /* timer set by init should return true */ -- g_assert(throttle_timers_are_initialized(&tt)); -+ g_assert(throttle_timers_are_initialized(tt)); - - /* timer should no longer exist after detaching */ -- throttle_timers_detach_aio_context(&tt); -- g_assert(!throttle_timers_are_initialized(&tt)); -+ throttle_timers_detach_aio_context(tt); -+ g_assert(!throttle_timers_are_initialized(tt)); - - /* timer should exist again after attaching */ -- throttle_timers_attach_aio_context(&tt, ctx); -- g_assert(throttle_timers_are_initialized(&tt)); -+ throttle_timers_attach_aio_context(tt, ctx); -+ g_assert(throttle_timers_are_initialized(tt)); - -- throttle_timers_destroy(&tt); -+ throttle_timers_destroy(tt); - } - - static bool do_test_accounting(bool is_ops, /* are we testing bps or ops */ -@@ -484,7 +487,7 @@ static bool do_test_accounting(bool is_ops, /* are we testing bps or ops */ - cfg.op_size = op_size; - - throttle_init(&ts); -- throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL, -+ throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL, - read_timer_cb, write_timer_cb, &ts); - throttle_config(&ts, QEMU_CLOCK_VIRTUAL, &cfg); - -@@ -511,7 +514,7 @@ static bool do_test_accounting(bool is_ops, /* are we testing bps or ops */ - return false; - } - -- throttle_timers_destroy(&tt); -+ throttle_timers_destroy(tt); - - return true; - } -@@ -611,9 +614,9 @@ static void test_groups(void) - g_assert(tgm2->throttle_state == NULL); - g_assert(tgm3->throttle_state == NULL); - -- throttle_group_register_tgm(tgm1, "bar"); -- throttle_group_register_tgm(tgm2, "foo"); -- throttle_group_register_tgm(tgm3, "bar"); -+ throttle_group_register_tgm(tgm1, "bar", blk_get_aio_context(blk1)); -+ throttle_group_register_tgm(tgm2, "foo", blk_get_aio_context(blk2)); -+ throttle_group_register_tgm(tgm3, "bar", blk_get_aio_context(blk3)); - - g_assert(tgm1->throttle_state != NULL); - g_assert(tgm2->throttle_state != NULL); --- -1.8.3.1 - diff --git a/SOURCES/kvm-block-add-bdrv_co_drain_end-callback.patch b/SOURCES/kvm-block-add-bdrv_co_drain_end-callback.patch deleted file mode 100644 index b7ed7ee..0000000 --- a/SOURCES/kvm-block-add-bdrv_co_drain_end-callback.patch +++ /dev/null @@ -1,209 +0,0 @@ -From 58a794ea48e1a6c6f5711f07e34024c037e4c4b1 Mon Sep 17 00:00:00 2001 -From: Jeffrey Cody -Date: Thu, 30 Nov 2017 22:49:05 +0100 -Subject: [PATCH 01/21] block: add bdrv_co_drain_end callback - -RH-Author: Jeffrey Cody -Message-id: <5493cbaa3bab031054077168340f5aff55b6be2e.1511985875.git.jcody@redhat.com> -Patchwork-id: 78040 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 01/11] block: add bdrv_co_drain_end callback -Bugzilla: 1506531 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: John Snow - -From: Manos Pitsidianakis - -BlockDriverState has a bdrv_co_drain() callback but no equivalent for -the end of the drain. The throttle driver (block/throttle.c) needs a way -to mark the end of the drain in order to toggle io_limits_disabled -correctly, thus bdrv_co_drain_end is needed. - -Signed-off-by: Manos Pitsidianakis -Reviewed-by: Stefan Hajnoczi -Reviewed-by: Fam Zheng -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit 481cad48e5e655746893e001af31c161f4587a02) -Signed-off-by: Jeff Cody -Signed-off-by: Miroslav Rezanina ---- - block/io.c | 48 +++++++++++++++++++++++++++++++++-------------- - include/block/block_int.h | 11 +++++++++-- - 2 files changed, 43 insertions(+), 16 deletions(-) - -diff --git a/block/io.c b/block/io.c -index 2600381..93fb802 100644 ---- a/block/io.c -+++ b/block/io.c -@@ -153,6 +153,7 @@ typedef struct { - Coroutine *co; - BlockDriverState *bs; - bool done; -+ bool begin; - } BdrvCoDrainData; - - static void coroutine_fn bdrv_drain_invoke_entry(void *opaque) -@@ -160,18 +161,23 @@ static void coroutine_fn bdrv_drain_invoke_entry(void *opaque) - BdrvCoDrainData *data = opaque; - BlockDriverState *bs = data->bs; - -- bs->drv->bdrv_co_drain(bs); -+ if (data->begin) { -+ bs->drv->bdrv_co_drain(bs); -+ } else { -+ bs->drv->bdrv_co_drain_end(bs); -+ } - - /* Set data->done before reading bs->wakeup. */ - atomic_mb_set(&data->done, true); - bdrv_wakeup(bs); - } - --static void bdrv_drain_invoke(BlockDriverState *bs) -+static void bdrv_drain_invoke(BlockDriverState *bs, bool begin) - { -- BdrvCoDrainData data = { .bs = bs, .done = false }; -+ BdrvCoDrainData data = { .bs = bs, .done = false, .begin = begin}; - -- if (!bs->drv || !bs->drv->bdrv_co_drain) { -+ if (!bs->drv || (begin && !bs->drv->bdrv_co_drain) || -+ (!begin && !bs->drv->bdrv_co_drain_end)) { - return; - } - -@@ -180,15 +186,16 @@ static void bdrv_drain_invoke(BlockDriverState *bs) - BDRV_POLL_WHILE(bs, !data.done); - } - --static bool bdrv_drain_recurse(BlockDriverState *bs) -+static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin) - { - BdrvChild *child, *tmp; - bool waited; - -- waited = BDRV_POLL_WHILE(bs, atomic_read(&bs->in_flight) > 0); -- - /* Ensure any pending metadata writes are submitted to bs->file. */ -- bdrv_drain_invoke(bs); -+ bdrv_drain_invoke(bs, begin); -+ -+ /* Wait for drained requests to finish */ -+ waited = BDRV_POLL_WHILE(bs, atomic_read(&bs->in_flight) > 0); - - QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) { - BlockDriverState *bs = child->bs; -@@ -205,7 +212,7 @@ static bool bdrv_drain_recurse(BlockDriverState *bs) - */ - bdrv_ref(bs); - } -- waited |= bdrv_drain_recurse(bs); -+ waited |= bdrv_drain_recurse(bs, begin); - if (in_main_loop) { - bdrv_unref(bs); - } -@@ -221,12 +228,18 @@ static void bdrv_co_drain_bh_cb(void *opaque) - BlockDriverState *bs = data->bs; - - bdrv_dec_in_flight(bs); -- bdrv_drained_begin(bs); -+ if (data->begin) { -+ bdrv_drained_begin(bs); -+ } else { -+ bdrv_drained_end(bs); -+ } -+ - data->done = true; - aio_co_wake(co); - } - --static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs) -+static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, -+ bool begin) - { - BdrvCoDrainData data; - -@@ -239,6 +252,7 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs) - .co = qemu_coroutine_self(), - .bs = bs, - .done = false, -+ .begin = begin, - }; - bdrv_inc_in_flight(bs); - aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), -@@ -253,7 +267,7 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs) - void bdrv_drained_begin(BlockDriverState *bs) - { - if (qemu_in_coroutine()) { -- bdrv_co_yield_to_drain(bs); -+ bdrv_co_yield_to_drain(bs, true); - return; - } - -@@ -262,17 +276,22 @@ void bdrv_drained_begin(BlockDriverState *bs) - bdrv_parent_drained_begin(bs); - } - -- bdrv_drain_recurse(bs); -+ bdrv_drain_recurse(bs, true); - } - - void bdrv_drained_end(BlockDriverState *bs) - { -+ if (qemu_in_coroutine()) { -+ bdrv_co_yield_to_drain(bs, false); -+ return; -+ } - assert(bs->quiesce_counter > 0); - if (atomic_fetch_dec(&bs->quiesce_counter) > 1) { - return; - } - - bdrv_parent_drained_end(bs); -+ bdrv_drain_recurse(bs, false); - aio_enable_external(bdrv_get_aio_context(bs)); - } - -@@ -350,7 +369,7 @@ void bdrv_drain_all_begin(void) - aio_context_acquire(aio_context); - for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { - if (aio_context == bdrv_get_aio_context(bs)) { -- waited |= bdrv_drain_recurse(bs); -+ waited |= bdrv_drain_recurse(bs, true); - } - } - aio_context_release(aio_context); -@@ -371,6 +390,7 @@ void bdrv_drain_all_end(void) - aio_context_acquire(aio_context); - aio_enable_external(aio_context); - bdrv_parent_drained_end(bs); -+ bdrv_drain_recurse(bs, false); - aio_context_release(aio_context); - } - -diff --git a/include/block/block_int.h b/include/block/block_int.h -index a6faf1b..98d02ba 100644 ---- a/include/block/block_int.h -+++ b/include/block/block_int.h -@@ -320,10 +320,17 @@ struct BlockDriver { - int (*bdrv_probe_geometry)(BlockDriverState *bs, HDGeometry *geo); - - /** -- * Drain and stop any internal sources of requests in the driver, and -- * remain so until next I/O callback (e.g. bdrv_co_writev) is called. -+ * bdrv_co_drain is called if implemented in the beginning of a -+ * drain operation to drain and stop any internal sources of requests in -+ * the driver. -+ * bdrv_co_drain_end is called if implemented at the end of the drain. -+ * -+ * They should be used by the driver to e.g. manage scheduled I/O -+ * requests, or toggle an internal state. After the end of the drain new -+ * requests will continue normally. - */ - void coroutine_fn (*bdrv_co_drain)(BlockDriverState *bs); -+ void coroutine_fn (*bdrv_co_drain_end)(BlockDriverState *bs); - - void (*bdrv_add_child)(BlockDriverState *parent, BlockDriverState *child, - Error **errp); --- -1.8.3.1 - diff --git a/SOURCES/kvm-block-all-I-O-should-be-completed-before-removing-th.patch b/SOURCES/kvm-block-all-I-O-should-be-completed-before-removing-th.patch deleted file mode 100644 index af7c524..0000000 --- a/SOURCES/kvm-block-all-I-O-should-be-completed-before-removing-th.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 18d530eed9ea334b2235a1a7ae5801ee23c57290 Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Fri, 17 Nov 2017 11:19:03 +0100 -Subject: [PATCH 04/15] block: all I/O should be completed before removing - throttle timers. - -RH-Author: Stefan Hajnoczi -Message-id: <20171117111908.8815-5-stefanha@redhat.com> -Patchwork-id: 77738 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 4/9] block: all I/O should be completed before removing throttle timers. -Bugzilla: 1492295 -RH-Acked-by: John Snow -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth - -From: Zhengui - -In blk_remove_bs, all I/O should be completed before removing throttle -timers. If there has inflight I/O, removing throttle timers here will -cause the inflight I/O never return. -This patch add bdrv_drained_begin before throttle_timers_detach_aio_context -to let all I/O completed before removing throttle timers. - -[Moved declaration of bs as suggested by Alberto Garcia -. ---Stefan] - -Signed-off-by: Zhengui -Reviewed-by: Stefan Hajnoczi -Reviewed-by: Alberto Garcia -Message-id: 1508564040-120700-1-git-send-email-lizhengui@huawei.com -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit 632a77354317df32c7ff2d23424f0559c23fee51) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - block/block-backend.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/block/block-backend.c b/block/block-backend.c -index 6826476..bfb3e84 100644 ---- a/block/block-backend.c -+++ b/block/block-backend.c -@@ -655,12 +655,16 @@ BlockBackend *blk_by_public(BlockBackendPublic *public) - */ - void blk_remove_bs(BlockBackend *blk) - { -+ BlockDriverState *bs; - ThrottleTimers *tt; - - notifier_list_notify(&blk->remove_bs_notifiers, blk); - if (blk->public.throttle_group_member.throttle_state) { - tt = &blk->public.throttle_group_member.throttle_timers; -+ bs = blk_bs(blk); -+ bdrv_drained_begin(bs); - throttle_timers_detach_aio_context(tt); -+ bdrv_drained_end(bs); - } - - blk_update_root_state(blk); --- -1.8.3.1 - diff --git a/SOURCES/kvm-block-avoid-recursive-AioContext-acquire-in-bdrv_ina.patch b/SOURCES/kvm-block-avoid-recursive-AioContext-acquire-in-bdrv_ina.patch deleted file mode 100644 index cb5019d..0000000 --- a/SOURCES/kvm-block-avoid-recursive-AioContext-acquire-in-bdrv_ina.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 14279ae97888ecd51bcf04771d064fa11a3df7a1 Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Wed, 20 Dec 2017 12:29:52 +0100 -Subject: [PATCH 02/42] block: avoid recursive AioContext acquire in - bdrv_inactivate_all() - -RH-Author: Dr. David Alan Gilbert -Message-id: <20171220122952.9799-2-dgilbert@redhat.com> -Patchwork-id: 78418 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 1/1] block: avoid recursive AioContext acquire in bdrv_inactivate_all() -Bugzilla: 1520824 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Laurent Vivier - -From: Paolo Bonzini - -BDRV_POLL_WHILE() does not support recursive AioContext locking. It -only releases the AioContext lock once regardless of how many times the -caller has acquired it. This results in a hang since the IOThread does -not make progress while the AioContext is still locked. - -The following steps trigger the hang: - - $ qemu-system-x86_64 -M accel=kvm -m 1G -cpu host \ - -object iothread,id=iothread0 \ - -device virtio-scsi-pci,iothread=iothread0 \ - -drive if=none,id=drive0,file=test.img,format=raw \ - -device scsi-hd,drive=drive0 \ - -drive if=none,id=drive1,file=test.img,format=raw \ - -device scsi-hd,drive=drive1 - $ qemu-system-x86_64 ...same options... \ - -incoming tcp::1234 - (qemu) migrate tcp:127.0.0.1:1234 - ...hang... - -Tested-by: Stefan Hajnoczi -Signed-off-by: Paolo Bonzini -Reviewed-by: Eric Blake -Message-id: 20171207201320.19284-2-stefanha@redhat.com -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit bd6458e410c1e7d2912357aeb399fe7d8ee9f9a3) -Signed-off-by: Miroslav Rezanina ---- - block.c | 14 +++++++++++--- - 1 file changed, 11 insertions(+), 3 deletions(-) - -diff --git a/block.c b/block.c -index bc8b80b..b5736dd 100644 ---- a/block.c -+++ b/block.c -@@ -4221,9 +4221,15 @@ int bdrv_inactivate_all(void) - BdrvNextIterator it; - int ret = 0; - int pass; -+ GSList *aio_ctxs = NULL, *ctx; - - for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { -- aio_context_acquire(bdrv_get_aio_context(bs)); -+ AioContext *aio_context = bdrv_get_aio_context(bs); -+ -+ if (!g_slist_find(aio_ctxs, aio_context)) { -+ aio_ctxs = g_slist_prepend(aio_ctxs, aio_context); -+ aio_context_acquire(aio_context); -+ } - } - - /* We do two passes of inactivation. The first pass calls to drivers' -@@ -4240,9 +4246,11 @@ int bdrv_inactivate_all(void) - } - - out: -- for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { -- aio_context_release(bdrv_get_aio_context(bs)); -+ for (ctx = aio_ctxs; ctx != NULL; ctx = ctx->next) { -+ AioContext *aio_context = ctx->data; -+ aio_context_release(aio_context); - } -+ g_slist_free(aio_ctxs); - - return ret; - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-block-backend-Add-.drained_poll-callback.patch b/SOURCES/kvm-block-backend-Add-.drained_poll-callback.patch new file mode 100644 index 0000000..99aa032 --- /dev/null +++ b/SOURCES/kvm-block-backend-Add-.drained_poll-callback.patch @@ -0,0 +1,64 @@ +From 79543d4ff66ab2c8f7050e5a5749ea11d1f0c2c0 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:32 +0200 +Subject: [PATCH 41/49] block-backend: Add .drained_poll callback + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-35-kwolf@redhat.com> +Patchwork-id: 82190 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 34/42] block-backend: Add .drained_poll callback +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +A bdrv_drain operation must ensure that all parents are quiesced, this +includes BlockBackends. Otherwise, callbacks called by requests that are +completed on the BDS layer, but not quite yet on the BlockBackend layer +could still create new requests. + +Signed-off-by: Kevin Wolf +Reviewed-by: Fam Zheng +Reviewed-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + block/block-backend.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/block/block-backend.c b/block/block-backend.c +index 2262506..ea85770 100644 +--- a/block/block-backend.c ++++ b/block/block-backend.c +@@ -121,6 +121,7 @@ static void blk_root_inherit_options(int *child_flags, QDict *child_options, + abort(); + } + static void blk_root_drained_begin(BdrvChild *child); ++static bool blk_root_drained_poll(BdrvChild *child); + static void blk_root_drained_end(BdrvChild *child); + + static void blk_root_change_media(BdrvChild *child, bool load); +@@ -294,6 +295,7 @@ static const BdrvChildRole child_root = { + .get_parent_desc = blk_root_get_parent_desc, + + .drained_begin = blk_root_drained_begin, ++ .drained_poll = blk_root_drained_poll, + .drained_end = blk_root_drained_end, + + .activate = blk_root_activate, +@@ -2217,6 +2219,13 @@ static void blk_root_drained_begin(BdrvChild *child) + } + } + ++static bool blk_root_drained_poll(BdrvChild *child) ++{ ++ BlockBackend *blk = child->opaque; ++ assert(blk->quiesce_counter); ++ return !!blk->in_flight; ++} ++ + static void blk_root_drained_end(BdrvChild *child) + { + BlockBackend *blk = child->opaque; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-backend-Add-blk_co_copy_range.patch b/SOURCES/kvm-block-backend-Add-blk_co_copy_range.patch new file mode 100644 index 0000000..97bfced --- /dev/null +++ b/SOURCES/kvm-block-backend-Add-blk_co_copy_range.patch @@ -0,0 +1,70 @@ +From 6f8e77a19dc072d428624f521e35a82a80893d25 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 29 Jun 2018 06:11:49 +0200 +Subject: [PATCH 45/57] block-backend: Add blk_co_copy_range + +RH-Author: Fam Zheng +Message-id: <20180629061153.12687-10-famz@redhat.com> +Patchwork-id: 81161 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v2 09/13] block-backend: Add blk_co_copy_range +Bugzilla: 1482537 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Kevin Wolf + +It's a BlockBackend wrapper of the BDS interface. + +Signed-off-by: Fam Zheng +Reviewed-by: Stefan Hajnoczi +Message-id: 20180601092648.24614-10-famz@redhat.com +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit b5679fa49c9a70efa7bf01f6efad1a65e2349a0b) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/block-backend.c | 18 ++++++++++++++++++ + include/sysemu/block-backend.h | 4 ++++ + 2 files changed, 22 insertions(+) + +diff --git a/block/block-backend.c b/block/block-backend.c +index fd342db..56ae535 100644 +--- a/block/block-backend.c ++++ b/block/block-backend.c +@@ -2236,3 +2236,21 @@ void blk_unregister_buf(BlockBackend *blk, void *host) + { + bdrv_unregister_buf(blk_bs(blk), host); + } ++ ++int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in, ++ BlockBackend *blk_out, int64_t off_out, ++ int bytes, BdrvRequestFlags flags) ++{ ++ int r; ++ r = blk_check_byte_request(blk_in, off_in, bytes); ++ if (r) { ++ return r; ++ } ++ r = blk_check_byte_request(blk_out, off_out, bytes); ++ if (r) { ++ return r; ++ } ++ return bdrv_co_copy_range(blk_in->root, off_in, ++ blk_out->root, off_out, ++ bytes, flags); ++} +diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h +index 92ab624..8d03d49 100644 +--- a/include/sysemu/block-backend.h ++++ b/include/sysemu/block-backend.h +@@ -232,4 +232,8 @@ void blk_set_force_allow_inactivate(BlockBackend *blk); + void blk_register_buf(BlockBackend *blk, void *host, size_t size); + void blk_unregister_buf(BlockBackend *blk, void *host); + ++int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in, ++ BlockBackend *blk_out, int64_t off_out, ++ int bytes, BdrvRequestFlags flags); ++ + #endif +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-backend-Decrease-in_flight-only-after-callback.patch b/SOURCES/kvm-block-backend-Decrease-in_flight-only-after-callback.patch new file mode 100644 index 0000000..6bc4bc9 --- /dev/null +++ b/SOURCES/kvm-block-backend-Decrease-in_flight-only-after-callback.patch @@ -0,0 +1,53 @@ +From 68265b080cec07c5a6ba6b1c6fbd867f4d9cf9ba Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:34 +0200 +Subject: [PATCH 43/49] block-backend: Decrease in_flight only after callback + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-37-kwolf@redhat.com> +Patchwork-id: 82187 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 36/42] block-backend: Decrease in_flight only after callback +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +Request callbacks can do pretty much anything, including operations that +will yield from the coroutine (such as draining the backend). In that +case, a decreased in_flight would be visible to other code and could +lead to a drain completing while the callback hasn't actually completed +yet. + +Signed-off-by: Kevin Wolf +Reviewed-by: Fam Zheng +Reviewed-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + block/block-backend.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/block/block-backend.c b/block/block-backend.c +index 1adf76b..466bc27 100644 +--- a/block/block-backend.c ++++ b/block/block-backend.c +@@ -1341,8 +1341,16 @@ static const AIOCBInfo blk_aio_em_aiocb_info = { + static void blk_aio_complete(BlkAioEmAIOCB *acb) + { + if (acb->has_returned) { +- blk_dec_in_flight(acb->rwco.blk); ++ if (qemu_get_current_aio_context() == qemu_get_aio_context()) { ++ /* If we are in the main thread, the callback is allowed to unref ++ * the BlockBackend, so we have to hold an additional reference */ ++ blk_ref(acb->rwco.blk); ++ } + acb->common.cb(acb->common.opaque, acb->rwco.ret); ++ blk_dec_in_flight(acb->rwco.blk); ++ if (qemu_get_current_aio_context() == qemu_get_aio_context()) { ++ blk_unref(acb->rwco.blk); ++ } + qemu_aio_unref(acb); + } + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-backend-Fix-potential-double-blk_delete.patch b/SOURCES/kvm-block-backend-Fix-potential-double-blk_delete.patch new file mode 100644 index 0000000..effd0f8 --- /dev/null +++ b/SOURCES/kvm-block-backend-Fix-potential-double-blk_delete.patch @@ -0,0 +1,65 @@ +From f006159bba058c873bf8c1a3684ec72f338f2a2c Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:33 +0200 +Subject: [PATCH 42/49] block-backend: Fix potential double blk_delete() + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-36-kwolf@redhat.com> +Patchwork-id: 82186 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 35/42] block-backend: Fix potential double blk_delete() +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +blk_unref() first decreases the refcount of the BlockBackend and calls +blk_delete() if the refcount reaches zero. Requests can still be in +flight at this point, they are only drained during blk_delete(): + +At this point, arbitrary callbacks can run. If any callback takes a +temporary BlockBackend reference, it will first increase the refcount to +1 and then decrease it to 0 again, triggering another blk_delete(). This +will cause a use-after-free crash in the outer blk_delete(). + +Fix it by draining the BlockBackend before decreasing to refcount to 0. +Assert in blk_ref() that it never takes the first refcount (which would +mean that the BlockBackend is already being deleted). + +Signed-off-by: Kevin Wolf +Reviewed-by: Fam Zheng +Reviewed-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + block/block-backend.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/block/block-backend.c b/block/block-backend.c +index ea85770..1adf76b 100644 +--- a/block/block-backend.c ++++ b/block/block-backend.c +@@ -436,6 +436,7 @@ int blk_get_refcnt(BlockBackend *blk) + */ + void blk_ref(BlockBackend *blk) + { ++ assert(blk->refcnt > 0); + blk->refcnt++; + } + +@@ -448,7 +449,13 @@ void blk_unref(BlockBackend *blk) + { + if (blk) { + assert(blk->refcnt > 0); +- if (!--blk->refcnt) { ++ if (blk->refcnt > 1) { ++ blk->refcnt--; ++ } else { ++ blk_drain(blk); ++ /* blk_drain() cannot resurrect blk, nobody held a reference */ ++ assert(blk->refcnt == 1); ++ blk->refcnt = 0; + blk_delete(blk); + } + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-backup-disable-copy-offloading-for-backup.patch b/SOURCES/kvm-block-backup-disable-copy-offloading-for-backup.patch new file mode 100644 index 0000000..64a5fa2 --- /dev/null +++ b/SOURCES/kvm-block-backup-disable-copy-offloading-for-backup.patch @@ -0,0 +1,43 @@ +From 0dff4725df2174ed2715d05793b40663a981633d Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 18 Jul 2018 22:54:53 +0200 +Subject: [PATCH 68/89] block/backup: disable copy offloading for backup + +RH-Author: John Snow +Message-id: <20180718225511.14878-18-jsnow@redhat.com> +Patchwork-id: 81417 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 17/35] block/backup: disable copy offloading for backup +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +Downstream only for 2.12.0; there are several upstream fixes that fix +the copy_range support for block/backup that are in 3.0 that we're not +prepared to backport to 2.12.0. + +For now, then, hardcode block/backup to use the old bounce buffer method +that works without additional caveats. + +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/backup.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/block/backup.c b/block/backup.c +index d26eeb5..adb3cbd 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -727,7 +727,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, + } else { + job->cluster_size = MAX(BACKUP_CLUSTER_SIZE_DEFAULT, bdi.cluster_size); + } +- job->use_copy_range = true; ++ job->use_copy_range = false; + job->copy_range_size = MIN_NON_ZERO(blk_get_max_transfer(job->common.blk), + blk_get_max_transfer(job->target)); + job->copy_range_size = MAX(job->cluster_size, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-backup-fix-fleecing-scheme-use-serialized-writ.patch b/SOURCES/kvm-block-backup-fix-fleecing-scheme-use-serialized-writ.patch new file mode 100644 index 0000000..c4392ca --- /dev/null +++ b/SOURCES/kvm-block-backup-fix-fleecing-scheme-use-serialized-writ.patch @@ -0,0 +1,141 @@ +From 5627c9fb0b86809d42914f1beef9b68226141d4b Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 18 Jul 2018 22:54:58 +0200 +Subject: [PATCH 73/89] block/backup: fix fleecing scheme: use serialized + writes + +RH-Author: John Snow +Message-id: <20180718225511.14878-23-jsnow@redhat.com> +Patchwork-id: 81396 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 22/35] block/backup: fix fleecing scheme: use serialized writes +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Vladimir Sementsov-Ogievskiy + +Fleecing scheme works as follows: we want a kind of temporary snapshot +of active drive A. We create temporary image B, with B->backing = A. +Then we start backup(sync=none) from A to B. From this point, B reads +as point-in-time snapshot of A (A continues to be active drive, +accepting guest IO). + +This scheme needs some additional synchronization between reads from B +and backup COW operations, otherwise, the following situation is +theoretically possible: + +(assume B is qcow2, client is NBD client, reading from B) + +1. client starts reading and take qcow2 mutex in qcow2_co_preadv, and + goes up to l2 table loading (assume cache miss) + +2) guest write => backup COW => qcow2 write => + try to take qcow2 mutex => waiting + +3. l2 table loaded, we see that cluster is UNALLOCATED, go to + "case QCOW2_CLUSTER_UNALLOCATED" and unlock mutex before + bdrv_co_preadv(bs->backing, ...) + +4) aha, mutex unlocked, backup COW continues, and we finally finish + guest write and change cluster in our active disk A + +5. actually, do bdrv_co_preadv(bs->backing, ...) and read + _new updated_ data. + +To avoid this, let's make backup writes serializing, to not intersect +with reads from B. + +Note: we expand range of handled cases from (sync=none and +B->backing = A) to just (A in backing chain of B), to finally allow +safe reading from B during backup for all cases when A in backing chain +of B, i.e. B formally looks like point-in-time snapshot of A. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: Fam Zheng +Signed-off-by: Kevin Wolf +(cherry picked from commit f8d59dfb40bbc6f5aeea57c8aac1e68c1d2454ee) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/backup.c | 20 ++++++++++++++------ + 1 file changed, 14 insertions(+), 6 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index 369155a..4ba1a6a 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -47,6 +47,8 @@ typedef struct BackupBlockJob { + HBitmap *copy_bitmap; + bool use_copy_range; + int64_t copy_range_size; ++ ++ bool serialize_target_writes; + } BackupBlockJob; + + static const BlockJobDriver backup_job_driver; +@@ -102,6 +104,8 @@ static int coroutine_fn backup_cow_with_bounce_buffer(BackupBlockJob *job, + QEMUIOVector qiov; + BlockBackend *blk = job->common.blk; + int nbytes; ++ int read_flags = is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0; ++ int write_flags = job->serialize_target_writes ? BDRV_REQ_SERIALISING : 0; + + hbitmap_reset(job->copy_bitmap, start / job->cluster_size, 1); + nbytes = MIN(job->cluster_size, job->len - start); +@@ -112,8 +116,7 @@ static int coroutine_fn backup_cow_with_bounce_buffer(BackupBlockJob *job, + iov.iov_len = nbytes; + qemu_iovec_init_external(&qiov, &iov, 1); + +- ret = blk_co_preadv(blk, start, qiov.size, &qiov, +- is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0); ++ ret = blk_co_preadv(blk, start, qiov.size, &qiov, read_flags); + if (ret < 0) { + trace_backup_do_cow_read_fail(job, start, ret); + if (error_is_read) { +@@ -124,11 +127,11 @@ static int coroutine_fn backup_cow_with_bounce_buffer(BackupBlockJob *job, + + if (qemu_iovec_is_zero(&qiov)) { + ret = blk_co_pwrite_zeroes(job->target, start, +- qiov.size, BDRV_REQ_MAY_UNMAP); ++ qiov.size, write_flags | BDRV_REQ_MAY_UNMAP); + } else { + ret = blk_co_pwritev(job->target, start, +- qiov.size, &qiov, +- job->compress ? BDRV_REQ_WRITE_COMPRESSED : 0); ++ qiov.size, &qiov, write_flags | ++ (job->compress ? BDRV_REQ_WRITE_COMPRESSED : 0)); + } + if (ret < 0) { + trace_backup_do_cow_write_fail(job, start, ret); +@@ -156,6 +159,8 @@ static int coroutine_fn backup_cow_with_offload(BackupBlockJob *job, + int nr_clusters; + BlockBackend *blk = job->common.blk; + int nbytes; ++ int read_flags = is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0; ++ int write_flags = job->serialize_target_writes ? BDRV_REQ_SERIALISING : 0; + + assert(QEMU_IS_ALIGNED(job->copy_range_size, job->cluster_size)); + nbytes = MIN(job->copy_range_size, end - start); +@@ -163,7 +168,7 @@ static int coroutine_fn backup_cow_with_offload(BackupBlockJob *job, + hbitmap_reset(job->copy_bitmap, start / job->cluster_size, + nr_clusters); + ret = blk_co_copy_range(blk, start, job->target, start, nbytes, +- is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0, 0); ++ read_flags, write_flags); + if (ret < 0) { + trace_backup_do_cow_copy_range_fail(job, start, ret); + hbitmap_set(job->copy_bitmap, start / job->cluster_size, +@@ -701,6 +706,9 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, + sync_bitmap : NULL; + job->compress = compress; + ++ /* Detect image-fleecing (and similar) schemes */ ++ job->serialize_target_writes = bdrv_chain_contains(target, bs); ++ + /* If there is no backing file on the target, we cannot rely on COW if our + * backup cluster size is smaller than the target cluster size. Even for + * targets with a backing file, try to avoid COW if possible. */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-backup-make-function-variables-consistently-na.patch b/SOURCES/kvm-block-backup-make-function-variables-consistently-na.patch new file mode 100644 index 0000000..cfbfc2b --- /dev/null +++ b/SOURCES/kvm-block-backup-make-function-variables-consistently-na.patch @@ -0,0 +1,166 @@ +From d829a781a2832a72264ade11062dad0e5ef578da Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 10 Sep 2018 18:17:45 +0200 +Subject: [PATCH 07/25] block/backup: make function variables consistently + named + +RH-Author: John Snow +Message-id: <20180910181803.11781-8-jsnow@redhat.com> +Patchwork-id: 82086 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 07/25] block/backup: make function variables consistently named +Bugzilla: 1626061 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Rename opaque_job to job to be consistent with other job implementations. +Rename 'job', the BackupBlockJob object, to 's' to also be consistent. + +Suggested-by: Eric Blake +Signed-off-by: John Snow +Reviewed-by: Max Reitz +Message-id: 20180830015734.19765-8-jsnow@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit 6870277535493fea31761d8d11ec23add2de0fb0) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/backup.c | 62 +++++++++++++++++++++++++++++----------------------------- + 1 file changed, 31 insertions(+), 31 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index 08a5b74..524e0ff 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -468,59 +468,59 @@ static void backup_incremental_init_copy_bitmap(BackupBlockJob *job) + bdrv_dirty_iter_free(dbi); + } + +-static int coroutine_fn backup_run(Job *opaque_job, Error **errp) ++static int coroutine_fn backup_run(Job *job, Error **errp) + { +- BackupBlockJob *job = container_of(opaque_job, BackupBlockJob, common.job); +- BlockDriverState *bs = blk_bs(job->common.blk); ++ BackupBlockJob *s = container_of(job, BackupBlockJob, common.job); ++ BlockDriverState *bs = blk_bs(s->common.blk); + int64_t offset, nb_clusters; + int ret = 0; + +- QLIST_INIT(&job->inflight_reqs); +- qemu_co_rwlock_init(&job->flush_rwlock); ++ QLIST_INIT(&s->inflight_reqs); ++ qemu_co_rwlock_init(&s->flush_rwlock); + +- nb_clusters = DIV_ROUND_UP(job->len, job->cluster_size); +- job_progress_set_remaining(&job->common.job, job->len); ++ nb_clusters = DIV_ROUND_UP(s->len, s->cluster_size); ++ job_progress_set_remaining(job, s->len); + +- job->copy_bitmap = hbitmap_alloc(nb_clusters, 0); +- if (job->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) { +- backup_incremental_init_copy_bitmap(job); ++ s->copy_bitmap = hbitmap_alloc(nb_clusters, 0); ++ if (s->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) { ++ backup_incremental_init_copy_bitmap(s); + } else { +- hbitmap_set(job->copy_bitmap, 0, nb_clusters); ++ hbitmap_set(s->copy_bitmap, 0, nb_clusters); + } + + +- job->before_write.notify = backup_before_write_notify; +- bdrv_add_before_write_notifier(bs, &job->before_write); ++ s->before_write.notify = backup_before_write_notify; ++ bdrv_add_before_write_notifier(bs, &s->before_write); + +- if (job->sync_mode == MIRROR_SYNC_MODE_NONE) { ++ if (s->sync_mode == MIRROR_SYNC_MODE_NONE) { + /* All bits are set in copy_bitmap to allow any cluster to be copied. + * This does not actually require them to be copied. */ +- while (!job_is_cancelled(&job->common.job)) { ++ while (!job_is_cancelled(job)) { + /* Yield until the job is cancelled. We just let our before_write + * notify callback service CoW requests. */ +- job_yield(&job->common.job); ++ job_yield(job); + } +- } else if (job->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) { +- ret = backup_run_incremental(job); ++ } else if (s->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) { ++ ret = backup_run_incremental(s); + } else { + /* Both FULL and TOP SYNC_MODE's require copying.. */ +- for (offset = 0; offset < job->len; +- offset += job->cluster_size) { ++ for (offset = 0; offset < s->len; ++ offset += s->cluster_size) { + bool error_is_read; + int alloced = 0; + +- if (yield_and_check(job)) { ++ if (yield_and_check(s)) { + break; + } + +- if (job->sync_mode == MIRROR_SYNC_MODE_TOP) { ++ if (s->sync_mode == MIRROR_SYNC_MODE_TOP) { + int i; + int64_t n; + + /* Check to see if these blocks are already in the + * backing file. */ + +- for (i = 0; i < job->cluster_size;) { ++ for (i = 0; i < s->cluster_size;) { + /* bdrv_is_allocated() only returns true/false based + * on the first set of sectors it comes across that + * are are all in the same state. +@@ -529,7 +529,7 @@ static int coroutine_fn backup_run(Job *opaque_job, Error **errp) + * needed but at some point that is always the case. */ + alloced = + bdrv_is_allocated(bs, offset + i, +- job->cluster_size - i, &n); ++ s->cluster_size - i, &n); + i += n; + + if (alloced || n == 0) { +@@ -547,29 +547,29 @@ static int coroutine_fn backup_run(Job *opaque_job, Error **errp) + if (alloced < 0) { + ret = alloced; + } else { +- ret = backup_do_cow(job, offset, job->cluster_size, ++ ret = backup_do_cow(s, offset, s->cluster_size, + &error_is_read, false); + } + if (ret < 0) { + /* Depending on error action, fail now or retry cluster */ + BlockErrorAction action = +- backup_error_action(job, error_is_read, -ret); ++ backup_error_action(s, error_is_read, -ret); + if (action == BLOCK_ERROR_ACTION_REPORT) { + break; + } else { +- offset -= job->cluster_size; ++ offset -= s->cluster_size; + continue; + } + } + } + } + +- notifier_with_return_remove(&job->before_write); ++ notifier_with_return_remove(&s->before_write); + + /* wait until pending backup_do_cow() calls have completed */ +- qemu_co_rwlock_wrlock(&job->flush_rwlock); +- qemu_co_rwlock_unlock(&job->flush_rwlock); +- hbitmap_free(job->copy_bitmap); ++ qemu_co_rwlock_wrlock(&s->flush_rwlock); ++ qemu_co_rwlock_unlock(&s->flush_rwlock); ++ hbitmap_free(s->copy_bitmap); + + return ret; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-backup-qapi-documentation-fixup.patch b/SOURCES/kvm-block-backup-qapi-documentation-fixup.patch new file mode 100644 index 0000000..8600365 --- /dev/null +++ b/SOURCES/kvm-block-backup-qapi-documentation-fixup.patch @@ -0,0 +1,73 @@ +From 74396004eb3705a30023e5206cc46e6b414830be Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 10 Sep 2018 18:18:02 +0200 +Subject: [PATCH 24/25] block/backup: qapi documentation fixup + +RH-Author: John Snow +Message-id: <20180910181803.11781-25-jsnow@redhat.com> +Patchwork-id: 82094 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 24/25] block/backup: qapi documentation fixup +Bugzilla: 1626061 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Fix documentation to match the other jobs amended for 3.1. + +Signed-off-by: John Snow +Reviewed-by: Max Reitz +Message-id: 20180906130225.5118-16-jsnow@redhat.com +Reviewed-by: Jeff Cody +Signed-off-by: Max Reitz +(cherry picked from commit 487e31ee250d0f05a26506107fd17191bbce614a) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + qapi/block-core.json | 18 ++++++++++-------- + 1 file changed, 10 insertions(+), 8 deletions(-) + +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 5526cbc..56937db 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -1255,13 +1255,14 @@ + # a different block device than @device). + # + # @auto-finalize: When false, this job will wait in a PENDING state after it has +-# finished its work, waiting for @block-job-finalize. +-# When true, this job will automatically perform its abort or +-# commit actions. ++# finished its work, waiting for @block-job-finalize before ++# making any block graph changes. ++# When true, this job will automatically ++# perform its abort or commit actions. + # Defaults to true. (Since 2.12) + # + # @auto-dismiss: When false, this job will wait in a CONCLUDED state after it +-# has completed ceased all work, and wait for @block-job-dismiss. ++# has completely ceased all work, and awaits @block-job-dismiss. + # When true, this job will automatically disappear from the query + # list without user intervention. + # Defaults to true. (Since 2.12) +@@ -1310,13 +1311,14 @@ + # a different block device than @device). + # + # @auto-finalize: When false, this job will wait in a PENDING state after it has +-# finished its work, waiting for @block-job-finalize. +-# When true, this job will automatically perform its abort or +-# commit actions. ++# finished its work, waiting for @block-job-finalize before ++# making any block graph changes. ++# When true, this job will automatically ++# perform its abort or commit actions. + # Defaults to true. (Since 2.12) + # + # @auto-dismiss: When false, this job will wait in a CONCLUDED state after it +-# has completed ceased all work, and wait for @block-job-dismiss. ++# has completely ceased all work, and awaits @block-job-dismiss. + # When true, this job will automatically disappear from the query + # list without user intervention. + # Defaults to true. (Since 2.12) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-commit-add-block-job-creation-flags.patch b/SOURCES/kvm-block-commit-add-block-job-creation-flags.patch new file mode 100644 index 0000000..e7fba00 --- /dev/null +++ b/SOURCES/kvm-block-commit-add-block-job-creation-flags.patch @@ -0,0 +1,110 @@ +From a846fdf85ff06e60d1d4f2da8ee26a111011e1f9 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 10 Sep 2018 18:17:48 +0200 +Subject: [PATCH 10/25] block/commit: add block job creation flags + +RH-Author: John Snow +Message-id: <20180910181803.11781-11-jsnow@redhat.com> +Patchwork-id: 82109 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 10/25] block/commit: add block job creation flags +Bugzilla: 1626061 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Add support for taking and passing forward job creation flags. + +Signed-off-by: John Snow +Reviewed-by: Max Reitz +Reviewed-by: Jeff Cody +Message-id: 20180906130225.5118-2-jsnow@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit cbb05aee29ba2c2dbbe8ac913a05bd6e1eff4e8a) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/commit.c | 5 +++-- + blockdev.c | 7 ++++--- + include/block/block_int.h | 5 ++++- + 3 files changed, 11 insertions(+), 6 deletions(-) + +diff --git a/block/commit.c b/block/commit.c +index 25b3cb8..c737664 100644 +--- a/block/commit.c ++++ b/block/commit.c +@@ -254,7 +254,8 @@ static BlockDriver bdrv_commit_top = { + }; + + void commit_start(const char *job_id, BlockDriverState *bs, +- BlockDriverState *base, BlockDriverState *top, int64_t speed, ++ BlockDriverState *base, BlockDriverState *top, ++ int creation_flags, int64_t speed, + BlockdevOnError on_error, const char *backing_file_str, + const char *filter_node_name, Error **errp) + { +@@ -272,7 +273,7 @@ void commit_start(const char *job_id, BlockDriverState *bs, + } + + s = block_job_create(job_id, &commit_job_driver, NULL, bs, 0, BLK_PERM_ALL, +- speed, JOB_DEFAULT, NULL, NULL, errp); ++ speed, creation_flags, NULL, NULL, errp); + if (!s) { + return; + } +diff --git a/blockdev.c b/blockdev.c +index baa7e18..20dbcf5 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -3371,6 +3371,7 @@ void qmp_block_commit(bool has_job_id, const char *job_id, const char *device, + * BlockdevOnError change for blkmirror makes it in + */ + BlockdevOnError on_error = BLOCKDEV_ON_ERROR_REPORT; ++ int job_flags = JOB_DEFAULT; + + if (!has_speed) { + speed = 0; +@@ -3452,15 +3453,15 @@ void qmp_block_commit(bool has_job_id, const char *job_id, const char *device, + goto out; + } + commit_active_start(has_job_id ? job_id : NULL, bs, base_bs, +- JOB_DEFAULT, speed, on_error, ++ job_flags, speed, on_error, + filter_node_name, NULL, NULL, false, &local_err); + } else { + BlockDriverState *overlay_bs = bdrv_find_overlay(bs, top_bs); + if (bdrv_op_is_blocked(overlay_bs, BLOCK_OP_TYPE_COMMIT_TARGET, errp)) { + goto out; + } +- commit_start(has_job_id ? job_id : NULL, bs, base_bs, top_bs, speed, +- on_error, has_backing_file ? backing_file : NULL, ++ commit_start(has_job_id ? job_id : NULL, bs, base_bs, top_bs, job_flags, ++ speed, on_error, has_backing_file ? backing_file : NULL, + filter_node_name, &local_err); + } + if (local_err != NULL) { +diff --git a/include/block/block_int.h b/include/block/block_int.h +index b05cf11..25ad363 100644 +--- a/include/block/block_int.h ++++ b/include/block/block_int.h +@@ -951,6 +951,8 @@ void stream_start(const char *job_id, BlockDriverState *bs, + * @bs: Active block device. + * @top: Top block device to be committed. + * @base: Block device that will be written into, and become the new top. ++ * @creation_flags: Flags that control the behavior of the Job lifetime. ++ * See @BlockJobCreateFlags + * @speed: The maximum speed, in bytes per second, or 0 for unlimited. + * @on_error: The action to take upon error. + * @backing_file_str: String to use as the backing file in @top's overlay +@@ -961,7 +963,8 @@ void stream_start(const char *job_id, BlockDriverState *bs, + * + */ + void commit_start(const char *job_id, BlockDriverState *bs, +- BlockDriverState *base, BlockDriverState *top, int64_t speed, ++ BlockDriverState *base, BlockDriverState *top, ++ int creation_flags, int64_t speed, + BlockdevOnError on_error, const char *backing_file_str, + const char *filter_node_name, Error **errp); + /** +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-commit-refactor-commit-to-use-job-callbacks.patch b/SOURCES/kvm-block-commit-refactor-commit-to-use-job-callbacks.patch new file mode 100644 index 0000000..8a1894f --- /dev/null +++ b/SOURCES/kvm-block-commit-refactor-commit-to-use-job-callbacks.patch @@ -0,0 +1,180 @@ +From c720832a9aa72b4b9a326ea95c46ed1e2cbd5cad Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 10 Sep 2018 18:17:51 +0200 +Subject: [PATCH 13/25] block/commit: refactor commit to use job callbacks + +RH-Author: John Snow +Message-id: <20180910181803.11781-14-jsnow@redhat.com> +Patchwork-id: 82092 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 13/25] block/commit: refactor commit to use job callbacks +Bugzilla: 1626061 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Use the component callbacks; prepare, abort, and clean. + +NB: prepare is only called when the job has not yet failed; +and abort can be called after prepare. + +complete -> prepare -> abort -> clean +complete -> abort -> clean + +During refactor, a potential problem with bdrv_drop_intermediate +was identified, the patched behavior is no worse than the pre-patch +behavior, so leave a FIXME for now to be fixed in a future patch. + +Signed-off-by: John Snow +Reviewed-by: Max Reitz +Message-id: 20180906130225.5118-5-jsnow@redhat.com +Reviewed-by: Jeff Cody +Signed-off-by: Max Reitz +(cherry picked from commit 38ff0656c24ad88fb08af343ad610c9fc4741c58) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/commit.c | 92 ++++++++++++++++++++++++++++++++-------------------------- + 1 file changed, 51 insertions(+), 41 deletions(-) + +diff --git a/block/commit.c b/block/commit.c +index c737664..b387765 100644 +--- a/block/commit.c ++++ b/block/commit.c +@@ -36,6 +36,7 @@ typedef struct CommitBlockJob { + BlockDriverState *commit_top_bs; + BlockBackend *top; + BlockBackend *base; ++ BlockDriverState *base_bs; + BlockdevOnError on_error; + int base_flags; + char *backing_file_str; +@@ -68,61 +69,67 @@ static int coroutine_fn commit_populate(BlockBackend *bs, BlockBackend *base, + return 0; + } + +-static void commit_exit(Job *job) ++static int commit_prepare(Job *job) + { + CommitBlockJob *s = container_of(job, CommitBlockJob, common.job); +- BlockJob *bjob = &s->common; +- BlockDriverState *top = blk_bs(s->top); +- BlockDriverState *base = blk_bs(s->base); +- BlockDriverState *commit_top_bs = s->commit_top_bs; +- bool remove_commit_top_bs = false; +- +- /* Make sure commit_top_bs and top stay around until bdrv_replace_node() */ +- bdrv_ref(top); +- bdrv_ref(commit_top_bs); + + /* Remove base node parent that still uses BLK_PERM_WRITE/RESIZE before + * the normal backing chain can be restored. */ + blk_unref(s->base); ++ s->base = NULL; ++ ++ /* FIXME: bdrv_drop_intermediate treats total failures and partial failures ++ * identically. Further work is needed to disambiguate these cases. */ ++ return bdrv_drop_intermediate(s->commit_top_bs, s->base_bs, ++ s->backing_file_str); ++} + +- if (!job_is_cancelled(job) && job->ret == 0) { +- /* success */ +- job->ret = bdrv_drop_intermediate(s->commit_top_bs, base, +- s->backing_file_str); +- } else { +- /* XXX Can (or should) we somehow keep 'consistent read' blocked even +- * after the failed/cancelled commit job is gone? If we already wrote +- * something to base, the intermediate images aren't valid any more. */ +- remove_commit_top_bs = true; ++static void commit_abort(Job *job) ++{ ++ CommitBlockJob *s = container_of(job, CommitBlockJob, common.job); ++ BlockDriverState *top_bs = blk_bs(s->top); ++ ++ /* Make sure commit_top_bs and top stay around until bdrv_replace_node() */ ++ bdrv_ref(top_bs); ++ bdrv_ref(s->commit_top_bs); ++ ++ if (s->base) { ++ blk_unref(s->base); + } + ++ /* free the blockers on the intermediate nodes so that bdrv_replace_nodes ++ * can succeed */ ++ block_job_remove_all_bdrv(&s->common); ++ ++ /* If bdrv_drop_intermediate() failed (or was not invoked), remove the ++ * commit filter driver from the backing chain now. Do this as the final ++ * step so that the 'consistent read' permission can be granted. ++ * ++ * XXX Can (or should) we somehow keep 'consistent read' blocked even ++ * after the failed/cancelled commit job is gone? If we already wrote ++ * something to base, the intermediate images aren't valid any more. */ ++ bdrv_child_try_set_perm(s->commit_top_bs->backing, 0, BLK_PERM_ALL, ++ &error_abort); ++ bdrv_replace_node(s->commit_top_bs, backing_bs(s->commit_top_bs), ++ &error_abort); ++ ++ bdrv_unref(s->commit_top_bs); ++ bdrv_unref(top_bs); ++} ++ ++static void commit_clean(Job *job) ++{ ++ CommitBlockJob *s = container_of(job, CommitBlockJob, common.job); ++ + /* restore base open flags here if appropriate (e.g., change the base back + * to r/o). These reopens do not need to be atomic, since we won't abort + * even on failure here */ +- if (s->base_flags != bdrv_get_flags(base)) { +- bdrv_reopen(base, s->base_flags, NULL); ++ if (s->base_flags != bdrv_get_flags(s->base_bs)) { ++ bdrv_reopen(s->base_bs, s->base_flags, NULL); + } ++ + g_free(s->backing_file_str); + blk_unref(s->top); +- +- /* If there is more than one reference to the job (e.g. if called from +- * job_finish_sync()), job_completed() won't free it and therefore the +- * blockers on the intermediate nodes remain. This would cause +- * bdrv_set_backing_hd() to fail. */ +- block_job_remove_all_bdrv(bjob); +- +- /* If bdrv_drop_intermediate() didn't already do that, remove the commit +- * filter driver from the backing chain. Do this as the final step so that +- * the 'consistent read' permission can be granted. */ +- if (remove_commit_top_bs) { +- bdrv_child_try_set_perm(commit_top_bs->backing, 0, BLK_PERM_ALL, +- &error_abort); +- bdrv_replace_node(commit_top_bs, backing_bs(commit_top_bs), +- &error_abort); +- } +- +- bdrv_unref(commit_top_bs); +- bdrv_unref(top); + } + + static int coroutine_fn commit_run(Job *job, Error **errp) +@@ -211,7 +218,9 @@ static const BlockJobDriver commit_job_driver = { + .user_resume = block_job_user_resume, + .drain = block_job_drain, + .run = commit_run, +- .exit = commit_exit, ++ .prepare = commit_prepare, ++ .abort = commit_abort, ++ .clean = commit_clean + }, + }; + +@@ -350,6 +359,7 @@ void commit_start(const char *job_id, BlockDriverState *bs, + if (ret < 0) { + goto fail; + } ++ s->base_bs = base; + + /* Required permissions are already taken with block_job_add_bdrv() */ + s->top = blk_new(0, BLK_PERM_ALL); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-commit-utilize-job_exit-shim.patch b/SOURCES/kvm-block-commit-utilize-job_exit-shim.patch new file mode 100644 index 0000000..c426005 --- /dev/null +++ b/SOURCES/kvm-block-commit-utilize-job_exit-shim.patch @@ -0,0 +1,115 @@ +From a0b03467a363f0e6804042925ea1df8ef56f8a46 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 10 Sep 2018 18:17:42 +0200 +Subject: [PATCH 04/25] block/commit: utilize job_exit shim + +RH-Author: John Snow +Message-id: <20180910181803.11781-5-jsnow@redhat.com> +Patchwork-id: 82110 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 04/25] block/commit: utilize job_exit shim +Bugzilla: 1626061 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Change the manual deferment to commit_complete into the implicit +callback to job_exit, renaming commit_complete to commit_exit. + +This conversion does change the timing of when job_completed is +called to after the bdrv_replace_node and bdrv_unref calls, which +could have implications for bjob->blk which will now be put down +after this cleanup. + +Kevin highlights that we did not take any permissions for that backend +at job creation time, so it is safe to reorder these operations. + +Signed-off-by: John Snow +Reviewed-by: Max Reitz +Message-id: 20180830015734.19765-5-jsnow@redhat.com +Reviewed-by: Jeff Cody +Signed-off-by: Max Reitz +(cherry picked from commit f369b48dc4095861223f9bc4329935599e03b1c5) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/commit.c | 22 +++++----------------- + 1 file changed, 5 insertions(+), 17 deletions(-) + +diff --git a/block/commit.c b/block/commit.c +index af7579d..25b3cb8 100644 +--- a/block/commit.c ++++ b/block/commit.c +@@ -68,19 +68,13 @@ static int coroutine_fn commit_populate(BlockBackend *bs, BlockBackend *base, + return 0; + } + +-typedef struct { +- int ret; +-} CommitCompleteData; +- +-static void commit_complete(Job *job, void *opaque) ++static void commit_exit(Job *job) + { + CommitBlockJob *s = container_of(job, CommitBlockJob, common.job); + BlockJob *bjob = &s->common; +- CommitCompleteData *data = opaque; + BlockDriverState *top = blk_bs(s->top); + BlockDriverState *base = blk_bs(s->base); + BlockDriverState *commit_top_bs = s->commit_top_bs; +- int ret = data->ret; + bool remove_commit_top_bs = false; + + /* Make sure commit_top_bs and top stay around until bdrv_replace_node() */ +@@ -91,10 +85,10 @@ static void commit_complete(Job *job, void *opaque) + * the normal backing chain can be restored. */ + blk_unref(s->base); + +- if (!job_is_cancelled(job) && ret == 0) { ++ if (!job_is_cancelled(job) && job->ret == 0) { + /* success */ +- ret = bdrv_drop_intermediate(s->commit_top_bs, base, +- s->backing_file_str); ++ job->ret = bdrv_drop_intermediate(s->commit_top_bs, base, ++ s->backing_file_str); + } else { + /* XXX Can (or should) we somehow keep 'consistent read' blocked even + * after the failed/cancelled commit job is gone? If we already wrote +@@ -117,9 +111,6 @@ static void commit_complete(Job *job, void *opaque) + * bdrv_set_backing_hd() to fail. */ + block_job_remove_all_bdrv(bjob); + +- job_completed(job, ret); +- g_free(data); +- + /* If bdrv_drop_intermediate() didn't already do that, remove the commit + * filter driver from the backing chain. Do this as the final step so that + * the 'consistent read' permission can be granted. */ +@@ -137,7 +128,6 @@ static void commit_complete(Job *job, void *opaque) + static int coroutine_fn commit_run(Job *job, Error **errp) + { + CommitBlockJob *s = container_of(job, CommitBlockJob, common.job); +- CommitCompleteData *data; + int64_t offset; + uint64_t delay_ns = 0; + int ret = 0; +@@ -210,9 +200,6 @@ static int coroutine_fn commit_run(Job *job, Error **errp) + out: + qemu_vfree(buf); + +- data = g_malloc(sizeof(*data)); +- data->ret = ret; +- job_defer_to_main_loop(&s->common.job, commit_complete, data); + return ret; + } + +@@ -224,6 +211,7 @@ static const BlockJobDriver commit_job_driver = { + .user_resume = block_job_user_resume, + .drain = block_job_drain, + .run = commit_run, ++ .exit = commit_exit, + }, + }; + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-create-Make-x-blockdev-create-a-job.patch b/SOURCES/kvm-block-create-Make-x-blockdev-create-a-job.patch new file mode 100644 index 0000000..7946e86 --- /dev/null +++ b/SOURCES/kvm-block-create-Make-x-blockdev-create-a-job.patch @@ -0,0 +1,217 @@ +From 15606cc179623a45cc36fd3a769897678083e804 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:40 +0200 +Subject: [PATCH 71/89] block/create: Make x-blockdev-create a job + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-58-kwolf@redhat.com> +Patchwork-id: 81066 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 57/73] block/create: Make x-blockdev-create a job +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This changes the x-blockdev-create QMP command so that it doesn't block +the monitor and the main loop any more, but starts a background job that +performs the image creation. + +The basic job as implemented here is all that is necessary to make image +creation asynchronous and to provide a QMP interface that can be marked +stable, but it still lacks a few features that jobs usually provide: The +job will ignore pause commands and it doesn't publish more than very +basic progress yet (total-progress is 1 and current-progress advances +from 0 to 1 when the driver callbacks returns). These features can be +added later without breaking compatibility. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +Reviewed-by: Jeff Cody +(cherry picked from commit e5ab4347f9f53495e31fcef5e232c7c6be4a0567) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/create.c | 67 +++++++++++++++++++++++++++++++++--------------- + qapi/block-core.json | 14 ++++++---- + qapi/job.json | 4 ++- + tests/qemu-iotests/group | 14 +++++----- + 4 files changed, 66 insertions(+), 33 deletions(-) + +diff --git a/block/create.c b/block/create.c +index 8bd8a03..1a263e4 100644 +--- a/block/create.c ++++ b/block/create.c +@@ -24,28 +24,51 @@ + + #include "qemu/osdep.h" + #include "block/block_int.h" ++#include "qemu/job.h" + #include "qapi/qapi-commands-block-core.h" ++#include "qapi/qapi-visit-block-core.h" ++#include "qapi/clone-visitor.h" + #include "qapi/error.h" + +-typedef struct BlockdevCreateCo { ++typedef struct BlockdevCreateJob { ++ Job common; + BlockDriver *drv; + BlockdevCreateOptions *opts; + int ret; +- Error **errp; +-} BlockdevCreateCo; ++ Error *err; ++} BlockdevCreateJob; + +-static void coroutine_fn bdrv_co_create_co_entry(void *opaque) ++static void blockdev_create_complete(Job *job, void *opaque) + { +- BlockdevCreateCo *cco = opaque; +- cco->ret = cco->drv->bdrv_co_create(cco->opts, cco->errp); ++ BlockdevCreateJob *s = container_of(job, BlockdevCreateJob, common); ++ ++ job_completed(job, s->ret, s->err); + } + +-void qmp_x_blockdev_create(BlockdevCreateOptions *options, Error **errp) ++static void coroutine_fn blockdev_create_run(void *opaque) + { ++ BlockdevCreateJob *s = opaque; ++ ++ job_progress_set_remaining(&s->common, 1); ++ s->ret = s->drv->bdrv_co_create(s->opts, &s->err); ++ job_progress_update(&s->common, 1); ++ ++ qapi_free_BlockdevCreateOptions(s->opts); ++ job_defer_to_main_loop(&s->common, blockdev_create_complete, NULL); ++} ++ ++static const JobDriver blockdev_create_job_driver = { ++ .instance_size = sizeof(BlockdevCreateJob), ++ .job_type = JOB_TYPE_CREATE, ++ .start = blockdev_create_run, ++}; ++ ++void qmp_x_blockdev_create(const char *job_id, BlockdevCreateOptions *options, ++ Error **errp) ++{ ++ BlockdevCreateJob *s; + const char *fmt = BlockdevDriver_str(options->driver); + BlockDriver *drv = bdrv_find_format(fmt); +- Coroutine *co; +- BlockdevCreateCo cco; + + /* If the driver is in the schema, we know that it exists. But it may not + * be whitelisted. */ +@@ -55,22 +78,24 @@ void qmp_x_blockdev_create(BlockdevCreateOptions *options, Error **errp) + return; + } + +- /* Call callback if it exists */ ++ /* Error out if the driver doesn't support .bdrv_co_create */ + if (!drv->bdrv_co_create) { + error_setg(errp, "Driver does not support blockdev-create"); + return; + } + +- cco = (BlockdevCreateCo) { +- .drv = drv, +- .opts = options, +- .ret = -EINPROGRESS, +- .errp = errp, +- }; +- +- co = qemu_coroutine_create(bdrv_co_create_co_entry, &cco); +- qemu_coroutine_enter(co); +- while (cco.ret == -EINPROGRESS) { +- aio_poll(qemu_get_aio_context(), true); ++ /* Create the block job */ ++ /* TODO Running in the main context. Block drivers need to error out or add ++ * locking when they use a BDS in a different AioContext. */ ++ s = job_create(job_id, &blockdev_create_job_driver, NULL, ++ qemu_get_aio_context(), JOB_DEFAULT | JOB_MANUAL_DISMISS, ++ NULL, NULL, errp); ++ if (!s) { ++ return; + } ++ ++ s->drv = drv, ++ s->opts = QAPI_CLONE(BlockdevCreateOptions, options), ++ ++ job_start(&s->common); + } +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 67e613a..d22d1db 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -4027,14 +4027,18 @@ + ## + # @x-blockdev-create: + # +-# Create an image format on a given node. +-# TODO Replace with something asynchronous (block job?) ++# Starts a job to create an image format on a given node. The job is ++# automatically finalized, but a manual job-dismiss is required. + # +-# Since: 2.12 ++# @job-id: Identifier for the newly created job. ++# ++# @options: Options for the image creation. ++# ++# Since: 3.0 + ## + { 'command': 'x-blockdev-create', +- 'data': 'BlockdevCreateOptions', +- 'boxed': true } ++ 'data': { 'job-id': 'str', ++ 'options': 'BlockdevCreateOptions' } } + + ## + # @blockdev-open-tray: +diff --git a/qapi/job.json b/qapi/job.json +index 970124d..69c1970 100644 +--- a/qapi/job.json ++++ b/qapi/job.json +@@ -17,10 +17,12 @@ + # + # @backup: drive backup job type, see "drive-backup" + # ++# @create: image creation job type, see "x-blockdev-create" (since 3.0) ++# + # Since: 1.7 + ## + { 'enum': 'JobType', +- 'data': ['commit', 'stream', 'mirror', 'backup'] } ++ 'data': ['commit', 'stream', 'mirror', 'backup', 'create'] } + + ## + # @JobStatus: +diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group +index 5c55adc..37ec5f1 100644 +--- a/tests/qemu-iotests/group ++++ b/tests/qemu-iotests/group +@@ -204,14 +204,16 @@ + 203 rw auto + 204 rw auto quick + 205 rw auto quick +-206 rw auto +-207 rw auto ++# TODO The following commented out tests need to be reworked to work ++# with the x-blockdev-create job ++#206 rw auto ++#207 rw auto + 208 rw auto quick + 209 rw auto quick +-210 rw auto +-211 rw auto quick +-212 rw auto quick +-213 rw auto quick ++#210 rw auto ++#211 rw auto quick ++#212 rw auto quick ++#213 rw auto quick + 214 rw auto + 215 rw auto quick + 216 rw auto quick +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-create-Mark-blockdev-create-stable.patch b/SOURCES/kvm-block-create-Mark-blockdev-create-stable.patch new file mode 100644 index 0000000..4fa9fa3 --- /dev/null +++ b/SOURCES/kvm-block-create-Mark-blockdev-create-stable.patch @@ -0,0 +1,969 @@ +From 6d13aa547ffb24311a0cd6f2268d35fd0a272182 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:52 +0200 +Subject: [PATCH 83/89] block/create: Mark blockdev-create stable + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-70-kwolf@redhat.com> +Patchwork-id: 81104 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 69/73] block/create: Mark blockdev-create stable +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +We're ready to declare the blockdev-create job stable. This renames the +corresponding QMP command from x-blockdev-create to blockdev-create. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +Reviewed-by: Jeff Cody +(cherry picked from commit 3fb588a0f2c006122c34e1960a15c87ae2b927eb) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/create.c | 4 ++-- + qapi/block-core.json | 4 ++-- + qapi/job.json | 2 +- + tests/qemu-iotests/206 | 2 +- + tests/qemu-iotests/206.out | 54 +++++++++++++++++++++++----------------------- + tests/qemu-iotests/207 | 2 +- + tests/qemu-iotests/207.out | 18 ++++++++-------- + tests/qemu-iotests/210 | 2 +- + tests/qemu-iotests/210.out | 18 ++++++++-------- + tests/qemu-iotests/211 | 2 +- + tests/qemu-iotests/211.out | 24 ++++++++++----------- + tests/qemu-iotests/212 | 2 +- + tests/qemu-iotests/212.out | 42 ++++++++++++++++++------------------ + tests/qemu-iotests/213 | 2 +- + tests/qemu-iotests/213.out | 44 ++++++++++++++++++------------------- + 15 files changed, 111 insertions(+), 111 deletions(-) + +diff --git a/block/create.c b/block/create.c +index 1a263e4..915cd41 100644 +--- a/block/create.c ++++ b/block/create.c +@@ -63,8 +63,8 @@ static const JobDriver blockdev_create_job_driver = { + .start = blockdev_create_run, + }; + +-void qmp_x_blockdev_create(const char *job_id, BlockdevCreateOptions *options, +- Error **errp) ++void qmp_blockdev_create(const char *job_id, BlockdevCreateOptions *options, ++ Error **errp) + { + BlockdevCreateJob *s; + const char *fmt = BlockdevDriver_str(options->driver); +diff --git a/qapi/block-core.json b/qapi/block-core.json +index d22d1db..0b07e41 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -4025,7 +4025,7 @@ + } } + + ## +-# @x-blockdev-create: ++# @blockdev-create: + # + # Starts a job to create an image format on a given node. The job is + # automatically finalized, but a manual job-dismiss is required. +@@ -4036,7 +4036,7 @@ + # + # Since: 3.0 + ## +-{ 'command': 'x-blockdev-create', ++{ 'command': 'blockdev-create', + 'data': { 'job-id': 'str', + 'options': 'BlockdevCreateOptions' } } + +diff --git a/qapi/job.json b/qapi/job.json +index 69c1970..17d1003 100644 +--- a/qapi/job.json ++++ b/qapi/job.json +@@ -17,7 +17,7 @@ + # + # @backup: drive backup job type, see "drive-backup" + # +-# @create: image creation job type, see "x-blockdev-create" (since 3.0) ++# @create: image creation job type, see "blockdev-create" (since 3.0) + # + # Since: 1.7 + ## +diff --git a/tests/qemu-iotests/206 b/tests/qemu-iotests/206 +index b8cf2e7..128c334 100755 +--- a/tests/qemu-iotests/206 ++++ b/tests/qemu-iotests/206 +@@ -26,7 +26,7 @@ from iotests import imgfmt + iotests.verify_image_format(supported_fmts=['qcow2']) + + def blockdev_create(vm, options): +- result = vm.qmp_log('x-blockdev-create', job_id='job0', options=options) ++ result = vm.qmp_log('blockdev-create', job_id='job0', options=options) + + if 'return' in result: + assert result['return'] == {} +diff --git a/tests/qemu-iotests/206.out b/tests/qemu-iotests/206.out +index 34451a3..789eebe 100644 +--- a/tests/qemu-iotests/206.out ++++ b/tests/qemu-iotests/206.out +@@ -1,13 +1,13 @@ + === Successful image creation (defaults) === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + + {'execute': 'blockdev-add', 'arguments': {'node_name': 'imgfile', 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}} + {u'return': {}} +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'imgfile', 'size': 134217728}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'imgfile', 'size': 134217728}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} +@@ -24,12 +24,12 @@ Format specific information: + + === Successful image creation (inline blockdev-add, explicit defaults) === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'nocow': False, 'preallocation': 'off', 'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'nocow': False, 'preallocation': 'off', 'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 65536, 'refcount-bits': 16, 'version': 'v3', 'preallocation': 'off', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}, 'lazy-refcounts': False, 'driver': 'qcow2', 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 65536, 'refcount-bits': 16, 'version': 'v3', 'preallocation': 'off', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}, 'lazy-refcounts': False, 'driver': 'qcow2', 'size': 67108864}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} +@@ -46,12 +46,12 @@ Format specific information: + + === Successful image creation (v3 non-default options) === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'nocow': True, 'preallocation': 'falloc', 'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'nocow': True, 'preallocation': 'falloc', 'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 2097152, 'refcount-bits': 1, 'version': 'v3', 'preallocation': 'metadata', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}, 'lazy-refcounts': True, 'driver': 'qcow2', 'size': 33554432}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 2097152, 'refcount-bits': 1, 'version': 'v3', 'preallocation': 'metadata', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}, 'lazy-refcounts': True, 'driver': 'qcow2', 'size': 33554432}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} +@@ -68,12 +68,12 @@ Format specific information: + + === Successful image creation (v2 non-default options) === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 512, 'backing-fmt': 'qcow2', 'driver': 'qcow2', 'version': 'v2', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}, 'backing-file': 'TEST_DIR/PID-t.qcow2.base', 'size': 33554432}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 512, 'backing-fmt': 'qcow2', 'driver': 'qcow2', 'version': 'v2', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}, 'backing-file': 'TEST_DIR/PID-t.qcow2.base', 'size': 33554432}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} +@@ -90,7 +90,7 @@ Format specific information: + + === Successful image creation (encrypted) === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'encrypt': {'key-secret': 'keysec0', 'iter-time': 10, 'cipher-mode': 'ctr', 'ivgen-hash-alg': 'md5', 'cipher-alg': 'twofish-128', 'format': 'luks', 'ivgen-alg': 'plain64', 'hash-alg': 'sha1'}, 'driver': 'qcow2', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}, 'size': 33554432}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'encrypt': {'key-secret': 'keysec0', 'iter-time': 10, 'cipher-mode': 'ctr', 'ivgen-hash-alg': 'md5', 'cipher-alg': 'twofish-128', 'format': 'luks', 'ivgen-alg': 'plain64', 'hash-alg': 'sha1'}, 'driver': 'qcow2', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.qcow2'}, 'size': 33554432}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} +@@ -144,111 +144,111 @@ Format specific information: + + === Invalid BlockdevRef === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': "this doesn't exist", 'size': 33554432}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': "this doesn't exist", 'size': 33554432}}} + {u'return': {}} + Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + + === Invalid sizes === +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'node0', 'size': 1234}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'node0', 'size': 1234}}} + {u'return': {}} + Job failed: Image size must be a multiple of 512 bytes + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'node0', 'size': 18446744073709551104L}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'node0', 'size': 18446744073709551104L}}} + {u'return': {}} + Job failed: Could not resize image: Image size cannot be negative + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'node0', 'size': 9223372036854775808L}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'node0', 'size': 9223372036854775808L}}} + {u'return': {}} + Job failed: Could not resize image: Image size cannot be negative + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'node0', 'size': 9223372036854775296}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'qcow2', 'file': 'node0', 'size': 9223372036854775296}}} + {u'return': {}} + Job failed: Could not resize image: Failed to grow the L1 table: File too large + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + + === Invalid version === +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'version': 'v1', 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'version': 'v1', 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} + {u'error': {u'class': u'GenericError', u'desc': u"Invalid parameter 'v1'"}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'lazy-refcounts': True, 'version': 'v2', 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'lazy-refcounts': True, 'version': 'v2', 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} + {u'return': {}} + Job failed: Lazy refcounts only supported with compatibility level 1.1 and above (use version=v3 or greater) + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'refcount-bits': 8, 'version': 'v2', 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'refcount-bits': 8, 'version': 'v2', 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} + {u'return': {}} + Job failed: Different refcount widths than 16 bits require compatibility level 1.1 or above (use version=v3 or greater) + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + + === Invalid backing file options === +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'preallocation': 'full', 'driver': 'qcow2', 'backing-file': '/dev/null', 'file': 'node0', 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'preallocation': 'full', 'driver': 'qcow2', 'backing-file': '/dev/null', 'file': 'node0', 'size': 67108864}}} + {u'return': {}} + Job failed: Backing file and preallocation cannot be used at the same time + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'backing-fmt': 'qcow2', 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'backing-fmt': 'qcow2', 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} + {u'return': {}} + Job failed: Backing format cannot be used without backing file + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + + === Invalid cluster size === +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 1234, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 1234, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} + {u'return': {}} + Job failed: Cluster size must be a power of two between 512 and 2048k + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 128, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 128, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} + {u'return': {}} + Job failed: Cluster size must be a power of two between 512 and 2048k + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 4194304, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 4194304, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} + {u'return': {}} + Job failed: Cluster size must be a power of two between 512 and 2048k + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 0, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 0, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} + {u'return': {}} + Job failed: Cluster size must be a power of two between 512 and 2048k + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 512, 'driver': 'qcow2', 'file': 'node0', 'size': 281474976710656}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 512, 'driver': 'qcow2', 'file': 'node0', 'size': 281474976710656}}} + {u'return': {}} + Job failed: Could not resize image: Failed to grow the L1 table: File too large + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + + === Invalid refcount width === +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'refcount-bits': 128, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'refcount-bits': 128, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} + {u'return': {}} + Job failed: Refcount width must be a power of two and may not exceed 64 bits + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'refcount-bits': 0, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'refcount-bits': 0, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} + {u'return': {}} + Job failed: Refcount width must be a power of two and may not exceed 64 bits + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'refcount-bits': 7, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'refcount-bits': 7, 'driver': 'qcow2', 'file': 'node0', 'size': 67108864}}} + {u'return': {}} + Job failed: Refcount width must be a power of two and may not exceed 64 bits + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +diff --git a/tests/qemu-iotests/207 b/tests/qemu-iotests/207 +index b595c92..444ae23 100755 +--- a/tests/qemu-iotests/207 ++++ b/tests/qemu-iotests/207 +@@ -31,7 +31,7 @@ def filter_hash(msg): + return re.sub("'hash': '[0-9a-f]+'", "'hash': HASH", msg) + + def blockdev_create(vm, options): +- result = vm.qmp_log('x-blockdev-create', job_id='job0', options=options, ++ result = vm.qmp_log('blockdev-create', job_id='job0', options=options, + filters=[iotests.filter_testfiles, filter_hash]) + + if 'return' in result: +diff --git a/tests/qemu-iotests/207.out b/tests/qemu-iotests/207.out +index 5eee17b..078b7e6 100644 +--- a/tests/qemu-iotests/207.out ++++ b/tests/qemu-iotests/207.out +@@ -1,6 +1,6 @@ + === Successful image creation (defaults) === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} +@@ -16,7 +16,7 @@ virtual size: 4.0M (4194304 bytes) + + === Test host-key-check options === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'mode': 'none'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 8388608}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'mode': 'none'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 8388608}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} +@@ -25,7 +25,7 @@ image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.po + file format: IMGFMT + virtual size: 8.0M (8388608 bytes) + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'mode': 'known_hosts'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'mode': 'known_hosts'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} +@@ -34,13 +34,13 @@ image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.po + file format: IMGFMT + virtual size: 4.0M (4194304 bytes) + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': 'wrong', 'type': 'md5', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 2097152}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': 'wrong', 'type': 'md5', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 2097152}}} + {u'return': {}} + Job failed: remote host key does not match host_key_check 'wrong' + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': HASH, 'type': 'md5', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 8388608}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': HASH, 'type': 'md5', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 8388608}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} +@@ -49,13 +49,13 @@ image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.po + file format: IMGFMT + virtual size: 8.0M (8388608 bytes) + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': 'wrong', 'type': 'sha1', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 2097152}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': 'wrong', 'type': 'sha1', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 2097152}}} + {u'return': {}} + Job failed: remote host key does not match host_key_check 'wrong' + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': HASH, 'type': 'sha1', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': HASH, 'type': 'sha1', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} +@@ -66,13 +66,13 @@ virtual size: 4.0M (4194304 bytes) + + === Invalid path and user === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': '/this/is/not/an/existing/path', 'host-key-check': {'mode': 'none'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': '/this/is/not/an/existing/path', 'host-key-check': {'mode': 'none'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}} + {u'return': {}} + Job failed: failed to open remote file '/this/is/not/an/existing/path': Failed opening remote file (libssh2 error code: -31) + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'mode': 'none'}, 'user': 'invalid user', 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'mode': 'none'}, 'user': 'invalid user', 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}} + {u'return': {}} + Job failed: failed to authenticate using publickey authentication and the identities held by your ssh-agent + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +diff --git a/tests/qemu-iotests/210 b/tests/qemu-iotests/210 +index ff4fdde..d142841 100755 +--- a/tests/qemu-iotests/210 ++++ b/tests/qemu-iotests/210 +@@ -27,7 +27,7 @@ iotests.verify_image_format(supported_fmts=['luks']) + iotests.verify_protocol(supported=['file']) + + def blockdev_create(vm, options): +- result = vm.qmp_log('x-blockdev-create', job_id='job0', options=options) ++ result = vm.qmp_log('blockdev-create', job_id='job0', options=options) + + if 'return' in result: + assert result['return'] == {} +diff --git a/tests/qemu-iotests/210.out b/tests/qemu-iotests/210.out +index 0e6e5c0..078ba54 100644 +--- a/tests/qemu-iotests/210.out ++++ b/tests/qemu-iotests/210.out +@@ -1,13 +1,13 @@ + === Successful image creation (defaults) === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.luks'}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.luks'}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + + {'execute': 'blockdev-add', 'arguments': {'node_name': 'imgfile', 'driver': 'file', 'filename': 'TEST_DIR/PID-t.luks'}} + {u'return': {}} +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'iter-time': 10, 'driver': 'luks', 'file': 'imgfile', 'size': 134217728}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'iter-time': 10, 'driver': 'luks', 'file': 'imgfile', 'size': 134217728}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} +@@ -54,12 +54,12 @@ Format specific information: + + === Successful image creation (with non-default options) === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.luks'}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.luks'}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'hash-alg': 'sha1', 'cipher-mode': 'ctr', 'cipher-alg': 'twofish-128', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.luks'}, 'iter-time': 10, 'ivgen-alg': 'plain64', 'ivgen-hash-alg': 'md5', 'driver': 'luks', 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'hash-alg': 'sha1', 'cipher-mode': 'ctr', 'cipher-alg': 'twofish-128', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.luks'}, 'iter-time': 10, 'ivgen-alg': 'plain64', 'ivgen-hash-alg': 'md5', 'driver': 'luks', 'size': 67108864}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} +@@ -106,7 +106,7 @@ Format specific information: + + === Invalid BlockdevRef === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'luks', 'file': "this doesn't exist", 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'luks', 'file': "this doesn't exist", 'size': 67108864}}} + {u'return': {}} + Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +@@ -114,7 +114,7 @@ Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exi + + === Zero size === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'iter-time': 10, 'driver': 'luks', 'file': 'node0', 'size': 0}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'iter-time': 10, 'driver': 'luks', 'file': 'node0', 'size': 0}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} +@@ -161,19 +161,19 @@ Format specific information: + + === Invalid sizes === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'driver': 'luks', 'file': 'node0', 'size': 18446744073709551104L}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'driver': 'luks', 'file': 'node0', 'size': 18446744073709551104L}}} + {u'return': {}} + Job failed: The requested file size is too large + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'driver': 'luks', 'file': 'node0', 'size': 9223372036854775808L}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'driver': 'luks', 'file': 'node0', 'size': 9223372036854775808L}}} + {u'return': {}} + Job failed: The requested file size is too large + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'driver': 'luks', 'file': 'node0', 'size': 9223372036854775296}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'key-secret': 'keysec0', 'driver': 'luks', 'file': 'node0', 'size': 9223372036854775296}}} + {u'return': {}} + Job failed: The requested file size is too large + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +diff --git a/tests/qemu-iotests/211 b/tests/qemu-iotests/211 +index b45f886..7b7985d 100755 +--- a/tests/qemu-iotests/211 ++++ b/tests/qemu-iotests/211 +@@ -27,7 +27,7 @@ iotests.verify_image_format(supported_fmts=['vdi']) + iotests.verify_protocol(supported=['file']) + + def blockdev_create(vm, options): +- result = vm.qmp_log('x-blockdev-create', job_id='job0', options=options) ++ result = vm.qmp_log('blockdev-create', job_id='job0', options=options) + + if 'return' in result: + assert result['return'] == {} +diff --git a/tests/qemu-iotests/211.out b/tests/qemu-iotests/211.out +index 2bf1c4a..6feaea3 100644 +--- a/tests/qemu-iotests/211.out ++++ b/tests/qemu-iotests/211.out +@@ -1,13 +1,13 @@ + === Successful image creation (defaults) === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + + {'execute': 'blockdev-add', 'arguments': {'node_name': 'imgfile', 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}} + {u'return': {}} +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'imgfile', 'size': 134217728}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'imgfile', 'size': 134217728}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} +@@ -21,12 +21,12 @@ cluster_size: 1048576 + + === Successful image creation (explicit defaults) === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'preallocation': 'off', 'driver': 'vdi', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}, 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'preallocation': 'off', 'driver': 'vdi', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}, 'size': 67108864}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} +@@ -40,12 +40,12 @@ cluster_size: 1048576 + + === Successful image creation (with non-default options) === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'preallocation': 'metadata', 'driver': 'vdi', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}, 'size': 33554432}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'preallocation': 'metadata', 'driver': 'vdi', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.vdi'}, 'size': 33554432}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} +@@ -60,7 +60,7 @@ cluster_size: 1048576 + + === Invalid BlockdevRef === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': "this doesn't exist", 'size': 33554432}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': "this doesn't exist", 'size': 33554432}}} + {u'return': {}} + Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +@@ -68,7 +68,7 @@ Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exi + + === Zero size === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 0}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 0}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} +@@ -80,7 +80,7 @@ cluster_size: 1048576 + + === Maximum size === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 562949819203584}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 562949819203584}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} +@@ -92,19 +92,19 @@ cluster_size: 1048576 + + === Invalid sizes === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 18446744073709551104L}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 18446744073709551104L}}} + {u'return': {}} + Job failed: Unsupported VDI image size (size is 0xfffffffffffffe00, max supported is 0x1fffff8000000) + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 9223372036854775808L}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 9223372036854775808L}}} + {u'return': {}} + Job failed: Unsupported VDI image size (size is 0x8000000000000000, max supported is 0x1fffff8000000) + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 562949819203585}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vdi', 'file': 'node0', 'size': 562949819203585}}} + {u'return': {}} + Job failed: Unsupported VDI image size (size is 0x1fffff8000001, max supported is 0x1fffff8000000) + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +diff --git a/tests/qemu-iotests/212 b/tests/qemu-iotests/212 +index 03cf41d..95c8810 100755 +--- a/tests/qemu-iotests/212 ++++ b/tests/qemu-iotests/212 +@@ -27,7 +27,7 @@ iotests.verify_image_format(supported_fmts=['parallels']) + iotests.verify_protocol(supported=['file']) + + def blockdev_create(vm, options): +- result = vm.qmp_log('x-blockdev-create', job_id='job0', options=options) ++ result = vm.qmp_log('blockdev-create', job_id='job0', options=options) + + if 'return' in result: + assert result['return'] == {} +diff --git a/tests/qemu-iotests/212.out b/tests/qemu-iotests/212.out +index 780bc30..9150da7 100644 +--- a/tests/qemu-iotests/212.out ++++ b/tests/qemu-iotests/212.out +@@ -1,13 +1,13 @@ + === Successful image creation (defaults) === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + + {'execute': 'blockdev-add', 'arguments': {'node_name': 'imgfile', 'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}} + {u'return': {}} +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'imgfile', 'size': 134217728}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'imgfile', 'size': 134217728}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} +@@ -18,12 +18,12 @@ virtual size: 128M (134217728 bytes) + + === Successful image creation (explicit defaults) === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 1048576, 'driver': 'parallels', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}, 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 1048576, 'driver': 'parallels', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}, 'size': 67108864}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} +@@ -34,12 +34,12 @@ virtual size: 64M (67108864 bytes) + + === Successful image creation (with non-default options) === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 65536, 'driver': 'parallels', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}, 'size': 33554432}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 65536, 'driver': 'parallels', 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.parallels'}, 'size': 33554432}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} +@@ -50,7 +50,7 @@ virtual size: 32M (33554432 bytes) + + === Invalid BlockdevRef === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': "this doesn't exist", 'size': 33554432}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': "this doesn't exist", 'size': 33554432}}} + {u'return': {}} + Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +@@ -58,7 +58,7 @@ Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exi + + === Zero size === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 0}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 0}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} +@@ -69,7 +69,7 @@ virtual size: 0 (0 bytes) + + === Maximum size === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 4503599627369984}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 4503599627369984}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} +@@ -80,31 +80,31 @@ virtual size: 4096T (4503599627369984 bytes) + + === Invalid sizes === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 1234}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 1234}}} + {u'return': {}} + Job failed: Image size must be a multiple of 512 bytes + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 18446744073709551104L}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 18446744073709551104L}}} + {u'return': {}} + Job failed: Image size is too large for this cluster size + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 9223372036854775808L}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 9223372036854775808L}}} + {u'return': {}} + Job failed: Image size is too large for this cluster size + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 9223372036854775296}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 9223372036854775296}}} + {u'return': {}} + Job failed: Image size is too large for this cluster size + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 4503599627370497}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'parallels', 'file': 'node0', 'size': 4503599627370497}}} + {u'return': {}} + Job failed: Image size is too large for this cluster size + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +@@ -112,43 +112,43 @@ Job failed: Image size is too large for this cluster size + + === Invalid cluster size === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 1234, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 1234, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}} + {u'return': {}} + Job failed: Cluster size must be a multiple of 512 bytes + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 128, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 128, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}} + {u'return': {}} + Job failed: Cluster size must be a multiple of 512 bytes + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 4294967296, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 4294967296, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}} + {u'return': {}} + Job failed: Cluster size is too large + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 9223372036854775808L, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 9223372036854775808L, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}} + {u'return': {}} + Job failed: Cluster size is too large + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 18446744073709551104L, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 18446744073709551104L, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}} + {u'return': {}} + Job failed: Cluster size is too large + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 0, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 0, 'driver': 'parallels', 'file': 'node0', 'size': 67108864}}} + {u'return': {}} + Job failed: Image size is too large for this cluster size + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 512, 'driver': 'parallels', 'file': 'node0', 'size': 281474976710656}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'cluster-size': 512, 'driver': 'parallels', 'file': 'node0', 'size': 281474976710656}}} + {u'return': {}} + Job failed: Image size is too large for this cluster size + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +diff --git a/tests/qemu-iotests/213 b/tests/qemu-iotests/213 +index 29d25bc..4054439 100755 +--- a/tests/qemu-iotests/213 ++++ b/tests/qemu-iotests/213 +@@ -27,7 +27,7 @@ iotests.verify_image_format(supported_fmts=['vhdx']) + iotests.verify_protocol(supported=['file']) + + def blockdev_create(vm, options): +- result = vm.qmp_log('x-blockdev-create', job_id='job0', options=options) ++ result = vm.qmp_log('blockdev-create', job_id='job0', options=options) + + if 'return' in result: + assert result['return'] == {} +diff --git a/tests/qemu-iotests/213.out b/tests/qemu-iotests/213.out +index f18a39a..e1dcd47 100644 +--- a/tests/qemu-iotests/213.out ++++ b/tests/qemu-iotests/213.out +@@ -1,13 +1,13 @@ + === Successful image creation (defaults) === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + + {'execute': 'blockdev-add', 'arguments': {'node_name': 'imgfile', 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}} + {u'return': {}} +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'imgfile', 'size': 134217728}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'imgfile', 'size': 134217728}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} +@@ -19,12 +19,12 @@ cluster_size: 8388608 + + === Successful image creation (explicit defaults) === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'block-size': 8388608, 'driver': 'vhdx', 'subformat': 'dynamic', 'log-size': 1048576, 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}, 'block-state-zero': True, 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'block-size': 8388608, 'driver': 'vhdx', 'subformat': 'dynamic', 'log-size': 1048576, 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}, 'block-state-zero': True, 'size': 67108864}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} +@@ -36,12 +36,12 @@ cluster_size: 8388608 + + === Successful image creation (with non-default options) === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'size': 0, 'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'block-size': 268435456, 'driver': 'vhdx', 'subformat': 'fixed', 'log-size': 8388608, 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}, 'block-state-zero': False, 'size': 33554432}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'block-size': 268435456, 'driver': 'vhdx', 'subformat': 'fixed', 'log-size': 8388608, 'file': {'driver': 'file', 'filename': 'TEST_DIR/PID-t.vhdx'}, 'block-state-zero': False, 'size': 33554432}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} +@@ -53,7 +53,7 @@ cluster_size: 268435456 + + === Invalid BlockdevRef === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': "this doesn't exist", 'size': 33554432}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': "this doesn't exist", 'size': 33554432}}} + {u'return': {}} + Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +@@ -61,7 +61,7 @@ Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exi + + === Zero size === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 0}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 0}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} +@@ -73,7 +73,7 @@ cluster_size: 8388608 + + === Maximum size === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 70368744177664}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 70368744177664}}} + {u'return': {}} + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} +@@ -85,25 +85,25 @@ cluster_size: 67108864 + + === Invalid sizes === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 18446744073709551104L}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 18446744073709551104L}}} + {u'return': {}} + Job failed: Image size too large; max of 64TB + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 9223372036854775808L}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 9223372036854775808L}}} + {u'return': {}} + Job failed: Image size too large; max of 64TB + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 9223372036854775296}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 9223372036854775296}}} + {u'return': {}} + Job failed: Image size too large; max of 64TB + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 70368744177665}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'file': 'node0', 'size': 70368744177665}}} + {u'return': {}} + Job failed: Image size too large; max of 64TB + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +@@ -111,31 +111,31 @@ Job failed: Image size too large; max of 64TB + + === Invalid block size === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 1234567, 'file': 'node0', 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 1234567, 'file': 'node0', 'size': 67108864}}} + {u'return': {}} + Job failed: Block size must be a multiple of 1 MB + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 128, 'file': 'node0', 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 128, 'file': 'node0', 'size': 67108864}}} + {u'return': {}} + Job failed: Block size must be a multiple of 1 MB + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 3145728, 'file': 'node0', 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 3145728, 'file': 'node0', 'size': 67108864}}} + {u'return': {}} + Job failed: Block size must be a power of two + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 536870912, 'file': 'node0', 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 536870912, 'file': 'node0', 'size': 67108864}}} + {u'return': {}} + Job failed: Block size must not exceed 268435456 + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 0, 'file': 'node0', 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'vhdx', 'block-size': 0, 'file': 'node0', 'size': 67108864}}} + {u'return': {}} + Job failed: Block size must be a multiple of 1 MB + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +@@ -143,25 +143,25 @@ Job failed: Block size must be a multiple of 1 MB + + === Invalid log size === + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'log-size': 1234567, 'driver': 'vhdx', 'file': 'node0', 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'log-size': 1234567, 'driver': 'vhdx', 'file': 'node0', 'size': 67108864}}} + {u'return': {}} + Job failed: Log size must be a multiple of 1 MB + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'log-size': 128, 'driver': 'vhdx', 'file': 'node0', 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'log-size': 128, 'driver': 'vhdx', 'file': 'node0', 'size': 67108864}}} + {u'return': {}} + Job failed: Log size must be a multiple of 1 MB + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'log-size': 4294967296, 'driver': 'vhdx', 'file': 'node0', 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'log-size': 4294967296, 'driver': 'vhdx', 'file': 'node0', 'size': 67108864}}} + {u'return': {}} + Job failed: Log size must be smaller than 4 GB + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} + {u'return': {}} + +-{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'log-size': 0, 'driver': 'vhdx', 'file': 'node0', 'size': 67108864}}} ++{'execute': 'blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'log-size': 0, 'driver': 'vhdx', 'file': 'node0', 'size': 67108864}}} + {u'return': {}} + Job failed: Log size must be a multiple of 1 MB + {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-dirty-bitmap-add-bdrv_enable_dirty_bitmap_lock.patch b/SOURCES/kvm-block-dirty-bitmap-add-bdrv_enable_dirty_bitmap_lock.patch new file mode 100644 index 0000000..bc52072 --- /dev/null +++ b/SOURCES/kvm-block-dirty-bitmap-add-bdrv_enable_dirty_bitmap_lock.patch @@ -0,0 +1,72 @@ +From b5c5693d22cda0db33d01c6350d790b59a98c92c Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 18 Jul 2018 22:54:42 +0200 +Subject: [PATCH 57/89] block/dirty-bitmap: add bdrv_enable_dirty_bitmap_locked + +RH-Author: John Snow +Message-id: <20180718225511.14878-7-jsnow@redhat.com> +Patchwork-id: 81405 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 06/35] block/dirty-bitmap: add bdrv_enable_dirty_bitmap_locked +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Vladimir Sementsov-Ogievskiy + +Add _locked version of bdrv_enable_dirty_bitmap, to fix dirty bitmap +migration in the following patch. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-id: 20180625165745.25259-2-vsementsov@virtuozzo.com +Signed-off-by: John Snow +(cherry picked from commit 92bcea40d3aac62853e60426bd109b748d4d1cd2) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 9 +++++++-- + include/block/dirty-bitmap.h | 1 + + 2 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index 4159d39..4d6ae8b 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -250,6 +250,12 @@ int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs, + return 0; + } + ++void bdrv_enable_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap) ++{ ++ assert(!bdrv_dirty_bitmap_frozen(bitmap)); ++ bitmap->disabled = false; ++} ++ + /* Called with BQL taken. */ + void bdrv_dirty_bitmap_enable_successor(BdrvDirtyBitmap *bitmap) + { +@@ -453,8 +459,7 @@ void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap) + void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap) + { + bdrv_dirty_bitmap_lock(bitmap); +- assert(!bdrv_dirty_bitmap_frozen(bitmap)); +- bitmap->disabled = false; ++ bdrv_enable_dirty_bitmap_locked(bitmap); + bdrv_dirty_bitmap_unlock(bitmap); + } + +diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h +index 1e14743..af9ba3c 100644 +--- a/include/block/dirty-bitmap.h ++++ b/include/block/dirty-bitmap.h +@@ -33,6 +33,7 @@ void bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs, + Error **errp); + void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap); + void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap); ++void bdrv_enable_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap); + BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs); + uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs); + uint32_t bdrv_dirty_bitmap_granularity(const BdrvDirtyBitmap *bitmap); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-dirty-bitmap-add-lock-to-bdrv_enable-disable_d.patch b/SOURCES/kvm-block-dirty-bitmap-add-lock-to-bdrv_enable-disable_d.patch new file mode 100644 index 0000000..71aca6a --- /dev/null +++ b/SOURCES/kvm-block-dirty-bitmap-add-lock-to-bdrv_enable-disable_d.patch @@ -0,0 +1,62 @@ +From d47b51e706c36542cf32e754fe9c539aed237aef Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 18 Jul 2018 22:54:37 +0200 +Subject: [PATCH 52/89] block/dirty-bitmap: add lock to + bdrv_enable/disable_dirty_bitmap + +RH-Author: John Snow +Message-id: <20180718225511.14878-2-jsnow@redhat.com> +Patchwork-id: 81426 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 01/35] block/dirty-bitmap: add lock to bdrv_enable/disable_dirty_bitmap +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Vladimir Sementsov-Ogievskiy + +Add locks and remove comments about BQL accordingly to +dirty_bitmap_mutex definition in block_int.h. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: John Snow +Reviewed-by: Jeff Cody +Message-id: 20180606182449.1607-2-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit 8b1402ce80d74dc02802f101a0f6c340462380d1) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index 9671594..5623425 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -442,18 +442,20 @@ void bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs, + } + } + +-/* Called with BQL taken. */ + void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap) + { ++ bdrv_dirty_bitmap_lock(bitmap); + assert(!bdrv_dirty_bitmap_frozen(bitmap)); + bitmap->disabled = true; ++ bdrv_dirty_bitmap_unlock(bitmap); + } + +-/* Called with BQL taken. */ + void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap) + { ++ bdrv_dirty_bitmap_lock(bitmap); + assert(!bdrv_dirty_bitmap_frozen(bitmap)); + bitmap->disabled = false; ++ bdrv_dirty_bitmap_unlock(bitmap); + } + + BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-don-t-add-driver-to-options-when-referring-to-.patch b/SOURCES/kvm-block-don-t-add-driver-to-options-when-referring-to-.patch deleted file mode 100644 index 6659373..0000000 --- a/SOURCES/kvm-block-don-t-add-driver-to-options-when-referring-to-.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 9ffa9f42dd630e01a507905b60cc7f45d8326327 Mon Sep 17 00:00:00 2001 -From: Kevin Wolf -Date: Thu, 30 Nov 2017 16:17:47 +0100 -Subject: [PATCH 08/36] block: don't add 'driver' to options when referring to - backing via node name - -RH-Author: Kevin Wolf -Message-id: <20171130161747.18388-2-kwolf@redhat.com> -Patchwork-id: 78023 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH 1/1] block: don't add 'driver' to options when referring to backing via node name -Bugzilla: 1505701 -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Max Reitz -RH-Acked-by: John Snow - -From: Peter Krempa - -When referring to a backing file of an image via node name -bdrv_open_backing_file would add the 'driver' option to the option list -filling it with the backing format driver. This breaks construction of -the backing chain via -blockdev, as bdrv_open_inherit reports an error -if both 'reference' and 'options' are provided. - -$ qemu-img create -f raw /tmp/backing.raw 64M -$ qemu-img create -f qcow2 -F raw -b /tmp/backing.raw /tmp/test.qcow2 -$ qemu-system-x86_64 \ - -blockdev driver=file,filename=/tmp/backing.raw,node-name=backing \ - -blockdev driver=qcow2,file.driver=file,file.filename=/tmp/test.qcow2,node-name=root,backing=backing -qemu-system-x86_64: -blockdev driver=qcow2,file.driver=file,file.filename=/tmp/test.qcow2,node-name=root,backing=backing: Could not open backing file: Cannot reference an existing block device with additional options or a new filename - -Signed-off-by: Peter Krempa -Signed-off-by: Kevin Wolf -(cherry picked from commit 6bff597bf6580ecc691258e849f652911dbdda7c) -Signed-off-by: Miroslav Rezanina ---- - block.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/block.c b/block.c -index 3308814..6fb4e98 100644 ---- a/block.c -+++ b/block.c -@@ -2178,7 +2178,8 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options, - goto free_exit; - } - -- if (bs->backing_format[0] != '\0' && !qdict_haskey(options, "driver")) { -+ if (!reference && -+ bs->backing_format[0] != '\0' && !qdict_haskey(options, "driver")) { - qdict_put_str(options, "driver", bs->backing_format); - } - --- -1.8.3.1 - diff --git a/SOURCES/kvm-block-don-t-keep-AioContext-acquired-after-blockdev_.patch b/SOURCES/kvm-block-don-t-keep-AioContext-acquired-after-blockdev_.patch deleted file mode 100644 index 327312d..0000000 --- a/SOURCES/kvm-block-don-t-keep-AioContext-acquired-after-blockdev_.patch +++ /dev/null @@ -1,132 +0,0 @@ -From 0caba353a8208065904c8a1c80da8f0a8163bc76 Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Fri, 22 Dec 2017 11:08:52 +0100 -Subject: [PATCH 34/42] block: don't keep AioContext acquired after - blockdev_backup_prepare() - -RH-Author: Stefan Hajnoczi -Message-id: <20171222110900.24813-13-stefanha@redhat.com> -Patchwork-id: 78497 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 12/20] block: don't keep AioContext acquired after blockdev_backup_prepare() -Bugzilla: 1519721 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -Signed-off-by: Stefan Hajnoczi -Reviewed-by: Kevin Wolf -Reviewed-by: Eric Blake -Message-id: 20171206144550.22295-5-stefanha@redhat.com -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit edd5adeecddf665e7954bc146ff458bb30f178ae) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - blockdev.c | 44 ++++++++++++++++++++++++++++++++++---------- - 1 file changed, 34 insertions(+), 10 deletions(-) - -diff --git a/blockdev.c b/blockdev.c -index c962b8a..6efae53 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -1979,7 +1979,6 @@ typedef struct BlockdevBackupState { - BlkActionState common; - BlockDriverState *bs; - BlockJob *job; -- AioContext *aio_context; - } BlockdevBackupState; - - static BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn, -@@ -1990,6 +1989,7 @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp) - BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common); - BlockdevBackup *backup; - BlockDriverState *bs, *target; -+ AioContext *aio_context; - Error *local_err = NULL; - - assert(common->action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP); -@@ -2005,29 +2005,39 @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp) - return; - } - -- /* AioContext is released in .clean() */ -- state->aio_context = bdrv_get_aio_context(bs); -- if (state->aio_context != bdrv_get_aio_context(target)) { -- state->aio_context = NULL; -+ aio_context = bdrv_get_aio_context(bs); -+ if (aio_context != bdrv_get_aio_context(target)) { - error_setg(errp, "Backup between two IO threads is not implemented"); - return; - } -- aio_context_acquire(state->aio_context); -+ aio_context_acquire(aio_context); - state->bs = bs; -+ -+ /* Paired with .clean() */ - bdrv_drained_begin(state->bs); - - state->job = do_blockdev_backup(backup, common->block_job_txn, &local_err); - if (local_err) { - error_propagate(errp, local_err); -- return; -+ goto out; - } -+ -+out: -+ aio_context_release(aio_context); - } - - static void blockdev_backup_commit(BlkActionState *common) - { - BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common); -+ AioContext *aio_context; -+ -+ aio_context = bdrv_get_aio_context(state->bs); -+ aio_context_acquire(aio_context); -+ - assert(state->job); - block_job_start(state->job); -+ -+ aio_context_release(aio_context); - } - - static void blockdev_backup_abort(BlkActionState *common) -@@ -2035,18 +2045,32 @@ static void blockdev_backup_abort(BlkActionState *common) - BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common); - - if (state->job) { -+ AioContext *aio_context; -+ -+ aio_context = bdrv_get_aio_context(state->bs); -+ aio_context_acquire(aio_context); -+ - block_job_cancel_sync(state->job); -+ -+ aio_context_release(aio_context); - } - } - - static void blockdev_backup_clean(BlkActionState *common) - { - BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common); -+ AioContext *aio_context; - -- if (state->aio_context) { -- bdrv_drained_end(state->bs); -- aio_context_release(state->aio_context); -+ if (!state->bs) { -+ return; - } -+ -+ aio_context = bdrv_get_aio_context(state->bs); -+ aio_context_acquire(aio_context); -+ -+ bdrv_drained_end(state->bs); -+ -+ aio_context_release(aio_context); - } - - typedef struct BlockDirtyBitmapState { --- -1.8.3.1 - diff --git a/SOURCES/kvm-block-don-t-keep-AioContext-acquired-after-drive_bac.patch b/SOURCES/kvm-block-don-t-keep-AioContext-acquired-after-drive_bac.patch deleted file mode 100644 index 2359fed..0000000 --- a/SOURCES/kvm-block-don-t-keep-AioContext-acquired-after-drive_bac.patch +++ /dev/null @@ -1,127 +0,0 @@ -From 73e2dea7d9da65e53aa05247324e069de75e0c71 Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Fri, 22 Dec 2017 11:08:51 +0100 -Subject: [PATCH 33/42] block: don't keep AioContext acquired after - drive_backup_prepare() - -RH-Author: Stefan Hajnoczi -Message-id: <20171222110900.24813-12-stefanha@redhat.com> -Patchwork-id: 78493 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 11/20] block: don't keep AioContext acquired after drive_backup_prepare() -Bugzilla: 1519721 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -Signed-off-by: Stefan Hajnoczi -Reviewed-by: Kevin Wolf -Reviewed-by: Eric Blake -Message-id: 20171206144550.22295-4-stefanha@redhat.com -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit 66d56054bca3c1c45861d18ea97f147f7d376d21) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - blockdev.c | 42 ++++++++++++++++++++++++++++++++++-------- - 1 file changed, 34 insertions(+), 8 deletions(-) - -diff --git a/blockdev.c b/blockdev.c -index 8bb23e9..c962b8a 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -1888,7 +1888,6 @@ static void external_snapshot_clean(BlkActionState *common) - typedef struct DriveBackupState { - BlkActionState common; - BlockDriverState *bs; -- AioContext *aio_context; - BlockJob *job; - } DriveBackupState; - -@@ -1900,6 +1899,7 @@ static void drive_backup_prepare(BlkActionState *common, Error **errp) - DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common); - BlockDriverState *bs; - DriveBackup *backup; -+ AioContext *aio_context; - Error *local_err = NULL; - - assert(common->action->type == TRANSACTION_ACTION_KIND_DRIVE_BACKUP); -@@ -1910,24 +1910,36 @@ static void drive_backup_prepare(BlkActionState *common, Error **errp) - return; - } - -- /* AioContext is released in .clean() */ -- state->aio_context = bdrv_get_aio_context(bs); -- aio_context_acquire(state->aio_context); -+ aio_context = bdrv_get_aio_context(bs); -+ aio_context_acquire(aio_context); -+ -+ /* Paired with .clean() */ - bdrv_drained_begin(bs); -+ - state->bs = bs; - - state->job = do_drive_backup(backup, common->block_job_txn, &local_err); - if (local_err) { - error_propagate(errp, local_err); -- return; -+ goto out; - } -+ -+out: -+ aio_context_release(aio_context); - } - - static void drive_backup_commit(BlkActionState *common) - { - DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common); -+ AioContext *aio_context; -+ -+ aio_context = bdrv_get_aio_context(state->bs); -+ aio_context_acquire(aio_context); -+ - assert(state->job); - block_job_start(state->job); -+ -+ aio_context_release(aio_context); - } - - static void drive_backup_abort(BlkActionState *common) -@@ -1935,18 +1947,32 @@ static void drive_backup_abort(BlkActionState *common) - DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common); - - if (state->job) { -+ AioContext *aio_context; -+ -+ aio_context = bdrv_get_aio_context(state->bs); -+ aio_context_acquire(aio_context); -+ - block_job_cancel_sync(state->job); -+ -+ aio_context_release(aio_context); - } - } - - static void drive_backup_clean(BlkActionState *common) - { - DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common); -+ AioContext *aio_context; - -- if (state->aio_context) { -- bdrv_drained_end(state->bs); -- aio_context_release(state->aio_context); -+ if (!state->bs) { -+ return; - } -+ -+ aio_context = bdrv_get_aio_context(state->bs); -+ aio_context_acquire(aio_context); -+ -+ bdrv_drained_end(state->bs); -+ -+ aio_context_release(aio_context); - } - - typedef struct BlockdevBackupState { --- -1.8.3.1 - diff --git a/SOURCES/kvm-block-don-t-keep-AioContext-acquired-after-external_.patch b/SOURCES/kvm-block-don-t-keep-AioContext-acquired-after-external_.patch deleted file mode 100644 index 4c6aab8..0000000 --- a/SOURCES/kvm-block-don-t-keep-AioContext-acquired-after-external_.patch +++ /dev/null @@ -1,246 +0,0 @@ -From 618ad78b4afa654623057234db339c8cbcfb7392 Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Fri, 22 Dec 2017 11:08:50 +0100 -Subject: [PATCH 32/42] block: don't keep AioContext acquired after - external_snapshot_prepare() - -RH-Author: Stefan Hajnoczi -Message-id: <20171222110900.24813-11-stefanha@redhat.com> -Patchwork-id: 78492 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 10/20] block: don't keep AioContext acquired after external_snapshot_prepare() -Bugzilla: 1519721 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -It is not necessary to hold AioContext across transactions anymore since -bdrv_drained_begin/end() is used to keep the nodes quiesced. In fact, -using the AioContext lock for this purpose was always buggy. - -This patch reduces the scope of AioContext locked regions. This is not -just a cleanup but also fixes hangs that occur in BDRV_POLL_WHILE() -because it is unware of recursive locking and does not release the -AioContext the necessary number of times to allow progress to be made. - -Signed-off-by: Stefan Hajnoczi -Reviewed-by: Kevin Wolf -Reviewed-by: Eric Blake -Message-id: 20171206144550.22295-3-stefanha@redhat.com -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit 2d24b60b7747f7bf40fd00b0375b6bd988d4f0d9) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - blockdev.c | 71 ++++++++++++++++++++++++++++++++++++++++++-------------------- - 1 file changed, 48 insertions(+), 23 deletions(-) - -diff --git a/blockdev.c b/blockdev.c -index c6978a5..8bb23e9 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -1649,7 +1649,6 @@ typedef struct ExternalSnapshotState { - BlkActionState common; - BlockDriverState *old_bs; - BlockDriverState *new_bs; -- AioContext *aio_context; - bool overlay_appended; - } ExternalSnapshotState; - -@@ -1669,6 +1668,7 @@ static void external_snapshot_prepare(BlkActionState *common, - ExternalSnapshotState *state = - DO_UPCAST(ExternalSnapshotState, common, common); - TransactionAction *action = common->action; -+ AioContext *aio_context; - - /* 'blockdev-snapshot' and 'blockdev-snapshot-sync' have similar - * purpose but a different set of parameters */ -@@ -1705,31 +1705,32 @@ static void external_snapshot_prepare(BlkActionState *common, - return; - } - -- /* Acquire AioContext now so any threads operating on old_bs stop */ -- state->aio_context = bdrv_get_aio_context(state->old_bs); -- aio_context_acquire(state->aio_context); -+ aio_context = bdrv_get_aio_context(state->old_bs); -+ aio_context_acquire(aio_context); -+ -+ /* Paired with .clean() */ - bdrv_drained_begin(state->old_bs); - - if (!bdrv_is_inserted(state->old_bs)) { - error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device); -- return; -+ goto out; - } - - if (bdrv_op_is_blocked(state->old_bs, - BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT, errp)) { -- return; -+ goto out; - } - - if (!bdrv_is_read_only(state->old_bs)) { - if (bdrv_flush(state->old_bs)) { - error_setg(errp, QERR_IO_ERROR); -- return; -+ goto out; - } - } - - if (!bdrv_is_first_non_filter(state->old_bs)) { - error_setg(errp, QERR_FEATURE_DISABLED, "snapshot"); -- return; -+ goto out; - } - - if (action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC) { -@@ -1741,13 +1742,13 @@ static void external_snapshot_prepare(BlkActionState *common, - - if (node_name && !snapshot_node_name) { - error_setg(errp, "New snapshot node name missing"); -- return; -+ goto out; - } - - if (snapshot_node_name && - bdrv_lookup_bs(snapshot_node_name, snapshot_node_name, NULL)) { - error_setg(errp, "New snapshot node name already in use"); -- return; -+ goto out; - } - - flags = state->old_bs->open_flags; -@@ -1760,7 +1761,7 @@ static void external_snapshot_prepare(BlkActionState *common, - int64_t size = bdrv_getlength(state->old_bs); - if (size < 0) { - error_setg_errno(errp, -size, "bdrv_getlength failed"); -- return; -+ goto out; - } - bdrv_img_create(new_image_file, format, - state->old_bs->filename, -@@ -1768,7 +1769,7 @@ static void external_snapshot_prepare(BlkActionState *common, - NULL, size, flags, false, &local_err); - if (local_err) { - error_propagate(errp, local_err); -- return; -+ goto out; - } - } - -@@ -1783,30 +1784,30 @@ static void external_snapshot_prepare(BlkActionState *common, - errp); - /* We will manually add the backing_hd field to the bs later */ - if (!state->new_bs) { -- return; -+ goto out; - } - - if (bdrv_has_blk(state->new_bs)) { - error_setg(errp, "The snapshot is already in use"); -- return; -+ goto out; - } - - if (bdrv_op_is_blocked(state->new_bs, BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT, - errp)) { -- return; -+ goto out; - } - - if (state->new_bs->backing != NULL) { - error_setg(errp, "The snapshot already has a backing image"); -- return; -+ goto out; - } - - if (!state->new_bs->drv->supports_backing) { - error_setg(errp, "The snapshot does not support backing images"); -- return; -+ goto out; - } - -- bdrv_set_aio_context(state->new_bs, state->aio_context); -+ bdrv_set_aio_context(state->new_bs, aio_context); - - /* This removes our old bs and adds the new bs. This is an operation that - * can fail, so we need to do it in .prepare; undoing it for abort is -@@ -1815,15 +1816,22 @@ static void external_snapshot_prepare(BlkActionState *common, - bdrv_append(state->new_bs, state->old_bs, &local_err); - if (local_err) { - error_propagate(errp, local_err); -- return; -+ goto out; - } - state->overlay_appended = true; -+ -+out: -+ aio_context_release(aio_context); - } - - static void external_snapshot_commit(BlkActionState *common) - { - ExternalSnapshotState *state = - DO_UPCAST(ExternalSnapshotState, common, common); -+ AioContext *aio_context; -+ -+ aio_context = bdrv_get_aio_context(state->old_bs); -+ aio_context_acquire(aio_context); - - /* We don't need (or want) to use the transactional - * bdrv_reopen_multiple() across all the entries at once, because we -@@ -1832,6 +1840,8 @@ static void external_snapshot_commit(BlkActionState *common) - bdrv_reopen(state->old_bs, state->old_bs->open_flags & ~BDRV_O_RDWR, - NULL); - } -+ -+ aio_context_release(aio_context); - } - - static void external_snapshot_abort(BlkActionState *common) -@@ -1840,11 +1850,18 @@ static void external_snapshot_abort(BlkActionState *common) - DO_UPCAST(ExternalSnapshotState, common, common); - if (state->new_bs) { - if (state->overlay_appended) { -+ AioContext *aio_context; -+ -+ aio_context = bdrv_get_aio_context(state->old_bs); -+ aio_context_acquire(aio_context); -+ - bdrv_ref(state->old_bs); /* we can't let bdrv_set_backind_hd() - close state->old_bs; we need it */ - bdrv_set_backing_hd(state->new_bs, NULL, &error_abort); - bdrv_replace_node(state->new_bs, state->old_bs, &error_abort); - bdrv_unref(state->old_bs); /* bdrv_replace_node() ref'ed old_bs */ -+ -+ aio_context_release(aio_context); - } - } - } -@@ -1853,11 +1870,19 @@ static void external_snapshot_clean(BlkActionState *common) - { - ExternalSnapshotState *state = - DO_UPCAST(ExternalSnapshotState, common, common); -- if (state->aio_context) { -- bdrv_drained_end(state->old_bs); -- bdrv_unref(state->new_bs); -- aio_context_release(state->aio_context); -+ AioContext *aio_context; -+ -+ if (!state->old_bs) { -+ return; - } -+ -+ aio_context = bdrv_get_aio_context(state->old_bs); -+ aio_context_acquire(aio_context); -+ -+ bdrv_drained_end(state->old_bs); -+ bdrv_unref(state->new_bs); -+ -+ aio_context_release(aio_context); - } - - typedef struct DriveBackupState { --- -1.8.3.1 - diff --git a/SOURCES/kvm-block-don-t-keep-AioContext-acquired-after-internal_.patch b/SOURCES/kvm-block-don-t-keep-AioContext-acquired-after-internal_.patch deleted file mode 100644 index fe426a5..0000000 --- a/SOURCES/kvm-block-don-t-keep-AioContext-acquired-after-internal_.patch +++ /dev/null @@ -1,171 +0,0 @@ -From a9ef5c84766a00677204474b0f8d8e845b9d4d3f Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Fri, 22 Dec 2017 11:08:53 +0100 -Subject: [PATCH 35/42] block: don't keep AioContext acquired after - internal_snapshot_prepare() - -RH-Author: Stefan Hajnoczi -Message-id: <20171222110900.24813-14-stefanha@redhat.com> -Patchwork-id: 78499 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 13/20] block: don't keep AioContext acquired after internal_snapshot_prepare() -Bugzilla: 1519721 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -Signed-off-by: Stefan Hajnoczi -Reviewed-by: Kevin Wolf -Reviewed-by: Eric Blake -Message-id: 20171206144550.22295-6-stefanha@redhat.com -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit a36e458cdda0196911c1cbe7cfe6f9530f2280e3) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - blockdev.c | 47 +++++++++++++++++++++++++++++++---------------- - 1 file changed, 31 insertions(+), 16 deletions(-) - -diff --git a/blockdev.c b/blockdev.c -index 6efae53..f118444 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -1497,7 +1497,6 @@ struct BlkActionState { - typedef struct InternalSnapshotState { - BlkActionState common; - BlockDriverState *bs; -- AioContext *aio_context; - QEMUSnapshotInfo sn; - bool created; - } InternalSnapshotState; -@@ -1528,6 +1527,7 @@ static void internal_snapshot_prepare(BlkActionState *common, - qemu_timeval tv; - BlockdevSnapshotInternal *internal; - InternalSnapshotState *state; -+ AioContext *aio_context; - int ret1; - - g_assert(common->action->type == -@@ -1549,32 +1549,33 @@ static void internal_snapshot_prepare(BlkActionState *common, - return; - } - -- /* AioContext is released in .clean() */ -- state->aio_context = bdrv_get_aio_context(bs); -- aio_context_acquire(state->aio_context); -+ aio_context = bdrv_get_aio_context(bs); -+ aio_context_acquire(aio_context); - - state->bs = bs; -+ -+ /* Paired with .clean() */ - bdrv_drained_begin(bs); - - if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT, errp)) { -- return; -+ goto out; - } - - if (bdrv_is_read_only(bs)) { - error_setg(errp, "Device '%s' is read only", device); -- return; -+ goto out; - } - - if (!bdrv_can_snapshot(bs)) { - error_setg(errp, "Block format '%s' used by device '%s' " - "does not support internal snapshots", - bs->drv->format_name, device); -- return; -+ goto out; - } - - if (!strlen(name)) { - error_setg(errp, "Name is empty"); -- return; -+ goto out; - } - - /* check whether a snapshot with name exist */ -@@ -1582,12 +1583,12 @@ static void internal_snapshot_prepare(BlkActionState *common, - &local_err); - if (local_err) { - error_propagate(errp, local_err); -- return; -+ goto out; - } else if (ret) { - error_setg(errp, - "Snapshot with name '%s' already exists on device '%s'", - name, device); -- return; -+ goto out; - } - - /* 3. take the snapshot */ -@@ -1603,11 +1604,14 @@ static void internal_snapshot_prepare(BlkActionState *common, - error_setg_errno(errp, -ret1, - "Failed to create snapshot '%s' on device '%s'", - name, device); -- return; -+ goto out; - } - - /* 4. succeed, mark a snapshot is created */ - state->created = true; -+ -+out: -+ aio_context_release(aio_context); - } - - static void internal_snapshot_abort(BlkActionState *common) -@@ -1616,12 +1620,16 @@ static void internal_snapshot_abort(BlkActionState *common) - DO_UPCAST(InternalSnapshotState, common, common); - BlockDriverState *bs = state->bs; - QEMUSnapshotInfo *sn = &state->sn; -+ AioContext *aio_context; - Error *local_error = NULL; - - if (!state->created) { - return; - } - -+ aio_context = bdrv_get_aio_context(state->bs); -+ aio_context_acquire(aio_context); -+ - if (bdrv_snapshot_delete(bs, sn->id_str, sn->name, &local_error) < 0) { - error_reportf_err(local_error, - "Failed to delete snapshot with id '%s' and " -@@ -1629,19 +1637,26 @@ static void internal_snapshot_abort(BlkActionState *common) - sn->id_str, sn->name, - bdrv_get_device_name(bs)); - } -+ -+ aio_context_release(aio_context); - } - - static void internal_snapshot_clean(BlkActionState *common) - { - InternalSnapshotState *state = DO_UPCAST(InternalSnapshotState, - common, common); -+ AioContext *aio_context; - -- if (state->aio_context) { -- if (state->bs) { -- bdrv_drained_end(state->bs); -- } -- aio_context_release(state->aio_context); -+ if (!state->bs) { -+ return; - } -+ -+ aio_context = bdrv_get_aio_context(state->bs); -+ aio_context_acquire(aio_context); -+ -+ bdrv_drained_end(state->bs); -+ -+ aio_context_release(aio_context); - } - - /* external snapshot private data */ --- -1.8.3.1 - diff --git a/SOURCES/kvm-block-file-posix-File-locking-during-creation.patch b/SOURCES/kvm-block-file-posix-File-locking-during-creation.patch new file mode 100644 index 0000000..e5f9543 --- /dev/null +++ b/SOURCES/kvm-block-file-posix-File-locking-during-creation.patch @@ -0,0 +1,102 @@ +From 8a3d5f5ed54868329ab665e6f2ebe7eb2fcb2055 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 14:53:36 +0200 +Subject: [PATCH 07/57] block/file-posix: File locking during creation + +RH-Author: Max Reitz +Message-id: <20180618145337.633-3-mreitz@redhat.com> +Patchwork-id: 80749 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 2/3] block/file-posix: File locking during creation +Bugzilla: 1519144 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng +RH-Acked-by: Miroslav Rezanina + +When creating a file, we should take the WRITE and RESIZE permissions. +We do not need either for the creation itself, but we do need them for +clearing and resizing it. So we can take the proper permissions by +replacing O_TRUNC with an explicit truncation to 0, and by taking the +appropriate file locks between those two steps. + +Signed-off-by: Max Reitz +Message-id: 20180509215336.31304-3-mreitz@redhat.com +Reviewed-by: Fam Zheng +Signed-off-by: Max Reitz +(cherry picked from commit b8cf1913a989b9ea6f248aaa233330047a62962e) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + block/file-posix.c | 37 +++++++++++++++++++++++++++++++++++-- + 1 file changed, 35 insertions(+), 2 deletions(-) + +diff --git a/block/file-posix.c b/block/file-posix.c +index c98a4a1..370a483 100644 +--- a/block/file-posix.c ++++ b/block/file-posix.c +@@ -1992,6 +1992,7 @@ static int raw_co_create(BlockdevCreateOptions *options, Error **errp) + { + BlockdevCreateOptionsFile *file_opts; + int fd; ++ int perm, shared; + int result = 0; + + /* Validate options and set default values */ +@@ -2006,14 +2007,44 @@ static int raw_co_create(BlockdevCreateOptions *options, Error **errp) + } + + /* Create file */ +- fd = qemu_open(file_opts->filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, +- 0644); ++ fd = qemu_open(file_opts->filename, O_RDWR | O_CREAT | O_BINARY, 0644); + if (fd < 0) { + result = -errno; + error_setg_errno(errp, -result, "Could not create file"); + goto out; + } + ++ /* Take permissions: We want to discard everything, so we need ++ * BLK_PERM_WRITE; and truncation to the desired size requires ++ * BLK_PERM_RESIZE. ++ * On the other hand, we cannot share the RESIZE permission ++ * because we promise that after this function, the file has the ++ * size given in the options. If someone else were to resize it ++ * concurrently, we could not guarantee that. ++ * Note that after this function, we can no longer guarantee that ++ * the file is not touched by a third party, so it may be resized ++ * then. */ ++ perm = BLK_PERM_WRITE | BLK_PERM_RESIZE; ++ shared = BLK_PERM_ALL & ~BLK_PERM_RESIZE; ++ ++ /* Step one: Take locks */ ++ result = raw_apply_lock_bytes(fd, perm, shared, false, errp); ++ if (result < 0) { ++ goto out_close; ++ } ++ ++ /* Step two: Check that nobody else has taken conflicting locks */ ++ result = raw_check_lock_bytes(fd, perm, shared, errp); ++ if (result < 0) { ++ goto out_close; ++ } ++ ++ /* Clear the file by truncating it to 0 */ ++ result = raw_regular_truncate(fd, 0, PREALLOC_MODE_OFF, errp); ++ if (result < 0) { ++ goto out_close; ++ } ++ + if (file_opts->nocow) { + #ifdef __linux__ + /* Set NOCOW flag to solve performance issue on fs like btrfs. +@@ -2029,6 +2060,8 @@ static int raw_co_create(BlockdevCreateOptions *options, Error **errp) + #endif + } + ++ /* Resize and potentially preallocate the file to the desired ++ * final size */ + result = raw_regular_truncate(fd, file_opts->size, file_opts->preallocation, + errp); + if (result < 0) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-file-posix-Pass-FD-to-locking-helpers.patch b/SOURCES/kvm-block-file-posix-Pass-FD-to-locking-helpers.patch new file mode 100644 index 0000000..cff8930 --- /dev/null +++ b/SOURCES/kvm-block-file-posix-Pass-FD-to-locking-helpers.patch @@ -0,0 +1,141 @@ +From 4667112e87999632688621951ce8c2ec8a0ebb8d Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 14:53:35 +0200 +Subject: [PATCH 06/57] block/file-posix: Pass FD to locking helpers + +RH-Author: Max Reitz +Message-id: <20180618145337.633-2-mreitz@redhat.com> +Patchwork-id: 80751 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 1/3] block/file-posix: Pass FD to locking helpers +Bugzilla: 1519144 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng +RH-Acked-by: Miroslav Rezanina + +raw_apply_lock_bytes() and raw_check_lock_bytes() currently take a +BDRVRawState *, but they only use the lock_fd field. During image +creation, we do not have a BDRVRawState, but we do have an FD; so if we +want to reuse the functions there, we should modify them to receive only +the FD. + +Signed-off-by: Max Reitz +Reviewed-by: Fam Zheng +Message-id: 20180509215336.31304-2-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit d0a96155de099d388f5e1f46277a54bdcfbb0bb2) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + block/file-posix.c | 27 ++++++++++++++------------- + 1 file changed, 14 insertions(+), 13 deletions(-) + +diff --git a/block/file-posix.c b/block/file-posix.c +index 3794c00..c98a4a1 100644 +--- a/block/file-posix.c ++++ b/block/file-posix.c +@@ -630,7 +630,7 @@ typedef enum { + * file; if @unlock == true, also unlock the unneeded bytes. + * @shared_perm_lock_bits is the mask of all permissions that are NOT shared. + */ +-static int raw_apply_lock_bytes(BDRVRawState *s, ++static int raw_apply_lock_bytes(int fd, + uint64_t perm_lock_bits, + uint64_t shared_perm_lock_bits, + bool unlock, Error **errp) +@@ -641,13 +641,13 @@ static int raw_apply_lock_bytes(BDRVRawState *s, + PERM_FOREACH(i) { + int off = RAW_LOCK_PERM_BASE + i; + if (perm_lock_bits & (1ULL << i)) { +- ret = qemu_lock_fd(s->lock_fd, off, 1, false); ++ ret = qemu_lock_fd(fd, off, 1, false); + if (ret) { + error_setg(errp, "Failed to lock byte %d", off); + return ret; + } + } else if (unlock) { +- ret = qemu_unlock_fd(s->lock_fd, off, 1); ++ ret = qemu_unlock_fd(fd, off, 1); + if (ret) { + error_setg(errp, "Failed to unlock byte %d", off); + return ret; +@@ -657,13 +657,13 @@ static int raw_apply_lock_bytes(BDRVRawState *s, + PERM_FOREACH(i) { + int off = RAW_LOCK_SHARED_BASE + i; + if (shared_perm_lock_bits & (1ULL << i)) { +- ret = qemu_lock_fd(s->lock_fd, off, 1, false); ++ ret = qemu_lock_fd(fd, off, 1, false); + if (ret) { + error_setg(errp, "Failed to lock byte %d", off); + return ret; + } + } else if (unlock) { +- ret = qemu_unlock_fd(s->lock_fd, off, 1); ++ ret = qemu_unlock_fd(fd, off, 1); + if (ret) { + error_setg(errp, "Failed to unlock byte %d", off); + return ret; +@@ -674,8 +674,7 @@ static int raw_apply_lock_bytes(BDRVRawState *s, + } + + /* Check "unshared" bytes implied by @perm and ~@shared_perm in the file. */ +-static int raw_check_lock_bytes(BDRVRawState *s, +- uint64_t perm, uint64_t shared_perm, ++static int raw_check_lock_bytes(int fd, uint64_t perm, uint64_t shared_perm, + Error **errp) + { + int ret; +@@ -685,7 +684,7 @@ static int raw_check_lock_bytes(BDRVRawState *s, + int off = RAW_LOCK_SHARED_BASE + i; + uint64_t p = 1ULL << i; + if (perm & p) { +- ret = qemu_lock_fd_test(s->lock_fd, off, 1, true); ++ ret = qemu_lock_fd_test(fd, off, 1, true); + if (ret) { + char *perm_name = bdrv_perm_names(p); + error_setg(errp, +@@ -702,7 +701,7 @@ static int raw_check_lock_bytes(BDRVRawState *s, + int off = RAW_LOCK_PERM_BASE + i; + uint64_t p = 1ULL << i; + if (!(shared_perm & p)) { +- ret = qemu_lock_fd_test(s->lock_fd, off, 1, true); ++ ret = qemu_lock_fd_test(fd, off, 1, true); + if (ret) { + char *perm_name = bdrv_perm_names(p); + error_setg(errp, +@@ -739,11 +738,11 @@ static int raw_handle_perm_lock(BlockDriverState *bs, + + switch (op) { + case RAW_PL_PREPARE: +- ret = raw_apply_lock_bytes(s, s->perm | new_perm, ++ ret = raw_apply_lock_bytes(s->lock_fd, s->perm | new_perm, + ~s->shared_perm | ~new_shared, + false, errp); + if (!ret) { +- ret = raw_check_lock_bytes(s, new_perm, new_shared, errp); ++ ret = raw_check_lock_bytes(s->lock_fd, new_perm, new_shared, errp); + if (!ret) { + return 0; + } +@@ -751,7 +750,8 @@ static int raw_handle_perm_lock(BlockDriverState *bs, + op = RAW_PL_ABORT; + /* fall through to unlock bytes. */ + case RAW_PL_ABORT: +- raw_apply_lock_bytes(s, s->perm, ~s->shared_perm, true, &local_err); ++ raw_apply_lock_bytes(s->lock_fd, s->perm, ~s->shared_perm, ++ true, &local_err); + if (local_err) { + /* Theoretically the above call only unlocks bytes and it cannot + * fail. Something weird happened, report it. +@@ -760,7 +760,8 @@ static int raw_handle_perm_lock(BlockDriverState *bs, + } + break; + case RAW_PL_COMMIT: +- raw_apply_lock_bytes(s, new_perm, ~new_shared, true, &local_err); ++ raw_apply_lock_bytes(s->lock_fd, new_perm, ~new_shared, ++ true, &local_err); + if (local_err) { + /* Theoretically the above call only unlocks bytes and it cannot + * fail. Something weird happened, report it. +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-fix-QEMU-crash-with-scsi-hd-and-drive_del.patch b/SOURCES/kvm-block-fix-QEMU-crash-with-scsi-hd-and-drive_del.patch new file mode 100644 index 0000000..88bc661 --- /dev/null +++ b/SOURCES/kvm-block-fix-QEMU-crash-with-scsi-hd-and-drive_del.patch @@ -0,0 +1,90 @@ +From 08e7b4d1dc3f71818fec2ebd5f189142011969a9 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Thu, 12 Jul 2018 16:06:19 +0200 +Subject: [PATCH 41/89] block: fix QEMU crash with scsi-hd and drive_del + +RH-Author: Kevin Wolf +Message-id: <20180712160619.30712-2-kwolf@redhat.com> +Patchwork-id: 81334 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 1/1] block: fix QEMU crash with scsi-hd and drive_del +Bugzilla: 1599515 +RH-Acked-by: Fam Zheng +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi + +From: Greg Kurz + +Removing a drive with drive_del while it is being used to run an I/O +intensive workload can cause QEMU to crash. + +An AIO flush can yield at some point: + +blk_aio_flush_entry() + blk_co_flush(blk) + bdrv_co_flush(blk->root->bs) + ... + qemu_coroutine_yield() + +and let the HMP command to run, free blk->root and give control +back to the AIO flush: + + hmp_drive_del() + blk_remove_bs() + bdrv_root_unref_child(blk->root) + child_bs = blk->root->bs + bdrv_detach_child(blk->root) + bdrv_replace_child(blk->root, NULL) + blk->root->bs = NULL + g_free(blk->root) <============== blk->root becomes stale + bdrv_unref(child_bs) + bdrv_delete(child_bs) + bdrv_close() + bdrv_drained_begin() + bdrv_do_drained_begin() + bdrv_drain_recurse() + aio_poll() + ... + qemu_coroutine_switch() + +and the AIO flush completion ends up dereferencing blk->root: + + blk_aio_complete() + scsi_aio_complete() + blk_get_aio_context(blk) + bs = blk_bs(blk) + ie, bs = blk->root ? blk->root->bs : NULL + ^^^^^ + stale + +The problem is that we should avoid making block driver graph +changes while we have in-flight requests. Let's drain all I/O +for this BB before calling bdrv_root_unref_child(). + +Signed-off-by: Greg Kurz +Signed-off-by: Kevin Wolf +(cherry picked from commit f45280cbf66d8e58224f6a253d0ae2aa72cc6280) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/block-backend.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/block/block-backend.c b/block/block-backend.c +index 56ae535..a469fc6 100644 +--- a/block/block-backend.c ++++ b/block/block-backend.c +@@ -768,6 +768,11 @@ void blk_remove_bs(BlockBackend *blk) + + blk_update_root_state(blk); + ++ /* bdrv_root_unref_child() will cause blk->root to become stale and may ++ * switch to a completion coroutine later on. Let's drain all I/O here ++ * to avoid that and a potential QEMU crash. ++ */ ++ blk_drain(blk); + bdrv_root_unref_child(blk->root); + blk->root = NULL; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-for-jobs-do-not-clear-user_paused-until-after-.patch b/SOURCES/kvm-block-for-jobs-do-not-clear-user_paused-until-after-.patch new file mode 100644 index 0000000..60ac8bb --- /dev/null +++ b/SOURCES/kvm-block-for-jobs-do-not-clear-user_paused-until-after-.patch @@ -0,0 +1,58 @@ +From 9382be6ea4b3785bcc3a4868e1f69348157ba5b1 Mon Sep 17 00:00:00 2001 +From: Jeffrey Cody +Date: Tue, 28 Aug 2018 21:08:16 +0200 +Subject: [PATCH 03/29] block: for jobs, do not clear user_paused until after + the resume + +RH-Author: Jeffrey Cody +Message-id: +Patchwork-id: 81957 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/3] block: for jobs, do not clear user_paused until after the resume +Bugzilla: 1605026 +RH-Acked-by: Max Reitz +RH-Acked-by: John Snow +RH-Acked-by: Miroslav Rezanina + +The function job_cancel_async() will always cause an assert for blockjob +user resume. We set job->user_paused to false, and then call +job->driver->user_resume(). In the case of blockjobs, this is the +block_job_user_resume() function. + +In that function, we assert that job.user_paused is set to true. +Unfortunately, right before calling this function, it has explicitly +been set to false. + +The fix is pretty simple: set job->user_paused to false only after the +job user_resume() function has been called. + +Reviewed-by: John Snow +Reviewed-by: Eric Blake +Signed-off-by: Jeff Cody +Message-id: bb183b77d8f2dd6bd67b8da559a90ac1e74b2052.1534868459.git.jcody@redhat.com +Signed-off-by: Jeff Cody +(cherry picked from commit e321c0597c7590499bacab239d7f86e257f96bcd) +Signed-off-by: Jeff Cody +Signed-off-by: Miroslav Rezanina +--- + job.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/job.c b/job.c +index 84e1402..95dc998 100644 +--- a/job.c ++++ b/job.c +@@ -727,10 +727,10 @@ static void job_cancel_async(Job *job, bool force) + { + if (job->user_paused) { + /* Do not call job_enter here, the caller will handle it. */ +- job->user_paused = false; + if (job->driver->user_resume) { + job->driver->user_resume(job); + } ++ job->user_paused = false; + assert(job->pause_count > 0); + job->pause_count--; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-ignore_bds_parents-parameter-for-drain-functio.patch b/SOURCES/kvm-block-ignore_bds_parents-parameter-for-drain-functio.patch new file mode 100644 index 0000000..2e3eea4 --- /dev/null +++ b/SOURCES/kvm-block-ignore_bds_parents-parameter-for-drain-functio.patch @@ -0,0 +1,481 @@ +From 83fe250c63d9a291267155bae9b86d983062c9d7 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:16 +0200 +Subject: [PATCH 25/49] block: ignore_bds_parents parameter for drain functions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-19-kwolf@redhat.com> +Patchwork-id: 82170 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 18/42] block: ignore_bds_parents parameter for drain functions +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +In the future, bdrv_drained_all_begin/end() will drain all invidiual +nodes separately rather than whole subtrees. This means that we don't +want to propagate the drain to all parents any more: If the parent is a +BDS, it will already be drained separately. Recursing to all parents is +unnecessary work and would make it an O(n²) operation. + +Prepare the drain function for the changed drain_all by adding an +ignore_bds_parents parameter to the internal implementation that +prevents the propagation of the drain to BDS parents. We still (have to) +propagate it to non-BDS parents like BlockBackends or Jobs because those +are not drained separately. + +Signed-off-by: Kevin Wolf +(cherry picked from commit 6cd5c9d7b2df93ef54144f170d4c908934a4767f) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block.c | 11 +++--- + block/io.c | 88 ++++++++++++++++++++++++++++------------------- + block/vvfat.c | 1 + + include/block/block.h | 16 ++++++--- + include/block/block_int.h | 6 ++++ + 5 files changed, 78 insertions(+), 44 deletions(-) + +diff --git a/block.c b/block.c +index 5a50de6..519be6e 100644 +--- a/block.c ++++ b/block.c +@@ -818,13 +818,13 @@ static char *bdrv_child_get_parent_desc(BdrvChild *c) + static void bdrv_child_cb_drained_begin(BdrvChild *child) + { + BlockDriverState *bs = child->opaque; +- bdrv_do_drained_begin_quiesce(bs, NULL); ++ bdrv_do_drained_begin_quiesce(bs, NULL, false); + } + + static bool bdrv_child_cb_drained_poll(BdrvChild *child) + { + BlockDriverState *bs = child->opaque; +- return bdrv_drain_poll(bs, false, NULL); ++ return bdrv_drain_poll(bs, false, NULL, false); + } + + static void bdrv_child_cb_drained_end(BdrvChild *child) +@@ -908,6 +908,7 @@ static void bdrv_inherited_options(int *child_flags, QDict *child_options, + } + + const BdrvChildRole child_file = { ++ .parent_is_bds = true, + .get_parent_desc = bdrv_child_get_parent_desc, + .inherit_options = bdrv_inherited_options, + .drained_begin = bdrv_child_cb_drained_begin, +@@ -933,6 +934,7 @@ static void bdrv_inherited_fmt_options(int *child_flags, QDict *child_options, + } + + const BdrvChildRole child_format = { ++ .parent_is_bds = true, + .get_parent_desc = bdrv_child_get_parent_desc, + .inherit_options = bdrv_inherited_fmt_options, + .drained_begin = bdrv_child_cb_drained_begin, +@@ -1051,6 +1053,7 @@ static int bdrv_backing_update_filename(BdrvChild *c, BlockDriverState *base, + } + + const BdrvChildRole child_backing = { ++ .parent_is_bds = true, + .get_parent_desc = bdrv_child_get_parent_desc, + .attach = bdrv_backing_attach, + .detach = bdrv_backing_detach, +@@ -4901,7 +4904,7 @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context) + AioContext *ctx = bdrv_get_aio_context(bs); + + aio_disable_external(ctx); +- bdrv_parent_drained_begin(bs, NULL); ++ bdrv_parent_drained_begin(bs, NULL, false); + bdrv_drain(bs); /* ensure there are no in-flight requests */ + + while (aio_poll(ctx, false)) { +@@ -4915,7 +4918,7 @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context) + */ + aio_context_acquire(new_context); + bdrv_attach_aio_context(bs, new_context); +- bdrv_parent_drained_end(bs, NULL); ++ bdrv_parent_drained_end(bs, NULL, false); + aio_enable_external(ctx); + aio_context_release(new_context); + } +diff --git a/block/io.c b/block/io.c +index b58c91b..0021fefd 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -41,12 +41,13 @@ + static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, + int64_t offset, int bytes, BdrvRequestFlags flags); + +-void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore) ++void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore, ++ bool ignore_bds_parents) + { + BdrvChild *c, *next; + + QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) { +- if (c == ignore) { ++ if (c == ignore || (ignore_bds_parents && c->role->parent_is_bds)) { + continue; + } + if (c->role->drained_begin) { +@@ -55,12 +56,13 @@ void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore) + } + } + +-void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore) ++void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore, ++ bool ignore_bds_parents) + { + BdrvChild *c, *next; + + QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) { +- if (c == ignore) { ++ if (c == ignore || (ignore_bds_parents && c->role->parent_is_bds)) { + continue; + } + if (c->role->drained_end) { +@@ -69,13 +71,14 @@ void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore) + } + } + +-static bool bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore) ++static bool bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore, ++ bool ignore_bds_parents) + { + BdrvChild *c, *next; + bool busy = false; + + QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) { +- if (c == ignore) { ++ if (c == ignore || (ignore_bds_parents && c->role->parent_is_bds)) { + continue; + } + if (c->role->drained_poll) { +@@ -166,6 +169,7 @@ typedef struct { + bool recursive; + bool poll; + BdrvChild *parent; ++ bool ignore_bds_parents; + } BdrvCoDrainData; + + static void coroutine_fn bdrv_drain_invoke_entry(void *opaque) +@@ -219,11 +223,11 @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin) + + /* Returns true if BDRV_POLL_WHILE() should go into a blocking aio_poll() */ + bool bdrv_drain_poll(BlockDriverState *bs, bool recursive, +- BdrvChild *ignore_parent) ++ BdrvChild *ignore_parent, bool ignore_bds_parents) + { + BdrvChild *child, *next; + +- if (bdrv_parent_drained_poll(bs, ignore_parent)) { ++ if (bdrv_parent_drained_poll(bs, ignore_parent, ignore_bds_parents)) { + return true; + } + +@@ -232,8 +236,9 @@ bool bdrv_drain_poll(BlockDriverState *bs, bool recursive, + } + + if (recursive) { ++ assert(!ignore_bds_parents); + QLIST_FOREACH_SAFE(child, &bs->children, next, next) { +- if (bdrv_drain_poll(child->bs, recursive, child)) { ++ if (bdrv_drain_poll(child->bs, recursive, child, false)) { + return true; + } + } +@@ -249,13 +254,14 @@ static bool bdrv_drain_poll_top_level(BlockDriverState *bs, bool recursive, + * have executed. */ + while (aio_poll(bs->aio_context, false)); + +- return bdrv_drain_poll(bs, recursive, ignore_parent); ++ return bdrv_drain_poll(bs, recursive, ignore_parent, false); + } + + static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, +- BdrvChild *parent, bool poll); ++ BdrvChild *parent, bool ignore_bds_parents, ++ bool poll); + static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive, +- BdrvChild *parent); ++ BdrvChild *parent, bool ignore_bds_parents); + + static void bdrv_co_drain_bh_cb(void *opaque) + { +@@ -266,9 +272,11 @@ static void bdrv_co_drain_bh_cb(void *opaque) + if (bs) { + bdrv_dec_in_flight(bs); + if (data->begin) { +- bdrv_do_drained_begin(bs, data->recursive, data->parent, data->poll); ++ bdrv_do_drained_begin(bs, data->recursive, data->parent, ++ data->ignore_bds_parents, data->poll); + } else { +- bdrv_do_drained_end(bs, data->recursive, data->parent); ++ bdrv_do_drained_end(bs, data->recursive, data->parent, ++ data->ignore_bds_parents); + } + } else { + assert(data->begin); +@@ -281,7 +289,9 @@ static void bdrv_co_drain_bh_cb(void *opaque) + + static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, + bool begin, bool recursive, +- BdrvChild *parent, bool poll) ++ BdrvChild *parent, ++ bool ignore_bds_parents, ++ bool poll) + { + BdrvCoDrainData data; + +@@ -296,6 +306,7 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, + .begin = begin, + .recursive = recursive, + .parent = parent, ++ .ignore_bds_parents = ignore_bds_parents, + .poll = poll, + }; + if (bs) { +@@ -311,7 +322,7 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, + } + + void bdrv_do_drained_begin_quiesce(BlockDriverState *bs, +- BdrvChild *parent) ++ BdrvChild *parent, bool ignore_bds_parents) + { + assert(!qemu_in_coroutine()); + +@@ -320,26 +331,30 @@ void bdrv_do_drained_begin_quiesce(BlockDriverState *bs, + aio_disable_external(bdrv_get_aio_context(bs)); + } + +- bdrv_parent_drained_begin(bs, parent); ++ bdrv_parent_drained_begin(bs, parent, ignore_bds_parents); + bdrv_drain_invoke(bs, true); + } + + static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, +- BdrvChild *parent, bool poll) ++ BdrvChild *parent, bool ignore_bds_parents, ++ bool poll) + { + BdrvChild *child, *next; + + if (qemu_in_coroutine()) { +- bdrv_co_yield_to_drain(bs, true, recursive, parent, poll); ++ bdrv_co_yield_to_drain(bs, true, recursive, parent, ignore_bds_parents, ++ poll); + return; + } + +- bdrv_do_drained_begin_quiesce(bs, parent); ++ bdrv_do_drained_begin_quiesce(bs, parent, ignore_bds_parents); + + if (recursive) { ++ assert(!ignore_bds_parents); + bs->recursive_quiesce_counter++; + QLIST_FOREACH_SAFE(child, &bs->children, next, next) { +- bdrv_do_drained_begin(child->bs, true, child, false); ++ bdrv_do_drained_begin(child->bs, true, child, ignore_bds_parents, ++ false); + } + } + +@@ -353,28 +368,30 @@ static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, + * nodes. + */ + if (poll) { ++ assert(!ignore_bds_parents); + BDRV_POLL_WHILE(bs, bdrv_drain_poll_top_level(bs, recursive, parent)); + } + } + + void bdrv_drained_begin(BlockDriverState *bs) + { +- bdrv_do_drained_begin(bs, false, NULL, true); ++ bdrv_do_drained_begin(bs, false, NULL, false, true); + } + + void bdrv_subtree_drained_begin(BlockDriverState *bs) + { +- bdrv_do_drained_begin(bs, true, NULL, true); ++ bdrv_do_drained_begin(bs, true, NULL, false, true); + } + +-void bdrv_do_drained_end(BlockDriverState *bs, bool recursive, +- BdrvChild *parent) ++static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive, ++ BdrvChild *parent, bool ignore_bds_parents) + { + BdrvChild *child, *next; + int old_quiesce_counter; + + if (qemu_in_coroutine()) { +- bdrv_co_yield_to_drain(bs, false, recursive, parent, false); ++ bdrv_co_yield_to_drain(bs, false, recursive, parent, ignore_bds_parents, ++ false); + return; + } + assert(bs->quiesce_counter > 0); +@@ -382,27 +399,28 @@ void bdrv_do_drained_end(BlockDriverState *bs, bool recursive, + + /* Re-enable things in child-to-parent order */ + bdrv_drain_invoke(bs, false); +- bdrv_parent_drained_end(bs, parent); ++ bdrv_parent_drained_end(bs, parent, ignore_bds_parents); + if (old_quiesce_counter == 1) { + aio_enable_external(bdrv_get_aio_context(bs)); + } + + if (recursive) { ++ assert(!ignore_bds_parents); + bs->recursive_quiesce_counter--; + QLIST_FOREACH_SAFE(child, &bs->children, next, next) { +- bdrv_do_drained_end(child->bs, true, child); ++ bdrv_do_drained_end(child->bs, true, child, ignore_bds_parents); + } + } + } + + void bdrv_drained_end(BlockDriverState *bs) + { +- bdrv_do_drained_end(bs, false, NULL); ++ bdrv_do_drained_end(bs, false, NULL, false); + } + + void bdrv_subtree_drained_end(BlockDriverState *bs) + { +- bdrv_do_drained_end(bs, true, NULL); ++ bdrv_do_drained_end(bs, true, NULL, false); + } + + void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent) +@@ -410,7 +428,7 @@ void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent) + int i; + + for (i = 0; i < new_parent->recursive_quiesce_counter; i++) { +- bdrv_do_drained_begin(child->bs, true, child, true); ++ bdrv_do_drained_begin(child->bs, true, child, false, true); + } + } + +@@ -419,7 +437,7 @@ void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent) + int i; + + for (i = 0; i < old_parent->recursive_quiesce_counter; i++) { +- bdrv_do_drained_end(child->bs, true, child); ++ bdrv_do_drained_end(child->bs, true, child, false); + } + } + +@@ -471,7 +489,7 @@ void bdrv_drain_all_begin(void) + BdrvNextIterator it; + + if (qemu_in_coroutine()) { +- bdrv_co_yield_to_drain(NULL, true, false, NULL, true); ++ bdrv_co_yield_to_drain(NULL, true, false, NULL, false, true); + return; + } + +@@ -485,7 +503,7 @@ void bdrv_drain_all_begin(void) + AioContext *aio_context = bdrv_get_aio_context(bs); + + aio_context_acquire(aio_context); +- bdrv_do_drained_begin(bs, true, NULL, true); ++ bdrv_do_drained_begin(bs, true, NULL, false, true); + aio_context_release(aio_context); + } + +@@ -503,7 +521,7 @@ void bdrv_drain_all_end(void) + AioContext *aio_context = bdrv_get_aio_context(bs); + + aio_context_acquire(aio_context); +- bdrv_do_drained_end(bs, true, NULL); ++ bdrv_do_drained_end(bs, true, NULL, false); + aio_context_release(aio_context); + } + } +diff --git a/block/vvfat.c b/block/vvfat.c +index 4595f33..c7d2ed2 100644 +--- a/block/vvfat.c ++++ b/block/vvfat.c +@@ -3134,6 +3134,7 @@ static void vvfat_qcow_options(int *child_flags, QDict *child_options, + } + + static const BdrvChildRole child_vvfat_qcow = { ++ .parent_is_bds = true, + .inherit_options = vvfat_qcow_options, + }; + +diff --git a/include/block/block.h b/include/block/block.h +index 43f29b5..6e91803 100644 +--- a/include/block/block.h ++++ b/include/block/block.h +@@ -585,7 +585,8 @@ void bdrv_io_unplug(BlockDriverState *bs); + * Begin a quiesced section of all users of @bs. This is part of + * bdrv_drained_begin. + */ +-void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore); ++void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore, ++ bool ignore_bds_parents); + + /** + * bdrv_parent_drained_end: +@@ -593,18 +594,23 @@ void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore); + * End a quiesced section of all users of @bs. This is part of + * bdrv_drained_end. + */ +-void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore); ++void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore, ++ bool ignore_bds_parents); + + /** + * bdrv_drain_poll: + * + * Poll for pending requests in @bs, its parents (except for @ignore_parent), +- * and if @recursive is true its children as well. ++ * and if @recursive is true its children as well (used for subtree drain). ++ * ++ * If @ignore_bds_parents is true, parents that are BlockDriverStates must ++ * ignore the drain request because they will be drained separately (used for ++ * drain_all). + * + * This is part of bdrv_drained_begin. + */ + bool bdrv_drain_poll(BlockDriverState *bs, bool recursive, +- BdrvChild *ignore_parent); ++ BdrvChild *ignore_parent, bool ignore_bds_parents); + + /** + * bdrv_drained_begin: +@@ -625,7 +631,7 @@ void bdrv_drained_begin(BlockDriverState *bs); + * running requests to complete. + */ + void bdrv_do_drained_begin_quiesce(BlockDriverState *bs, +- BdrvChild *parent); ++ BdrvChild *parent, bool ignore_bds_parents); + + /** + * Like bdrv_drained_begin, but recursively begins a quiesced section for +diff --git a/include/block/block_int.h b/include/block/block_int.h +index beeacde..0ad8a76 100644 +--- a/include/block/block_int.h ++++ b/include/block/block_int.h +@@ -582,6 +582,12 @@ struct BdrvChildRole { + * points to. */ + bool stay_at_node; + ++ /* If true, the parent is a BlockDriverState and bdrv_next_all_states() ++ * will return it. This information is used for drain_all, where every node ++ * will be drained separately, so the drain only needs to be propagated to ++ * non-BDS parents. */ ++ bool parent_is_bds; ++ + void (*inherit_options)(int *child_flags, QDict *child_options, + int parent_flags, QDict *parent_options); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-io-fix-copy_range.patch b/SOURCES/kvm-block-io-fix-copy_range.patch new file mode 100644 index 0000000..f411722 --- /dev/null +++ b/SOURCES/kvm-block-io-fix-copy_range.patch @@ -0,0 +1,152 @@ +From 75720bedd9d4ba79f7eff5213f30af5e6c475570 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Tue, 24 Jul 2018 12:59:12 +0200 +Subject: [PATCH 70/89] block/io: fix copy_range + +RH-Author: John Snow +Message-id: <20180718225511.14878-20-jsnow@redhat.com> +Patchwork-id: 81420 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 19/35] block/io: fix copy_range +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Vladimir Sementsov-Ogievskiy + +Here two things are fixed: + +1. Architecture + +On each recursion step, we go to the child of src or dst, only for one +of them. So, it's wrong to create tracked requests for both on each +step. It leads to tracked requests duplication. + +2. Wait for serializing requests on write path independently of + BDRV_REQ_NO_SERIALISING + +Before commit 9ded4a01149 "backup: Use copy offloading", +BDRV_REQ_NO_SERIALISING was used for only one case: read in +copy-on-write operation during backup. Also, the flag was handled only +on read path (in bdrv_co_preadv and bdrv_aligned_preadv). + +After 9ded4a01149, flag is used for not waiting serializing operations +on backup target (in same case of copy-on-write operation). This +behavior change is unsubstantiated and potentially dangerous, let's +drop it and add additional asserts and documentation. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: Fam Zheng +Signed-off-by: Kevin Wolf +(cherry picked from commit 999658a05e61a8d87b65827da665302bb44ce8c9) +Signed-off-by: John Snow +--- + block/io.c | 43 +++++++++++++++++++++++++++---------------- + include/block/block.h | 12 ++++++++++++ + 2 files changed, 39 insertions(+), 16 deletions(-) + +diff --git a/block/io.c b/block/io.c +index b6754f3..f8de42f 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -1505,6 +1505,8 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child, + max_transfer = QEMU_ALIGN_DOWN(MIN_NON_ZERO(bs->bl.max_transfer, INT_MAX), + align); + ++ /* BDRV_REQ_NO_SERIALISING is only for read operation */ ++ assert(!(flags & BDRV_REQ_NO_SERIALISING)); + waited = wait_serialising_requests(req); + assert(!waited || !req->serialising); + assert(req->overlap_offset <= offset); +@@ -2847,7 +2849,7 @@ static int coroutine_fn bdrv_co_copy_range_internal(BdrvChild *src, + BdrvRequestFlags flags, + bool recurse_src) + { +- BdrvTrackedRequest src_req, dst_req; ++ BdrvTrackedRequest req; + int ret; + + if (!dst || !dst->bs) { +@@ -2876,32 +2878,41 @@ static int coroutine_fn bdrv_co_copy_range_internal(BdrvChild *src, + return -ENOTSUP; + } + +- bdrv_inc_in_flight(src->bs); +- bdrv_inc_in_flight(dst->bs); +- tracked_request_begin(&src_req, src->bs, src_offset, +- bytes, BDRV_TRACKED_READ); +- tracked_request_begin(&dst_req, dst->bs, dst_offset, +- bytes, BDRV_TRACKED_WRITE); +- +- if (!(flags & BDRV_REQ_NO_SERIALISING)) { +- wait_serialising_requests(&src_req); +- wait_serialising_requests(&dst_req); +- } + if (recurse_src) { ++ bdrv_inc_in_flight(src->bs); ++ tracked_request_begin(&req, src->bs, src_offset, bytes, ++ BDRV_TRACKED_READ); ++ ++ if (!(flags & BDRV_REQ_NO_SERIALISING)) { ++ wait_serialising_requests(&req); ++ } ++ + ret = src->bs->drv->bdrv_co_copy_range_from(src->bs, + src, src_offset, + dst, dst_offset, + bytes, flags); ++ ++ tracked_request_end(&req); ++ bdrv_dec_in_flight(src->bs); + } else { ++ bdrv_inc_in_flight(dst->bs); ++ tracked_request_begin(&req, dst->bs, dst_offset, bytes, ++ BDRV_TRACKED_WRITE); ++ ++ /* BDRV_REQ_NO_SERIALISING is only for read operation, ++ * so we ignore it in flags. ++ */ ++ wait_serialising_requests(&req); ++ + ret = dst->bs->drv->bdrv_co_copy_range_to(dst->bs, + src, src_offset, + dst, dst_offset, + bytes, flags); ++ ++ tracked_request_end(&req); ++ bdrv_dec_in_flight(dst->bs); + } +- tracked_request_end(&src_req); +- tracked_request_end(&dst_req); +- bdrv_dec_in_flight(src->bs); +- bdrv_dec_in_flight(dst->bs); ++ + return ret; + } + +diff --git a/include/block/block.h b/include/block/block.h +index e1d5e47..716fb5b 100644 +--- a/include/block/block.h ++++ b/include/block/block.h +@@ -50,6 +50,18 @@ typedef enum { + * opened with BDRV_O_UNMAP. + */ + BDRV_REQ_MAY_UNMAP = 0x4, ++ ++ /* ++ * The BDRV_REQ_NO_SERIALISING flag is only valid for reads and means that ++ * we don't want wait_serialising_requests() during the read operation. ++ * ++ * This flag is used for backup copy-on-write operations, when we need to ++ * read old data before write (write notifier triggered). It is okay since ++ * we already waited for other serializing requests in the initiating write ++ * (see bdrv_aligned_pwritev), and it is necessary if the initiating write ++ * is already serializing (without the flag, the read would deadlock ++ * waiting for the serialising write to complete). ++ */ + BDRV_REQ_NO_SERIALISING = 0x8, + BDRV_REQ_FUA = 0x10, + BDRV_REQ_WRITE_COMPRESSED = 0x20, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-iotest-to-catch-abort-on-forced-blockjob-cance.patch b/SOURCES/kvm-block-iotest-to-catch-abort-on-forced-blockjob-cance.patch new file mode 100644 index 0000000..fe82d9f --- /dev/null +++ b/SOURCES/kvm-block-iotest-to-catch-abort-on-forced-blockjob-cance.patch @@ -0,0 +1,171 @@ +From 981ab75d595c2aa8477cab9b514d3ba50e895c9f Mon Sep 17 00:00:00 2001 +From: Jeffrey Cody +Date: Tue, 28 Aug 2018 21:08:18 +0200 +Subject: [PATCH 05/29] block: iotest to catch abort on forced blockjob cancel + +RH-Author: Jeffrey Cody +Message-id: +Patchwork-id: 81956 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 3/3] block: iotest to catch abort on forced blockjob cancel +Bugzilla: 1605026 +RH-Acked-by: Max Reitz +RH-Acked-by: John Snow +RH-Acked-by: Miroslav Rezanina + +Signed-off-by: Jeff Cody +Reviewed-by: John Snow +Message-id: df317f617fbe5affcf699cb8560e7b0c2e028a64.1534868459.git.jcody@redhat.com +Signed-off-by: Jeff Cody +(cherry picked from commit 26bf474ba92c76e61bea51726e22da6dfd185296) +Signed-off-by: Jeff Cody +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/229 | 95 ++++++++++++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/229.out | 23 +++++++++++ + tests/qemu-iotests/group | 1 + + 3 files changed, 119 insertions(+) + create mode 100755 tests/qemu-iotests/229 + create mode 100644 tests/qemu-iotests/229.out + +diff --git a/tests/qemu-iotests/229 b/tests/qemu-iotests/229 +new file mode 100755 +index 0000000..ff851ec +--- /dev/null ++++ b/tests/qemu-iotests/229 +@@ -0,0 +1,95 @@ ++#!/bin/bash ++# ++# Test for force canceling a running blockjob that is paused in ++# an error state. ++# ++# Copyright (C) 2018 Red Hat, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++ ++# creator ++owner=jcody@redhat.com ++ ++seq="$(basename $0)" ++echo "QA output created by $seq" ++ ++here="$PWD" ++status=1 # failure is the default! ++ ++_cleanup() ++{ ++ _cleanup_qemu ++ _cleanup_test_img ++ rm -f "$TEST_IMG" "$DEST_IMG" ++} ++trap "_cleanup; exit \$status" 0 1 2 3 15 ++ ++# get standard environment, filters and checks ++. ./common.rc ++. ./common.filter ++. ./common.qemu ++ ++# Needs backing file and backing format support ++_supported_fmt qcow2 qed ++_supported_proto file ++_supported_os Linux ++ ++ ++DEST_IMG="$TEST_DIR/d.$IMGFMT" ++TEST_IMG="$TEST_DIR/b.$IMGFMT" ++ ++_make_test_img 2M ++ ++# destination for mirror will be too small, causing error ++TEST_IMG=$DEST_IMG _make_test_img 1M ++ ++$QEMU_IO -c 'write 0 2M' "$TEST_IMG" | _filter_qemu_io ++ ++_launch_qemu -drive id=testdisk,file="$TEST_IMG",format="$IMGFMT" ++ ++_send_qemu_cmd $QEMU_HANDLE \ ++ "{'execute': 'qmp_capabilities'}" \ ++ 'return' ++ ++echo ++echo '=== Starting drive-mirror, causing error & stop ===' ++echo ++ ++_send_qemu_cmd $QEMU_HANDLE \ ++ "{'execute': 'drive-mirror', ++ 'arguments': {'device': 'testdisk', ++ 'mode': 'absolute-paths', ++ 'format': '$IMGFMT', ++ 'target': '$DEST_IMG', ++ 'sync': 'full', ++ 'mode': 'existing', ++ 'on-source-error': 'stop', ++ 'on-target-error': 'stop' }}" \ ++ "JOB_STATUS_CHANGE.*pause" ++ ++echo ++echo '=== Force cancel job paused in error state ===' ++echo ++ ++success_or_failure="y" _send_qemu_cmd $QEMU_HANDLE \ ++ "{'execute': 'block-job-cancel', ++ 'arguments': { 'device': 'testdisk', ++ 'force': true}}" \ ++ "BLOCK_JOB_CANCELLED" "Assertion" ++ ++# success, all done ++echo "*** done" ++rm -f $seq.full ++status=0 +diff --git a/tests/qemu-iotests/229.out b/tests/qemu-iotests/229.out +new file mode 100644 +index 0000000..4c41128 +--- /dev/null ++++ b/tests/qemu-iotests/229.out +@@ -0,0 +1,23 @@ ++QA output created by 229 ++Formatting 'TEST_DIR/b.IMGFMT', fmt=IMGFMT size=2097152 ++Formatting 'TEST_DIR/d.IMGFMT', fmt=IMGFMT size=1048576 ++wrote 2097152/2097152 bytes at offset 0 ++2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++{"return": {}} ++ ++=== Starting drive-mirror, causing error & stop === ++ ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "testdisk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "testdisk"}} ++{"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "testdisk", "operation": "write", "action": "stop"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "testdisk"}} ++ ++=== Force cancel job paused in error state === ++ ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "testdisk"}} ++{"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "testdisk", "operation": "write", "action": "stop"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "testdisk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "testdisk", "len": 2097152, "offset": 1048576, "speed": 0, "type": "mirror"}} ++*** done +diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group +index 6dd146a..3817d28 100644 +--- a/tests/qemu-iotests/group ++++ b/tests/qemu-iotests/group +@@ -223,3 +223,4 @@ + 223 rw auto quick + 226 auto quick + 227 auto quick ++229 auto quick +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-linux-aio-acquire-AioContext-before-qemu_laio_.patch b/SOURCES/kvm-block-linux-aio-acquire-AioContext-before-qemu_laio_.patch new file mode 100644 index 0000000..ba9c1a8 --- /dev/null +++ b/SOURCES/kvm-block-linux-aio-acquire-AioContext-before-qemu_laio_.patch @@ -0,0 +1,132 @@ +From cd8c3589d4c99a1968cf7a37b50165fa7e927b2f Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:21 +0200 +Subject: [PATCH 30/49] block/linux-aio: acquire AioContext before + qemu_laio_process_completions + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-24-kwolf@redhat.com> +Patchwork-id: 82175 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 23/42] block/linux-aio: acquire AioContext before qemu_laio_process_completions +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +From: Sergio Lopez + +In qemu_laio_process_completions_and_submit, the AioContext is acquired +before the ioq_submit iteration and after qemu_laio_process_completions, +but the latter is not thread safe either. + +This change avoids a number of random crashes when the Main Thread and +an IO Thread collide processing completions for the same AioContext. +This is an example of such crash: + + - The IO Thread is trying to acquire the AioContext at aio_co_enter, + which evidences that it didn't lock it before: + +Thread 3 (Thread 0x7fdfd8bd8700 (LWP 36743)): + #0 0x00007fdfe0dd542d in __lll_lock_wait () at ../nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:135 + #1 0x00007fdfe0dd0de6 in _L_lock_870 () at /lib64/libpthread.so.0 + #2 0x00007fdfe0dd0cdf in __GI___pthread_mutex_lock (mutex=mutex@entry=0x5631fde0e6c0) + at ../nptl/pthread_mutex_lock.c:114 + #3 0x00005631fc0603a7 in qemu_mutex_lock_impl (mutex=0x5631fde0e6c0, file=0x5631fc23520f "util/async.c", line=511) at util/qemu-thread-posix.c:66 + #4 0x00005631fc05b558 in aio_co_enter (ctx=0x5631fde0e660, co=0x7fdfcc0c2b40) at util/async.c:493 + #5 0x00005631fc05b5ac in aio_co_wake (co=) at util/async.c:478 + #6 0x00005631fbfc51ad in qemu_laio_process_completion (laiocb=) at block/linux-aio.c:104 + #7 0x00005631fbfc523c in qemu_laio_process_completions (s=s@entry=0x7fdfc0297670) + at block/linux-aio.c:222 + #8 0x00005631fbfc5499 in qemu_laio_process_completions_and_submit (s=0x7fdfc0297670) + at block/linux-aio.c:237 + #9 0x00005631fc05d978 in aio_dispatch_handlers (ctx=ctx@entry=0x5631fde0e660) at util/aio-posix.c:406 + #10 0x00005631fc05e3ea in aio_poll (ctx=0x5631fde0e660, blocking=blocking@entry=true) + at util/aio-posix.c:693 + #11 0x00005631fbd7ad96 in iothread_run (opaque=0x5631fde0e1c0) at iothread.c:64 + #12 0x00007fdfe0dcee25 in start_thread (arg=0x7fdfd8bd8700) at pthread_create.c:308 + #13 0x00007fdfe0afc34d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:113 + + - The Main Thread is also processing completions from the same + AioContext, and crashes due to failed assertion at util/iov.c:78: + +Thread 1 (Thread 0x7fdfeb5eac80 (LWP 36740)): + #0 0x00007fdfe0a391f7 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56 + #1 0x00007fdfe0a3a8e8 in __GI_abort () at abort.c:90 + #2 0x00007fdfe0a32266 in __assert_fail_base (fmt=0x7fdfe0b84e68 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n", assertion=assertion@entry=0x5631fc238ccb "offset == 0", file=file@entry=0x5631fc23698e "util/iov.c", line=line@entry=78, function=function@entry=0x5631fc236adc <__PRETTY_FUNCTION__.15220> "iov_memset") + at assert.c:92 + #3 0x00007fdfe0a32312 in __GI___assert_fail (assertion=assertion@entry=0x5631fc238ccb "offset == 0", file=file@entry=0x5631fc23698e "util/iov.c", line=line@entry=78, function=function@entry=0x5631fc236adc <__PRETTY_FUNCTION__.15220> "iov_memset") at assert.c:101 + #4 0x00005631fc065287 in iov_memset (iov=, iov_cnt=, offset=, offset@entry=65536, fillc=fillc@entry=0, bytes=15515191315812405248) at util/iov.c:78 + #5 0x00005631fc065a63 in qemu_iovec_memset (qiov=, offset=offset@entry=65536, fillc=fillc@entry=0, bytes=) at util/iov.c:410 + #6 0x00005631fbfc5178 in qemu_laio_process_completion (laiocb=0x7fdd920df630) at block/linux-aio.c:88 + #7 0x00005631fbfc523c in qemu_laio_process_completions (s=s@entry=0x7fdfc0297670) + at block/linux-aio.c:222 + #8 0x00005631fbfc5499 in qemu_laio_process_completions_and_submit (s=0x7fdfc0297670) + at block/linux-aio.c:237 + #9 0x00005631fbfc54ed in qemu_laio_poll_cb (opaque=) at block/linux-aio.c:272 + #10 0x00005631fc05d85e in run_poll_handlers_once (ctx=ctx@entry=0x5631fde0e660) at util/aio-posix.c:497 + #11 0x00005631fc05e2ca in aio_poll (blocking=false, ctx=0x5631fde0e660) at util/aio-posix.c:574 + #12 0x00005631fc05e2ca in aio_poll (ctx=0x5631fde0e660, blocking=blocking@entry=false) + at util/aio-posix.c:604 + #13 0x00005631fbfcb8a3 in bdrv_do_drained_begin (ignore_parent=, recursive=, bs=) at block/io.c:273 + #14 0x00005631fbfcb8a3 in bdrv_do_drained_begin (bs=0x5631fe8b6200, recursive=, parent=0x0, ignore_bds_parents=, poll=) at block/io.c:390 + #15 0x00005631fbfbcd2e in blk_drain (blk=0x5631fe83ac80) at block/block-backend.c:1590 + #16 0x00005631fbfbe138 in blk_remove_bs (blk=blk@entry=0x5631fe83ac80) at block/block-backend.c:774 + #17 0x00005631fbfbe3d6 in blk_unref (blk=0x5631fe83ac80) at block/block-backend.c:401 + #18 0x00005631fbfbe3d6 in blk_unref (blk=0x5631fe83ac80) at block/block-backend.c:449 + #19 0x00005631fbfc9a69 in commit_complete (job=0x5631fe8b94b0, opaque=0x7fdfcc1bb080) + at block/commit.c:92 + #20 0x00005631fbf7d662 in job_defer_to_main_loop_bh (opaque=0x7fdfcc1b4560) at job.c:973 + #21 0x00005631fc05ad41 in aio_bh_poll (bh=0x7fdfcc01ad90) at util/async.c:90 + #22 0x00005631fc05ad41 in aio_bh_poll (ctx=ctx@entry=0x5631fddffdb0) at util/async.c:118 + #23 0x00005631fc05e210 in aio_dispatch (ctx=0x5631fddffdb0) at util/aio-posix.c:436 + #24 0x00005631fc05ac1e in aio_ctx_dispatch (source=, callback=, user_data=) at util/async.c:261 + #25 0x00007fdfeaae44c9 in g_main_context_dispatch (context=0x5631fde00140) at gmain.c:3201 + #26 0x00007fdfeaae44c9 in g_main_context_dispatch (context=context@entry=0x5631fde00140) at gmain.c:3854 + #27 0x00005631fc05d503 in main_loop_wait () at util/main-loop.c:215 + #28 0x00005631fc05d503 in main_loop_wait (timeout=) at util/main-loop.c:238 + #29 0x00005631fc05d503 in main_loop_wait (nonblocking=nonblocking@entry=0) at util/main-loop.c:497 + #30 0x00005631fbd81412 in main_loop () at vl.c:1866 + #31 0x00005631fbc18ff3 in main (argc=, argv=, envp=) + at vl.c:4647 + + - A closer examination shows that s->io_q.in_flight appears to have + gone backwards: + +(gdb) frame 7 + #7 0x00005631fbfc523c in qemu_laio_process_completions (s=s@entry=0x7fdfc0297670) + at block/linux-aio.c:222 +222 qemu_laio_process_completion(laiocb); +(gdb) p s +$2 = (LinuxAioState *) 0x7fdfc0297670 +(gdb) p *s +$3 = {aio_context = 0x5631fde0e660, ctx = 0x7fdfeb43b000, e = {rfd = 33, wfd = 33}, io_q = {plugged = 0, + in_queue = 0, in_flight = 4294967280, blocked = false, pending = {sqh_first = 0x0, + sqh_last = 0x7fdfc0297698}}, completion_bh = 0x7fdfc0280ef0, event_idx = 21, event_max = 241} +(gdb) p/x s->io_q.in_flight +$4 = 0xfffffff0 + +Signed-off-by: Sergio Lopez +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/linux-aio.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/block/linux-aio.c b/block/linux-aio.c +index 88b8d55..abd8886 100644 +--- a/block/linux-aio.c ++++ b/block/linux-aio.c +@@ -233,9 +233,9 @@ static void qemu_laio_process_completions(LinuxAioState *s) + + static void qemu_laio_process_completions_and_submit(LinuxAioState *s) + { ++ aio_context_acquire(s->aio_context); + qemu_laio_process_completions(s); + +- aio_context_acquire(s->aio_context); + if (!s->io_q.plugged && !QSIMPLEQ_EMPTY(&s->io_q.pending)) { + ioq_submit(s); + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-mirror-Make-cancel-always-cancel-pre-READY.patch b/SOURCES/kvm-block-mirror-Make-cancel-always-cancel-pre-READY.patch new file mode 100644 index 0000000..cfc3783 --- /dev/null +++ b/SOURCES/kvm-block-mirror-Make-cancel-always-cancel-pre-READY.patch @@ -0,0 +1,59 @@ +From ec4901d603e9f29f9111933bb14d48653a1d67fa Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 14:47:35 +0200 +Subject: [PATCH 25/54] block/mirror: Make cancel always cancel pre-READY + +RH-Author: Max Reitz +Message-id: <20180618144736.29873-3-mreitz@redhat.com> +Patchwork-id: 80748 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 2/3] block/mirror: Make cancel always cancel pre-READY +Bugzilla: 1572856 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf +RH-Acked-by: John Snow + +Commit b76e4458b1eb3c32e9824fe6aa51f67d2b251748 made the mirror block +job respect block-job-cancel's @force flag: With that flag set, it would +now always really cancel, even post-READY. + +Unfortunately, it had a side effect: Without that flag set, it would now +never cancel, not even before READY. Considering that is an +incompatible change and not noted anywhere in the commit or the +description of block-job-cancel's @force parameter, this seems +unintentional and we should revert to the previous behavior, which is to +immediately cancel the job when block-job-cancel is called before source +and target are in sync (i.e. before the READY event). + +Cc: qemu-stable@nongnu.org +Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1572856 +Reported-by: Yanan Fu +Signed-off-by: Max Reitz +Reviewed-by: Eric Blake +Message-id: 20180501220509.14152-2-mreitz@redhat.com +Reviewed-by: Jeff Cody +Signed-off-by: Jeff Cody +(cherry picked from commit eb36639f7bbc16055e551593b81365e8ae3b0b05) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + block/mirror.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/block/mirror.c b/block/mirror.c +index 9436a8d..99da9c0 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -874,7 +874,9 @@ static void coroutine_fn mirror_run(void *opaque) + } + trace_mirror_before_sleep(s, cnt, s->synced, delay_ns); + block_job_sleep_ns(&s->common, delay_ns); +- if (block_job_is_cancelled(&s->common) && s->common.force) { ++ if (block_job_is_cancelled(&s->common) && ++ (!s->synced || s->common.force)) ++ { + break; + } + s->last_pause_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-mirror-add-block-job-creation-flags.patch b/SOURCES/kvm-block-mirror-add-block-job-creation-flags.patch new file mode 100644 index 0000000..c5e0efa --- /dev/null +++ b/SOURCES/kvm-block-mirror-add-block-job-creation-flags.patch @@ -0,0 +1,100 @@ +From 504f6ad36108eb4d710cd1e29694bb4a2bcdb8bd Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 10 Sep 2018 18:17:49 +0200 +Subject: [PATCH 11/25] block/mirror: add block job creation flags + +RH-Author: John Snow +Message-id: <20180910181803.11781-12-jsnow@redhat.com> +Patchwork-id: 82088 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 11/25] block/mirror: add block job creation flags +Bugzilla: 1626061 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Add support for taking and passing forward job creation flags. + +Signed-off-by: John Snow +Reviewed-by: Max Reitz +Reviewed-by: Jeff Cody +Message-id: 20180906130225.5118-3-jsnow@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit bbb6798d0caa79cd4e899b33777c577d0bd04399) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/mirror.c | 5 +++-- + blockdev.c | 3 ++- + include/block/block_int.h | 5 ++++- + 3 files changed, 9 insertions(+), 4 deletions(-) + +diff --git a/block/mirror.c b/block/mirror.c +index 0ab0822..a80c359 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -1270,7 +1270,8 @@ fail: + + void mirror_start(const char *job_id, BlockDriverState *bs, + BlockDriverState *target, const char *replaces, +- int64_t speed, uint32_t granularity, int64_t buf_size, ++ int creation_flags, int64_t speed, ++ uint32_t granularity, int64_t buf_size, + MirrorSyncMode mode, BlockMirrorBackingMode backing_mode, + BlockdevOnError on_source_error, + BlockdevOnError on_target_error, +@@ -1285,7 +1286,7 @@ void mirror_start(const char *job_id, BlockDriverState *bs, + } + is_none_mode = mode == MIRROR_SYNC_MODE_NONE; + base = mode == MIRROR_SYNC_MODE_TOP ? backing_bs(bs) : NULL; +- mirror_start_job(job_id, bs, JOB_DEFAULT, target, replaces, ++ mirror_start_job(job_id, bs, creation_flags, target, replaces, + speed, granularity, buf_size, backing_mode, + on_source_error, on_target_error, unmap, NULL, NULL, + &mirror_job_driver, is_none_mode, base, false, +diff --git a/blockdev.c b/blockdev.c +index 20dbcf5..5d38e17 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -3746,6 +3746,7 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs, + const char *filter_node_name, + Error **errp) + { ++ int job_flags = JOB_DEFAULT; + + if (!has_speed) { + speed = 0; +@@ -3795,7 +3796,7 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs, + * and will allow to check whether the node still exist at mirror completion + */ + mirror_start(job_id, bs, target, +- has_replaces ? replaces : NULL, ++ has_replaces ? replaces : NULL, job_flags, + speed, granularity, buf_size, sync, backing_mode, + on_source_error, on_target_error, unmap, filter_node_name, + errp); +diff --git a/include/block/block_int.h b/include/block/block_int.h +index 25ad363..07517cf 100644 +--- a/include/block/block_int.h ++++ b/include/block/block_int.h +@@ -1000,6 +1000,8 @@ void commit_active_start(const char *job_id, BlockDriverState *bs, + * @target: Block device to write to. + * @replaces: Block graph node name to replace once the mirror is done. Can + * only be used when full mirroring is selected. ++ * @creation_flags: Flags that control the behavior of the Job lifetime. ++ * See @BlockJobCreateFlags + * @speed: The maximum speed, in bytes per second, or 0 for unlimited. + * @granularity: The chosen granularity for the dirty bitmap. + * @buf_size: The amount of data that can be in flight at one time. +@@ -1020,7 +1022,8 @@ void commit_active_start(const char *job_id, BlockDriverState *bs, + */ + void mirror_start(const char *job_id, BlockDriverState *bs, + BlockDriverState *target, const char *replaces, +- int64_t speed, uint32_t granularity, int64_t buf_size, ++ int creation_flags, int64_t speed, ++ uint32_t granularity, int64_t buf_size, + MirrorSyncMode mode, BlockMirrorBackingMode backing_mode, + BlockdevOnError on_source_error, + BlockdevOnError on_target_error, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-mirror-conservative-mirror_exit-refactor.patch b/SOURCES/kvm-block-mirror-conservative-mirror_exit-refactor.patch new file mode 100644 index 0000000..4f2ea05 --- /dev/null +++ b/SOURCES/kvm-block-mirror-conservative-mirror_exit-refactor.patch @@ -0,0 +1,141 @@ +From f27835b1c21b80477e828ed82c5afd764e6f90ca Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 10 Sep 2018 18:17:53 +0200 +Subject: [PATCH 15/25] block/mirror: conservative mirror_exit refactor + +RH-Author: John Snow +Message-id: <20180910181803.11781-16-jsnow@redhat.com> +Patchwork-id: 82105 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 15/25] block/mirror: conservative mirror_exit refactor +Bugzilla: 1626061 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +For purposes of minimum code movement, refactor the mirror_exit +callback to use the post-finalization callbacks in a trivial way. + +Signed-off-by: John Snow +Message-id: 20180906130225.5118-7-jsnow@redhat.com +Reviewed-by: Jeff Cody +Reviewed-by: Max Reitz +[mreitz: Added comment for the mirror_exit() function] +Signed-off-by: Max Reitz +(cherry picked from commit 9fd426955da4239af7690c92b387fff0502aca84) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina + +Conflicts: + block/mirror.c: context conflict on job properties +--- + block/mirror.c | 44 +++++++++++++++++++++++++++++++++----------- + 1 file changed, 33 insertions(+), 11 deletions(-) + +diff --git a/block/mirror.c b/block/mirror.c +index 1945000..313e6e9 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -71,6 +71,7 @@ typedef struct MirrorBlockJob { + int target_cluster_size; + int max_iov; + bool initial_zeroing_ongoing; ++ bool prepared; + } MirrorBlockJob; + + typedef struct MirrorOp { +@@ -480,7 +481,12 @@ static void mirror_wait_for_all_io(MirrorBlockJob *s) + } + } + +-static void mirror_exit(Job *job) ++/** ++ * mirror_exit_common: handle both abort() and prepare() cases. ++ * for .prepare, returns 0 on success and -errno on failure. ++ * for .abort cases, denoted by abort = true, MUST return 0. ++ */ ++static int mirror_exit_common(Job *job) + { + MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job); + BlockJob *bjob = &s->common; +@@ -489,7 +495,13 @@ static void mirror_exit(Job *job) + BlockDriverState *target_bs = blk_bs(s->target); + BlockDriverState *mirror_top_bs = s->mirror_top_bs; + Error *local_err = NULL; +- int ret = job->ret; ++ bool abort = job->ret < 0; ++ int ret = 0; ++ ++ if (s->prepared) { ++ return 0; ++ } ++ s->prepared = true; + + bdrv_release_dirty_bitmap(src, s->dirty_bitmap); + +@@ -514,7 +526,7 @@ static void mirror_exit(Job *job) + * required before it could become a backing file of target_bs. */ + bdrv_child_try_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL, + &error_abort); +- if (ret == 0 && s->backing_mode == MIRROR_SOURCE_BACKING_CHAIN) { ++ if (!abort && s->backing_mode == MIRROR_SOURCE_BACKING_CHAIN) { + BlockDriverState *backing = s->is_none_mode ? src : s->base; + if (backing_bs(target_bs) != backing) { + bdrv_set_backing_hd(target_bs, backing, &local_err); +@@ -530,11 +542,8 @@ static void mirror_exit(Job *job) + aio_context_acquire(replace_aio_context); + } + +- if (s->should_complete && ret == 0) { +- BlockDriverState *to_replace = src; +- if (s->to_replace) { +- to_replace = s->to_replace; +- } ++ if (s->should_complete && !abort) { ++ BlockDriverState *to_replace = s->to_replace ?: src; + + if (bdrv_get_flags(target_bs) != bdrv_get_flags(to_replace)) { + bdrv_reopen(target_bs, bdrv_get_flags(to_replace), NULL); +@@ -581,7 +590,18 @@ static void mirror_exit(Job *job) + bdrv_unref(mirror_top_bs); + bdrv_unref(src); + +- job->ret = ret; ++ return ret; ++} ++ ++static int mirror_prepare(Job *job) ++{ ++ return mirror_exit_common(job); ++} ++ ++static void mirror_abort(Job *job) ++{ ++ int ret = mirror_exit_common(job); ++ assert(ret == 0); + } + + static void mirror_throttle(MirrorBlockJob *s) +@@ -986,7 +1006,8 @@ static const BlockJobDriver mirror_job_driver = { + .user_resume = block_job_user_resume, + .drain = block_job_drain, + .run = mirror_run, +- .exit = mirror_exit, ++ .prepare = mirror_prepare, ++ .abort = mirror_abort, + .pause = mirror_pause, + .complete = mirror_complete, + }, +@@ -1002,7 +1023,8 @@ static const BlockJobDriver commit_active_job_driver = { + .user_resume = block_job_user_resume, + .drain = block_job_drain, + .run = mirror_run, +- .exit = mirror_exit, ++ .prepare = mirror_prepare, ++ .abort = mirror_abort, + .pause = mirror_pause, + .complete = mirror_complete, + }, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-mirror-don-t-install-backing-chain-on-abort.patch b/SOURCES/kvm-block-mirror-don-t-install-backing-chain-on-abort.patch new file mode 100644 index 0000000..4c85635 --- /dev/null +++ b/SOURCES/kvm-block-mirror-don-t-install-backing-chain-on-abort.patch @@ -0,0 +1,45 @@ +From ec75d6bf020a399a3caee05dcc37b463d438c332 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 10 Sep 2018 18:17:52 +0200 +Subject: [PATCH 14/25] block/mirror: don't install backing chain on abort + +RH-Author: John Snow +Message-id: <20180910181803.11781-15-jsnow@redhat.com> +Patchwork-id: 82091 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 14/25] block/mirror: don't install backing chain on abort +Bugzilla: 1626061 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +In cases where we abort the block/mirror job, there's no point in +installing the new backing chain before we finish aborting. + +Signed-off-by: John Snow +Message-id: 20180906130225.5118-6-jsnow@redhat.com +Reviewed-by: Jeff Cody +Reviewed-by: Max Reitz +Signed-off-by: Max Reitz +(cherry picked from commit 46e2f0070a9bd82187c12b679ec5a69c6aabe128) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/mirror.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/block/mirror.c b/block/mirror.c +index a80c359..1945000 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -514,7 +514,7 @@ static void mirror_exit(Job *job) + * required before it could become a backing file of target_bs. */ + bdrv_child_try_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL, + &error_abort); +- if (s->backing_mode == MIRROR_SOURCE_BACKING_CHAIN) { ++ if (ret == 0 && s->backing_mode == MIRROR_SOURCE_BACKING_CHAIN) { + BlockDriverState *backing = s->is_none_mode ? src : s->base; + if (backing_bs(target_bs) != backing) { + bdrv_set_backing_hd(target_bs, backing, &local_err); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-mirror-honor-ratelimit-again.patch b/SOURCES/kvm-block-mirror-honor-ratelimit-again.patch new file mode 100644 index 0000000..9876f63 --- /dev/null +++ b/SOURCES/kvm-block-mirror-honor-ratelimit-again.patch @@ -0,0 +1,87 @@ +From 294916c8fdc6fdd221543c70b716e31591315379 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 14:47:34 +0200 +Subject: [PATCH 24/54] block/mirror: honor ratelimit again + +RH-Author: Max Reitz +Message-id: <20180618144736.29873-2-mreitz@redhat.com> +Patchwork-id: 80747 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 1/3] block/mirror: honor ratelimit again +Bugzilla: 1572856 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf +RH-Acked-by: John Snow + +From: Stefan Hajnoczi + +Commit b76e4458b1eb3c32e9824fe6aa51f67d2b251748 ("block/mirror: change +the semantic of 'force' of block-job-cancel") accidentally removed the +ratelimit in the mirror job. + +Reintroduce the ratelimit but keep the block-job-cancel force=true +behavior that was added in commit +b76e4458b1eb3c32e9824fe6aa51f67d2b251748. + +Note that block_job_sleep_ns() returns immediately when the job is +cancelled. Therefore it's safe to unconditionally call +block_job_sleep_ns() - a cancelled job does not sleep. + +This commit fixes the non-deterministic qemu-iotests 185 output. The +test relies on the ratelimit to make the job sleep until the 'quit' +command is processed. Previously the job could complete before the +'quit' command was received since there was no ratelimit. + +Cc: Liang Li +Cc: Jeff Cody +Cc: Kevin Wolf +Signed-off-by: Stefan Hajnoczi +Message-id: 20180424123527.19168-1-stefanha@redhat.com +Signed-off-by: Jeff Cody +(cherry picked from commit ddc4115efdfa6619689fe18871aa2d37890b3463) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + block/mirror.c | 8 +++++--- + tests/qemu-iotests/185.out | 2 +- + 2 files changed, 6 insertions(+), 4 deletions(-) + +diff --git a/block/mirror.c b/block/mirror.c +index 820f512..9436a8d 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -868,12 +868,14 @@ static void coroutine_fn mirror_run(void *opaque) + } + + ret = 0; ++ ++ if (s->synced && !should_complete) { ++ delay_ns = (s->in_flight == 0 && cnt == 0 ? SLICE_TIME : 0); ++ } + trace_mirror_before_sleep(s, cnt, s->synced, delay_ns); ++ block_job_sleep_ns(&s->common, delay_ns); + if (block_job_is_cancelled(&s->common) && s->common.force) { + break; +- } else if (!should_complete) { +- delay_ns = (s->in_flight == 0 && cnt == 0 ? SLICE_TIME : 0); +- block_job_sleep_ns(&s->common, delay_ns); + } + s->last_pause_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); + } +diff --git a/tests/qemu-iotests/185.out b/tests/qemu-iotests/185.out +index 2c4b04d..992162f 100644 +--- a/tests/qemu-iotests/185.out ++++ b/tests/qemu-iotests/185.out +@@ -36,9 +36,9 @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.q + {"return": {}} + Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 + {"return": {}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "disk", "len": 4194304, "offset": 4194304, "speed": 65536, "type": "mirror"}} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "disk", "len": 4194304, "offset": 4194304, "speed": 65536, "type": "mirror"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "disk", "len": 4194304, "offset": 4194304, "speed": 65536, "type": "mirror"}} + + === Start backup job and exit qemu === +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-mirror-utilize-job_exit-shim.patch b/SOURCES/kvm-block-mirror-utilize-job_exit-shim.patch new file mode 100644 index 0000000..10d3210 --- /dev/null +++ b/SOURCES/kvm-block-mirror-utilize-job_exit-shim.patch @@ -0,0 +1,152 @@ +From a89c41261dee7c365995d9f5f98bcdb543e42775 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 10 Sep 2018 18:17:43 +0200 +Subject: [PATCH 05/25] block/mirror: utilize job_exit shim + +RH-Author: John Snow +Message-id: <20180910181803.11781-6-jsnow@redhat.com> +Patchwork-id: 82098 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 05/25] block/mirror: utilize job_exit shim +Bugzilla: 1626061 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Change the manual deferment to mirror_exit into the implicit +callback to job_exit and the mirror_exit callback. + +This does change the order of some bdrv_unref calls and job_completed, +but thanks to the new context in which we call .exit, this is safe to +defer the possible flushing of any nodes to the job_finalize_single +cleanup stage. + +Signed-off-by: John Snow +Message-id: 20180830015734.19765-6-jsnow@redhat.com +Reviewed-by: Max Reitz +Reviewed-by: Jeff Cody +Signed-off-by: Max Reitz +(cherry picked from commit 7b508f6b7a38a8d9729772fa6e525da883fb120b) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/mirror.c | 30 +++++++++++------------------- + 1 file changed, 11 insertions(+), 19 deletions(-) + +diff --git a/block/mirror.c b/block/mirror.c +index 459f944..0ab0822 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -480,25 +480,21 @@ static void mirror_wait_for_all_io(MirrorBlockJob *s) + } + } + +-typedef struct { +- int ret; +-} MirrorExitData; +- +-static void mirror_exit(Job *job, void *opaque) ++static void mirror_exit(Job *job) + { + MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job); + BlockJob *bjob = &s->common; +- MirrorExitData *data = opaque; + AioContext *replace_aio_context = NULL; + BlockDriverState *src = s->source; + BlockDriverState *target_bs = blk_bs(s->target); + BlockDriverState *mirror_top_bs = s->mirror_top_bs; + Error *local_err = NULL; ++ int ret = job->ret; + + bdrv_release_dirty_bitmap(src, s->dirty_bitmap); + +- /* Make sure that the source BDS doesn't go away before we called +- * job_completed(). */ ++ /* Make sure that the source BDS doesn't go away during bdrv_replace_node, ++ * before we can call bdrv_drained_end */ + bdrv_ref(src); + bdrv_ref(mirror_top_bs); + bdrv_ref(target_bs); +@@ -524,7 +520,7 @@ static void mirror_exit(Job *job, void *opaque) + bdrv_set_backing_hd(target_bs, backing, &local_err); + if (local_err) { + error_report_err(local_err); +- data->ret = -EPERM; ++ ret = -EPERM; + } + } + } +@@ -534,7 +530,7 @@ static void mirror_exit(Job *job, void *opaque) + aio_context_acquire(replace_aio_context); + } + +- if (s->should_complete && data->ret == 0) { ++ if (s->should_complete && ret == 0) { + BlockDriverState *to_replace = src; + if (s->to_replace) { + to_replace = s->to_replace; +@@ -551,7 +547,7 @@ static void mirror_exit(Job *job, void *opaque) + bdrv_drained_end(target_bs); + if (local_err) { + error_report_err(local_err); +- data->ret = -EPERM; ++ ret = -EPERM; + } + } + if (s->to_replace) { +@@ -581,12 +577,11 @@ static void mirror_exit(Job *job, void *opaque) + blk_set_perm(bjob->blk, 0, BLK_PERM_ALL, &error_abort); + blk_insert_bs(bjob->blk, mirror_top_bs, &error_abort); + +- job_completed(job, data->ret); +- +- g_free(data); + bdrv_drained_end(src); + bdrv_unref(mirror_top_bs); + bdrv_unref(src); ++ ++ job->ret = ret; + } + + static void mirror_throttle(MirrorBlockJob *s) +@@ -686,7 +681,6 @@ static int mirror_flush(MirrorBlockJob *s) + static int coroutine_fn mirror_run(Job *job, Error **errp) + { + MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job); +- MirrorExitData *data; + BlockDriverState *bs = s->source; + BlockDriverState *target_bs = blk_bs(s->target); + bool need_drain = true; +@@ -896,14 +890,10 @@ immediate_exit: + g_free(s->in_flight_bitmap); + bdrv_dirty_iter_free(s->dbi); + +- data = g_malloc(sizeof(*data)); +- data->ret = ret; +- + if (need_drain) { + bdrv_drained_begin(bs); + } + +- job_defer_to_main_loop(&s->common.job, mirror_exit, data); + return ret; + } + +@@ -996,6 +986,7 @@ static const BlockJobDriver mirror_job_driver = { + .user_resume = block_job_user_resume, + .drain = block_job_drain, + .run = mirror_run, ++ .exit = mirror_exit, + .pause = mirror_pause, + .complete = mirror_complete, + }, +@@ -1011,6 +1002,7 @@ static const BlockJobDriver commit_active_job_driver = { + .user_resume = block_job_user_resume, + .drain = block_job_drain, + .run = mirror_run, ++ .exit = mirror_exit, + .pause = mirror_pause, + .complete = mirror_complete, + }, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-move-ThrottleGroup-membership-to-ThrottleGroup.patch b/SOURCES/kvm-block-move-ThrottleGroup-membership-to-ThrottleGroup.patch deleted file mode 100644 index f9ac543..0000000 --- a/SOURCES/kvm-block-move-ThrottleGroup-membership-to-ThrottleGroup.patch +++ /dev/null @@ -1,1023 +0,0 @@ -From 6b39617d8b6ec2930c61e8965452317afbdf8030 Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Fri, 17 Nov 2017 11:19:00 +0100 -Subject: [PATCH 01/15] block: move ThrottleGroup membership to - ThrottleGroupMember - -RH-Author: Stefan Hajnoczi -Message-id: <20171117111908.8815-2-stefanha@redhat.com> -Patchwork-id: 77737 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 1/9] block: move ThrottleGroup membership to ThrottleGroupMember -Bugzilla: 1492295 -RH-Acked-by: John Snow -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth - -From: Manos Pitsidianakis - -This commit eliminates the 1:1 relationship between BlockBackend and -throttle group state. Users will be able to create multiple throttle -nodes, each with its own throttle group state, in the future. The -throttle group state cannot be per-BlockBackend anymore, it must be -per-throttle node. This is done by gathering ThrottleGroup membership -details from BlockBackendPublic into ThrottleGroupMember and refactoring -existing code to use the structure. - -Reviewed-by: Alberto Garcia -Reviewed-by: Stefan Hajnoczi -Signed-off-by: Manos Pitsidianakis -Signed-off-by: Kevin Wolf -(cherry picked from commit 022cdc9f407434ad6eb7ace80362a1218a009bcc) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - block/block-backend.c | 66 +++++---- - block/qapi.c | 8 +- - block/throttle-groups.c | 288 ++++++++++++++++++++-------------------- - blockdev.c | 4 +- - include/block/throttle-groups.h | 39 +++++- - include/sysemu/block-backend.h | 20 +-- - tests/test-throttle.c | 53 ++++---- - 7 files changed, 252 insertions(+), 226 deletions(-) - -diff --git a/block/block-backend.c b/block/block-backend.c -index 0819b3a..e61f072 100644 ---- a/block/block-backend.c -+++ b/block/block-backend.c -@@ -273,9 +273,9 @@ BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm) - blk->shared_perm = shared_perm; - blk_set_enable_write_cache(blk, true); - -- qemu_co_mutex_init(&blk->public.throttled_reqs_lock); -- qemu_co_queue_init(&blk->public.throttled_reqs[0]); -- qemu_co_queue_init(&blk->public.throttled_reqs[1]); -+ qemu_co_mutex_init(&blk->public.throttle_group_member.throttled_reqs_lock); -+ qemu_co_queue_init(&blk->public.throttle_group_member.throttled_reqs[0]); -+ qemu_co_queue_init(&blk->public.throttle_group_member.throttled_reqs[1]); - block_acct_init(&blk->stats); - - notifier_list_init(&blk->remove_bs_notifiers); -@@ -343,7 +343,7 @@ static void blk_delete(BlockBackend *blk) - assert(!blk->refcnt); - assert(!blk->name); - assert(!blk->dev); -- if (blk->public.throttle_state) { -+ if (blk->public.throttle_group_member.throttle_state) { - blk_io_limits_disable(blk); - } - if (blk->root) { -@@ -658,9 +658,12 @@ BlockBackend *blk_by_public(BlockBackendPublic *public) - */ - void blk_remove_bs(BlockBackend *blk) - { -+ ThrottleTimers *tt; -+ - notifier_list_notify(&blk->remove_bs_notifiers, blk); -- if (blk->public.throttle_state) { -- throttle_timers_detach_aio_context(&blk->public.throttle_timers); -+ if (blk->public.throttle_group_member.throttle_state) { -+ tt = &blk->public.throttle_group_member.throttle_timers; -+ throttle_timers_detach_aio_context(tt); - } - - blk_update_root_state(blk); -@@ -682,9 +685,10 @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp) - bdrv_ref(bs); - - notifier_list_notify(&blk->insert_bs_notifiers, blk); -- if (blk->public.throttle_state) { -+ if (blk->public.throttle_group_member.throttle_state) { - throttle_timers_attach_aio_context( -- &blk->public.throttle_timers, bdrv_get_aio_context(bs)); -+ &blk->public.throttle_group_member.throttle_timers, -+ bdrv_get_aio_context(bs)); - } - - return 0; -@@ -1046,8 +1050,9 @@ int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset, - bdrv_inc_in_flight(bs); - - /* throttling disk I/O */ -- if (blk->public.throttle_state) { -- throttle_group_co_io_limits_intercept(blk, bytes, false); -+ if (blk->public.throttle_group_member.throttle_state) { -+ throttle_group_co_io_limits_intercept(&blk->public.throttle_group_member, -+ bytes, false); - } - - ret = bdrv_co_preadv(blk->root, offset, bytes, qiov, flags); -@@ -1070,10 +1075,10 @@ int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset, - } - - bdrv_inc_in_flight(bs); -- - /* throttling disk I/O */ -- if (blk->public.throttle_state) { -- throttle_group_co_io_limits_intercept(blk, bytes, true); -+ if (blk->public.throttle_group_member.throttle_state) { -+ throttle_group_co_io_limits_intercept(&blk->public.throttle_group_member, -+ bytes, true); - } - - if (!blk->enable_write_cache) { -@@ -1761,15 +1766,17 @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb) - void blk_set_aio_context(BlockBackend *blk, AioContext *new_context) - { - BlockDriverState *bs = blk_bs(blk); -+ ThrottleTimers *tt; - - if (bs) { -- if (blk->public.throttle_state) { -- throttle_timers_detach_aio_context(&blk->public.throttle_timers); -+ if (blk->public.throttle_group_member.throttle_state) { -+ tt = &blk->public.throttle_group_member.throttle_timers; -+ throttle_timers_detach_aio_context(tt); - } - bdrv_set_aio_context(bs, new_context); -- if (blk->public.throttle_state) { -- throttle_timers_attach_aio_context(&blk->public.throttle_timers, -- new_context); -+ if (blk->public.throttle_group_member.throttle_state) { -+ tt = &blk->public.throttle_group_member.throttle_timers; -+ throttle_timers_attach_aio_context(tt, new_context); - } - } - } -@@ -1988,33 +1995,34 @@ int blk_commit_all(void) - /* throttling disk I/O limits */ - void blk_set_io_limits(BlockBackend *blk, ThrottleConfig *cfg) - { -- throttle_group_config(blk, cfg); -+ throttle_group_config(&blk->public.throttle_group_member, cfg); - } - - void blk_io_limits_disable(BlockBackend *blk) - { -- assert(blk->public.throttle_state); -+ assert(blk->public.throttle_group_member.throttle_state); - bdrv_drained_begin(blk_bs(blk)); -- throttle_group_unregister_blk(blk); -+ throttle_group_unregister_tgm(&blk->public.throttle_group_member); - bdrv_drained_end(blk_bs(blk)); - } - - /* should be called before blk_set_io_limits if a limit is set */ - void blk_io_limits_enable(BlockBackend *blk, const char *group) - { -- assert(!blk->public.throttle_state); -- throttle_group_register_blk(blk, group); -+ assert(!blk->public.throttle_group_member.throttle_state); -+ throttle_group_register_tgm(&blk->public.throttle_group_member, group); - } - - void blk_io_limits_update_group(BlockBackend *blk, const char *group) - { - /* this BB is not part of any group */ -- if (!blk->public.throttle_state) { -+ if (!blk->public.throttle_group_member.throttle_state) { - return; - } - - /* this BB is a part of the same group than the one we want */ -- if (!g_strcmp0(throttle_group_get_name(blk), group)) { -+ if (!g_strcmp0(throttle_group_get_name(&blk->public.throttle_group_member), -+ group)) { - return; - } - -@@ -2036,8 +2044,8 @@ static void blk_root_drained_begin(BdrvChild *child) - /* Note that blk->root may not be accessible here yet if we are just - * attaching to a BlockDriverState that is drained. Use child instead. */ - -- if (atomic_fetch_inc(&blk->public.io_limits_disabled) == 0) { -- throttle_group_restart_blk(blk); -+ if (atomic_fetch_inc(&blk->public.throttle_group_member.io_limits_disabled) == 0) { -+ throttle_group_restart_tgm(&blk->public.throttle_group_member); - } - } - -@@ -2046,8 +2054,8 @@ static void blk_root_drained_end(BdrvChild *child) - BlockBackend *blk = child->opaque; - assert(blk->quiesce_counter); - -- assert(blk->public.io_limits_disabled); -- atomic_dec(&blk->public.io_limits_disabled); -+ assert(blk->public.throttle_group_member.io_limits_disabled); -+ atomic_dec(&blk->public.throttle_group_member.io_limits_disabled); - - if (--blk->quiesce_counter == 0) { - if (blk->dev_ops && blk->dev_ops->drained_end) { -diff --git a/block/qapi.c b/block/qapi.c -index 5f1a71f..7fa2437 100644 ---- a/block/qapi.c -+++ b/block/qapi.c -@@ -66,10 +66,11 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk, - - info->detect_zeroes = bs->detect_zeroes; - -- if (blk && blk_get_public(blk)->throttle_state) { -+ if (blk && blk_get_public(blk)->throttle_group_member.throttle_state) { - ThrottleConfig cfg; -+ BlockBackendPublic *blkp = blk_get_public(blk); - -- throttle_group_get_config(blk, &cfg); -+ throttle_group_get_config(&blkp->throttle_group_member, &cfg); - - info->bps = cfg.buckets[THROTTLE_BPS_TOTAL].avg; - info->bps_rd = cfg.buckets[THROTTLE_BPS_READ].avg; -@@ -117,7 +118,8 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk, - info->iops_size = cfg.op_size; - - info->has_group = true; -- info->group = g_strdup(throttle_group_get_name(blk)); -+ info->group = -+ g_strdup(throttle_group_get_name(&blkp->throttle_group_member)); - } - - info->write_threshold = bdrv_write_threshold_get(bs); -diff --git a/block/throttle-groups.c b/block/throttle-groups.c -index 890bfde..c8ed16d 100644 ---- a/block/throttle-groups.c -+++ b/block/throttle-groups.c -@@ -30,7 +30,7 @@ - #include "sysemu/qtest.h" - - /* The ThrottleGroup structure (with its ThrottleState) is shared -- * among different BlockBackends and it's independent from -+ * among different ThrottleGroupMembers and it's independent from - * AioContext, so in order to use it from different threads it needs - * its own locking. - * -@@ -40,26 +40,26 @@ - * The whole ThrottleGroup structure is private and invisible to - * outside users, that only use it through its ThrottleState. - * -- * In addition to the ThrottleGroup structure, BlockBackendPublic has -+ * In addition to the ThrottleGroup structure, ThrottleGroupMember has - * fields that need to be accessed by other members of the group and - * therefore also need to be protected by this lock. Once a -- * BlockBackend is registered in a group those fields can be accessed -+ * ThrottleGroupMember is registered in a group those fields can be accessed - * by other threads any time. - * - * Again, all this is handled internally and is mostly transparent to - * the outside. The 'throttle_timers' field however has an additional - * constraint because it may be temporarily invalid (see for example - * blk_set_aio_context()). Therefore in this file a thread will -- * access some other BlockBackend's timers only after verifying that -- * that BlockBackend has throttled requests in the queue. -+ * access some other ThrottleGroupMember's timers only after verifying that -+ * that ThrottleGroupMember has throttled requests in the queue. - */ - typedef struct ThrottleGroup { - char *name; /* This is constant during the lifetime of the group */ - - QemuMutex lock; /* This lock protects the following four fields */ - ThrottleState ts; -- QLIST_HEAD(, BlockBackendPublic) head; -- BlockBackend *tokens[2]; -+ QLIST_HEAD(, ThrottleGroupMember) head; -+ ThrottleGroupMember *tokens[2]; - bool any_timer_armed[2]; - QEMUClockType clock_type; - -@@ -140,114 +140,112 @@ void throttle_group_unref(ThrottleState *ts) - qemu_mutex_unlock(&throttle_groups_lock); - } - --/* Get the name from a BlockBackend's ThrottleGroup. The name (and the pointer) -+/* Get the name from a ThrottleGroupMember's group. The name (and the pointer) - * is guaranteed to remain constant during the lifetime of the group. - * -- * @blk: a BlockBackend that is member of a throttling group -+ * @tgm: a ThrottleGroupMember - * @ret: the name of the group. - */ --const char *throttle_group_get_name(BlockBackend *blk) -+const char *throttle_group_get_name(ThrottleGroupMember *tgm) - { -- BlockBackendPublic *blkp = blk_get_public(blk); -- ThrottleGroup *tg = container_of(blkp->throttle_state, ThrottleGroup, ts); -+ ThrottleGroup *tg = container_of(tgm->throttle_state, ThrottleGroup, ts); - return tg->name; - } - --/* Return the next BlockBackend in the round-robin sequence, simulating a -- * circular list. -+/* Return the next ThrottleGroupMember in the round-robin sequence, simulating -+ * a circular list. - * - * This assumes that tg->lock is held. - * -- * @blk: the current BlockBackend -- * @ret: the next BlockBackend in the sequence -+ * @tgm: the current ThrottleGroupMember -+ * @ret: the next ThrottleGroupMember in the sequence - */ --static BlockBackend *throttle_group_next_blk(BlockBackend *blk) -+static ThrottleGroupMember *throttle_group_next_tgm(ThrottleGroupMember *tgm) - { -- BlockBackendPublic *blkp = blk_get_public(blk); -- ThrottleState *ts = blkp->throttle_state; -+ ThrottleState *ts = tgm->throttle_state; - ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts); -- BlockBackendPublic *next = QLIST_NEXT(blkp, round_robin); -+ ThrottleGroupMember *next = QLIST_NEXT(tgm, round_robin); - - if (!next) { - next = QLIST_FIRST(&tg->head); - } - -- return blk_by_public(next); -+ return next; - } - - /* -- * Return whether a BlockBackend has pending requests. -+ * Return whether a ThrottleGroupMember has pending requests. - * - * This assumes that tg->lock is held. - * -- * @blk: the BlockBackend -- * @is_write: the type of operation (read/write) -- * @ret: whether the BlockBackend has pending requests. -+ * @tgm: the ThrottleGroupMember -+ * @is_write: the type of operation (read/write) -+ * @ret: whether the ThrottleGroupMember has pending requests. - */ --static inline bool blk_has_pending_reqs(BlockBackend *blk, -+static inline bool tgm_has_pending_reqs(ThrottleGroupMember *tgm, - bool is_write) - { -- const BlockBackendPublic *blkp = blk_get_public(blk); -- return blkp->pending_reqs[is_write]; -+ return tgm->pending_reqs[is_write]; - } - --/* Return the next BlockBackend in the round-robin sequence with pending I/O -- * requests. -+/* Return the next ThrottleGroupMember in the round-robin sequence with pending -+ * I/O requests. - * - * This assumes that tg->lock is held. - * -- * @blk: the current BlockBackend -+ * @tgm: the current ThrottleGroupMember - * @is_write: the type of operation (read/write) -- * @ret: the next BlockBackend with pending requests, or blk if there is -- * none. -+ * @ret: the next ThrottleGroupMember with pending requests, or tgm if -+ * there is none. - */ --static BlockBackend *next_throttle_token(BlockBackend *blk, bool is_write) -+static ThrottleGroupMember *next_throttle_token(ThrottleGroupMember *tgm, -+ bool is_write) - { -- BlockBackendPublic *blkp = blk_get_public(blk); -- ThrottleGroup *tg = container_of(blkp->throttle_state, ThrottleGroup, ts); -- BlockBackend *token, *start; -+ ThrottleState *ts = tgm->throttle_state; -+ ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts); -+ ThrottleGroupMember *token, *start; - - start = token = tg->tokens[is_write]; - - /* get next bs round in round robin style */ -- token = throttle_group_next_blk(token); -- while (token != start && !blk_has_pending_reqs(token, is_write)) { -- token = throttle_group_next_blk(token); -+ token = throttle_group_next_tgm(token); -+ while (token != start && !tgm_has_pending_reqs(token, is_write)) { -+ token = throttle_group_next_tgm(token); - } - - /* If no IO are queued for scheduling on the next round robin token -- * then decide the token is the current bs because chances are -- * the current bs get the current request queued. -+ * then decide the token is the current tgm because chances are -+ * the current tgm got the current request queued. - */ -- if (token == start && !blk_has_pending_reqs(token, is_write)) { -- token = blk; -+ if (token == start && !tgm_has_pending_reqs(token, is_write)) { -+ token = tgm; - } - -- /* Either we return the original BB, or one with pending requests */ -- assert(token == blk || blk_has_pending_reqs(token, is_write)); -+ /* Either we return the original TGM, or one with pending requests */ -+ assert(token == tgm || tgm_has_pending_reqs(token, is_write)); - - return token; - } - --/* Check if the next I/O request for a BlockBackend needs to be throttled or -- * not. If there's no timer set in this group, set one and update the token -- * accordingly. -+/* Check if the next I/O request for a ThrottleGroupMember needs to be -+ * throttled or not. If there's no timer set in this group, set one and update -+ * the token accordingly. - * - * This assumes that tg->lock is held. - * -- * @blk: the current BlockBackend -+ * @tgm: the current ThrottleGroupMember - * @is_write: the type of operation (read/write) - * @ret: whether the I/O request needs to be throttled or not - */ --static bool throttle_group_schedule_timer(BlockBackend *blk, bool is_write) -+static bool throttle_group_schedule_timer(ThrottleGroupMember *tgm, -+ bool is_write) - { -- BlockBackendPublic *blkp = blk_get_public(blk); -- ThrottleState *ts = blkp->throttle_state; -- ThrottleTimers *tt = &blkp->throttle_timers; -+ ThrottleState *ts = tgm->throttle_state; - ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts); -+ ThrottleTimers *tt = &tgm->throttle_timers; - bool must_wait; - -- if (atomic_read(&blkp->io_limits_disabled)) { -+ if (atomic_read(&tgm->io_limits_disabled)) { - return false; - } - -@@ -258,30 +256,29 @@ static bool throttle_group_schedule_timer(BlockBackend *blk, bool is_write) - - must_wait = throttle_schedule_timer(ts, tt, is_write); - -- /* If a timer just got armed, set blk as the current token */ -+ /* If a timer just got armed, set tgm as the current token */ - if (must_wait) { -- tg->tokens[is_write] = blk; -+ tg->tokens[is_write] = tgm; - tg->any_timer_armed[is_write] = true; - } - - return must_wait; - } - --/* Start the next pending I/O request for a BlockBackend. Return whether -+/* Start the next pending I/O request for a ThrottleGroupMember. Return whether - * any request was actually pending. - * -- * @blk: the current BlockBackend -+ * @tgm: the current ThrottleGroupMember - * @is_write: the type of operation (read/write) - */ --static bool coroutine_fn throttle_group_co_restart_queue(BlockBackend *blk, -+static bool coroutine_fn throttle_group_co_restart_queue(ThrottleGroupMember *tgm, - bool is_write) - { -- BlockBackendPublic *blkp = blk_get_public(blk); - bool ret; - -- qemu_co_mutex_lock(&blkp->throttled_reqs_lock); -- ret = qemu_co_queue_next(&blkp->throttled_reqs[is_write]); -- qemu_co_mutex_unlock(&blkp->throttled_reqs_lock); -+ qemu_co_mutex_lock(&tgm->throttled_reqs_lock); -+ ret = qemu_co_queue_next(&tgm->throttled_reqs[is_write]); -+ qemu_co_mutex_unlock(&tgm->throttled_reqs_lock); - - return ret; - } -@@ -290,19 +287,19 @@ static bool coroutine_fn throttle_group_co_restart_queue(BlockBackend *blk, - * - * This assumes that tg->lock is held. - * -- * @blk: the current BlockBackend -+ * @tgm: the current ThrottleGroupMember - * @is_write: the type of operation (read/write) - */ --static void schedule_next_request(BlockBackend *blk, bool is_write) -+static void schedule_next_request(ThrottleGroupMember *tgm, bool is_write) - { -- BlockBackendPublic *blkp = blk_get_public(blk); -- ThrottleGroup *tg = container_of(blkp->throttle_state, ThrottleGroup, ts); -+ ThrottleState *ts = tgm->throttle_state; -+ ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts); - bool must_wait; -- BlockBackend *token; -+ ThrottleGroupMember *token; - - /* Check if there's any pending request to schedule next */ -- token = next_throttle_token(blk, is_write); -- if (!blk_has_pending_reqs(token, is_write)) { -+ token = next_throttle_token(tgm, is_write); -+ if (!tgm_has_pending_reqs(token, is_write)) { - return; - } - -@@ -311,12 +308,12 @@ static void schedule_next_request(BlockBackend *blk, bool is_write) - - /* If it doesn't have to wait, queue it for immediate execution */ - if (!must_wait) { -- /* Give preference to requests from the current blk */ -+ /* Give preference to requests from the current tgm */ - if (qemu_in_coroutine() && -- throttle_group_co_restart_queue(blk, is_write)) { -- token = blk; -+ throttle_group_co_restart_queue(tgm, is_write)) { -+ token = tgm; - } else { -- ThrottleTimers *tt = &blk_get_public(token)->throttle_timers; -+ ThrottleTimers *tt = &token->throttle_timers; - int64_t now = qemu_clock_get_ns(tg->clock_type); - timer_mod(tt->timers[is_write], now); - tg->any_timer_armed[is_write] = true; -@@ -329,76 +326,77 @@ static void schedule_next_request(BlockBackend *blk, bool is_write) - * if necessary, and schedule the next request using a round robin - * algorithm. - * -- * @blk: the current BlockBackend -+ * @tgm: the current ThrottleGroupMember - * @bytes: the number of bytes for this I/O - * @is_write: the type of operation (read/write) - */ --void coroutine_fn throttle_group_co_io_limits_intercept(BlockBackend *blk, -+void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember *tgm, - unsigned int bytes, - bool is_write) - { - bool must_wait; -- BlockBackend *token; -- -- BlockBackendPublic *blkp = blk_get_public(blk); -- ThrottleGroup *tg = container_of(blkp->throttle_state, ThrottleGroup, ts); -+ ThrottleGroupMember *token; -+ ThrottleGroup *tg = container_of(tgm->throttle_state, ThrottleGroup, ts); - qemu_mutex_lock(&tg->lock); - - /* First we check if this I/O has to be throttled. */ -- token = next_throttle_token(blk, is_write); -+ token = next_throttle_token(tgm, is_write); - must_wait = throttle_group_schedule_timer(token, is_write); - - /* Wait if there's a timer set or queued requests of this type */ -- if (must_wait || blkp->pending_reqs[is_write]) { -- blkp->pending_reqs[is_write]++; -+ if (must_wait || tgm->pending_reqs[is_write]) { -+ tgm->pending_reqs[is_write]++; - qemu_mutex_unlock(&tg->lock); -- qemu_co_mutex_lock(&blkp->throttled_reqs_lock); -- qemu_co_queue_wait(&blkp->throttled_reqs[is_write], -- &blkp->throttled_reqs_lock); -- qemu_co_mutex_unlock(&blkp->throttled_reqs_lock); -+ qemu_co_mutex_lock(&tgm->throttled_reqs_lock); -+ qemu_co_queue_wait(&tgm->throttled_reqs[is_write], -+ &tgm->throttled_reqs_lock); -+ qemu_co_mutex_unlock(&tgm->throttled_reqs_lock); - qemu_mutex_lock(&tg->lock); -- blkp->pending_reqs[is_write]--; -+ tgm->pending_reqs[is_write]--; - } - - /* The I/O will be executed, so do the accounting */ -- throttle_account(blkp->throttle_state, is_write, bytes); -+ throttle_account(tgm->throttle_state, is_write, bytes); - - /* Schedule the next request */ -- schedule_next_request(blk, is_write); -+ schedule_next_request(tgm, is_write); - - qemu_mutex_unlock(&tg->lock); - } - - typedef struct { -- BlockBackend *blk; -+ ThrottleGroupMember *tgm; - bool is_write; - } RestartData; - - static void coroutine_fn throttle_group_restart_queue_entry(void *opaque) - { - RestartData *data = opaque; -- BlockBackend *blk = data->blk; -+ ThrottleGroupMember *tgm = data->tgm; -+ ThrottleState *ts = tgm->throttle_state; -+ ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts); - bool is_write = data->is_write; -- BlockBackendPublic *blkp = blk_get_public(blk); -- ThrottleGroup *tg = container_of(blkp->throttle_state, ThrottleGroup, ts); - bool empty_queue; - -- empty_queue = !throttle_group_co_restart_queue(blk, is_write); -+ empty_queue = !throttle_group_co_restart_queue(tgm, is_write); - - /* If the request queue was empty then we have to take care of - * scheduling the next one */ - if (empty_queue) { - qemu_mutex_lock(&tg->lock); -- schedule_next_request(blk, is_write); -+ schedule_next_request(tgm, is_write); - qemu_mutex_unlock(&tg->lock); - } - } - --static void throttle_group_restart_queue(BlockBackend *blk, bool is_write) -+static void throttle_group_restart_queue(ThrottleGroupMember *tgm, bool is_write) - { -+ BlockBackendPublic *blkp = container_of(tgm, BlockBackendPublic, -+ throttle_group_member); -+ BlockBackend *blk = blk_by_public(blkp); - Coroutine *co; - RestartData rd = { -- .blk = blk, -+ .tgm = tgm, - .is_write = is_write - }; - -@@ -406,13 +404,11 @@ static void throttle_group_restart_queue(BlockBackend *blk, bool is_write) - aio_co_enter(blk_get_aio_context(blk), co); - } - --void throttle_group_restart_blk(BlockBackend *blk) -+void throttle_group_restart_tgm(ThrottleGroupMember *tgm) - { -- BlockBackendPublic *blkp = blk_get_public(blk); -- -- if (blkp->throttle_state) { -- throttle_group_restart_queue(blk, 0); -- throttle_group_restart_queue(blk, 1); -+ if (tgm->throttle_state) { -+ throttle_group_restart_queue(tgm, 0); -+ throttle_group_restart_queue(tgm, 1); - } - } - -@@ -420,32 +416,30 @@ void throttle_group_restart_blk(BlockBackend *blk) - * to throttle_config(), but guarantees atomicity within the - * throttling group. - * -- * @blk: a BlockBackend that is a member of the group -+ * @tgm: a ThrottleGroupMember that is a member of the group - * @cfg: the configuration to set - */ --void throttle_group_config(BlockBackend *blk, ThrottleConfig *cfg) -+void throttle_group_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg) - { -- BlockBackendPublic *blkp = blk_get_public(blk); -- ThrottleState *ts = blkp->throttle_state; -+ ThrottleState *ts = tgm->throttle_state; - ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts); - qemu_mutex_lock(&tg->lock); - throttle_config(ts, tg->clock_type, cfg); - qemu_mutex_unlock(&tg->lock); - -- throttle_group_restart_blk(blk); -+ throttle_group_restart_tgm(tgm); - } - - /* Get the throttle configuration from a particular group. Similar to - * throttle_get_config(), but guarantees atomicity within the - * throttling group. - * -- * @blk: a BlockBackend that is a member of the group -+ * @tgm: a ThrottleGroupMember that is a member of the group - * @cfg: the configuration will be written here - */ --void throttle_group_get_config(BlockBackend *blk, ThrottleConfig *cfg) -+void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg) - { -- BlockBackendPublic *blkp = blk_get_public(blk); -- ThrottleState *ts = blkp->throttle_state; -+ ThrottleState *ts = tgm->throttle_state; - ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts); - qemu_mutex_lock(&tg->lock); - throttle_get_config(ts, cfg); -@@ -461,7 +455,8 @@ void throttle_group_get_config(BlockBackend *blk, ThrottleConfig *cfg) - static void timer_cb(BlockBackend *blk, bool is_write) - { - BlockBackendPublic *blkp = blk_get_public(blk); -- ThrottleState *ts = blkp->throttle_state; -+ ThrottleGroupMember *tgm = &blkp->throttle_group_member; -+ ThrottleState *ts = tgm->throttle_state; - ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts); - - /* The timer has just been fired, so we can update the flag */ -@@ -470,7 +465,7 @@ static void timer_cb(BlockBackend *blk, bool is_write) - qemu_mutex_unlock(&tg->lock); - - /* Run the request that was waiting for this timer */ -- throttle_group_restart_queue(blk, is_write); -+ throttle_group_restart_queue(tgm, is_write); - } - - static void read_timer_cb(void *opaque) -@@ -483,32 +478,36 @@ static void write_timer_cb(void *opaque) - timer_cb(opaque, true); - } - --/* Register a BlockBackend in the throttling group, also initializing its -- * timers and updating its throttle_state pointer to point to it. If a -+/* Register a ThrottleGroupMember from the throttling group, also initializing -+ * its timers and updating its throttle_state pointer to point to it. If a - * throttling group with that name does not exist yet, it will be created. - * -- * @blk: the BlockBackend to insert -+ * @tgm: the ThrottleGroupMember to insert - * @groupname: the name of the group - */ --void throttle_group_register_blk(BlockBackend *blk, const char *groupname) -+void throttle_group_register_tgm(ThrottleGroupMember *tgm, -+ const char *groupname) - { - int i; -- BlockBackendPublic *blkp = blk_get_public(blk); -+ BlockBackendPublic *blkp = container_of(tgm, BlockBackendPublic, -+ throttle_group_member); -+ BlockBackend *blk = blk_by_public(blkp); - ThrottleState *ts = throttle_group_incref(groupname); - ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts); -- blkp->throttle_state = ts; -+ -+ tgm->throttle_state = ts; - - qemu_mutex_lock(&tg->lock); -- /* If the ThrottleGroup is new set this BlockBackend as the token */ -+ /* If the ThrottleGroup is new set this ThrottleGroupMember as the token */ - for (i = 0; i < 2; i++) { - if (!tg->tokens[i]) { -- tg->tokens[i] = blk; -+ tg->tokens[i] = tgm; - } - } - -- QLIST_INSERT_HEAD(&tg->head, blkp, round_robin); -+ QLIST_INSERT_HEAD(&tg->head, tgm, round_robin); - -- throttle_timers_init(&blkp->throttle_timers, -+ throttle_timers_init(&tgm->throttle_timers, - blk_get_aio_context(blk), - tg->clock_type, - read_timer_cb, -@@ -518,45 +517,46 @@ void throttle_group_register_blk(BlockBackend *blk, const char *groupname) - qemu_mutex_unlock(&tg->lock); - } - --/* Unregister a BlockBackend from its group, removing it from the list, -+/* Unregister a ThrottleGroupMember from its group, removing it from the list, - * destroying the timers and setting the throttle_state pointer to NULL. - * -- * The BlockBackend must not have pending throttled requests, so the caller has -- * to drain them first. -+ * The ThrottleGroupMember must not have pending throttled requests, so the -+ * caller has to drain them first. - * - * The group will be destroyed if it's empty after this operation. - * -- * @blk: the BlockBackend to remove -+ * @tgm the ThrottleGroupMember to remove - */ --void throttle_group_unregister_blk(BlockBackend *blk) -+void throttle_group_unregister_tgm(ThrottleGroupMember *tgm) - { -- BlockBackendPublic *blkp = blk_get_public(blk); -- ThrottleGroup *tg = container_of(blkp->throttle_state, ThrottleGroup, ts); -+ ThrottleState *ts = tgm->throttle_state; -+ ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts); -+ ThrottleGroupMember *token; - int i; - -- assert(blkp->pending_reqs[0] == 0 && blkp->pending_reqs[1] == 0); -- assert(qemu_co_queue_empty(&blkp->throttled_reqs[0])); -- assert(qemu_co_queue_empty(&blkp->throttled_reqs[1])); -+ assert(tgm->pending_reqs[0] == 0 && tgm->pending_reqs[1] == 0); -+ assert(qemu_co_queue_empty(&tgm->throttled_reqs[0])); -+ assert(qemu_co_queue_empty(&tgm->throttled_reqs[1])); - - qemu_mutex_lock(&tg->lock); - for (i = 0; i < 2; i++) { -- if (tg->tokens[i] == blk) { -- BlockBackend *token = throttle_group_next_blk(blk); -- /* Take care of the case where this is the last blk in the group */ -- if (token == blk) { -+ if (tg->tokens[i] == tgm) { -+ token = throttle_group_next_tgm(tgm); -+ /* Take care of the case where this is the last tgm in the group */ -+ if (token == tgm) { - token = NULL; - } - tg->tokens[i] = token; - } - } - -- /* remove the current blk from the list */ -- QLIST_REMOVE(blkp, round_robin); -- throttle_timers_destroy(&blkp->throttle_timers); -+ /* remove the current tgm from the list */ -+ QLIST_REMOVE(tgm, round_robin); -+ throttle_timers_destroy(&tgm->throttle_timers); - qemu_mutex_unlock(&tg->lock); - - throttle_group_unref(&tg->ts); -- blkp->throttle_state = NULL; -+ tgm->throttle_state = NULL; - } - - static void throttle_groups_init(void) -diff --git a/blockdev.c b/blockdev.c -index d54ea6f..0f063ec 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -2729,7 +2729,7 @@ void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp) - if (throttle_enabled(&cfg)) { - /* Enable I/O limits if they're not enabled yet, otherwise - * just update the throttling group. */ -- if (!blk_get_public(blk)->throttle_state) { -+ if (!blk_get_public(blk)->throttle_group_member.throttle_state) { - blk_io_limits_enable(blk, - arg->has_group ? arg->group : - arg->has_device ? arg->device : -@@ -2739,7 +2739,7 @@ void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp) - } - /* Set the new throttling configuration */ - blk_set_io_limits(blk, &cfg); -- } else if (blk_get_public(blk)->throttle_state) { -+ } else if (blk_get_public(blk)->throttle_group_member.throttle_state) { - /* If all throttling settings are set to 0, disable I/O limits */ - blk_io_limits_disable(blk); - } -diff --git a/include/block/throttle-groups.h b/include/block/throttle-groups.h -index d983d34..1a6bcda 100644 ---- a/include/block/throttle-groups.h -+++ b/include/block/throttle-groups.h -@@ -28,19 +28,44 @@ - #include "qemu/throttle.h" - #include "block/block_int.h" - --const char *throttle_group_get_name(BlockBackend *blk); -+/* The ThrottleGroupMember structure indicates membership in a ThrottleGroup -+ * and holds related data. -+ */ -+ -+typedef struct ThrottleGroupMember { -+ /* throttled_reqs_lock protects the CoQueues for throttled requests. */ -+ CoMutex throttled_reqs_lock; -+ CoQueue throttled_reqs[2]; -+ -+ /* Nonzero if the I/O limits are currently being ignored; generally -+ * it is zero. Accessed with atomic operations. -+ */ -+ unsigned int io_limits_disabled; -+ -+ /* The following fields are protected by the ThrottleGroup lock. -+ * See the ThrottleGroup documentation for details. -+ * throttle_state tells us if I/O limits are configured. */ -+ ThrottleState *throttle_state; -+ ThrottleTimers throttle_timers; -+ unsigned pending_reqs[2]; -+ QLIST_ENTRY(ThrottleGroupMember) round_robin; -+ -+} ThrottleGroupMember; -+ -+const char *throttle_group_get_name(ThrottleGroupMember *tgm); - - ThrottleState *throttle_group_incref(const char *name); - void throttle_group_unref(ThrottleState *ts); - --void throttle_group_config(BlockBackend *blk, ThrottleConfig *cfg); --void throttle_group_get_config(BlockBackend *blk, ThrottleConfig *cfg); -+void throttle_group_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg); -+void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg); - --void throttle_group_register_blk(BlockBackend *blk, const char *groupname); --void throttle_group_unregister_blk(BlockBackend *blk); --void throttle_group_restart_blk(BlockBackend *blk); -+void throttle_group_register_tgm(ThrottleGroupMember *tgm, -+ const char *groupname); -+void throttle_group_unregister_tgm(ThrottleGroupMember *tgm); -+void throttle_group_restart_tgm(ThrottleGroupMember *tgm); - --void coroutine_fn throttle_group_co_io_limits_intercept(BlockBackend *blk, -+void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember *tgm, - unsigned int bytes, - bool is_write); - -diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h -index aadc733..c4e52a5 100644 ---- a/include/sysemu/block-backend.h -+++ b/include/sysemu/block-backend.h -@@ -70,24 +70,10 @@ typedef struct BlockDevOps { - - /* This struct is embedded in (the private) BlockBackend struct and contains - * fields that must be public. This is in particular for QLIST_ENTRY() and -- * friends so that BlockBackends can be kept in lists outside block-backend.c */ -+ * friends so that BlockBackends can be kept in lists outside block-backend.c -+ * */ - typedef struct BlockBackendPublic { -- /* throttled_reqs_lock protects the CoQueues for throttled requests. */ -- CoMutex throttled_reqs_lock; -- CoQueue throttled_reqs[2]; -- -- /* Nonzero if the I/O limits are currently being ignored; generally -- * it is zero. Accessed with atomic operations. -- */ -- unsigned int io_limits_disabled; -- -- /* The following fields are protected by the ThrottleGroup lock. -- * See the ThrottleGroup documentation for details. -- * throttle_state tells us if I/O limits are configured. */ -- ThrottleState *throttle_state; -- ThrottleTimers throttle_timers; -- unsigned pending_reqs[2]; -- QLIST_ENTRY(BlockBackendPublic) round_robin; -+ ThrottleGroupMember throttle_group_member; - } BlockBackendPublic; - - BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm); -diff --git a/tests/test-throttle.c b/tests/test-throttle.c -index 768f11d..6e6d926 100644 ---- a/tests/test-throttle.c -+++ b/tests/test-throttle.c -@@ -592,6 +592,7 @@ static void test_groups(void) - ThrottleConfig cfg1, cfg2; - BlockBackend *blk1, *blk2, *blk3; - BlockBackendPublic *blkp1, *blkp2, *blkp3; -+ ThrottleGroupMember *tgm1, *tgm2, *tgm3; - - /* No actual I/O is performed on these devices */ - blk1 = blk_new(0, BLK_PERM_ALL); -@@ -602,21 +603,25 @@ static void test_groups(void) - blkp2 = blk_get_public(blk2); - blkp3 = blk_get_public(blk3); - -- g_assert(blkp1->throttle_state == NULL); -- g_assert(blkp2->throttle_state == NULL); -- g_assert(blkp3->throttle_state == NULL); -+ tgm1 = &blkp1->throttle_group_member; -+ tgm2 = &blkp2->throttle_group_member; -+ tgm3 = &blkp3->throttle_group_member; - -- throttle_group_register_blk(blk1, "bar"); -- throttle_group_register_blk(blk2, "foo"); -- throttle_group_register_blk(blk3, "bar"); -+ g_assert(tgm1->throttle_state == NULL); -+ g_assert(tgm2->throttle_state == NULL); -+ g_assert(tgm3->throttle_state == NULL); - -- g_assert(blkp1->throttle_state != NULL); -- g_assert(blkp2->throttle_state != NULL); -- g_assert(blkp3->throttle_state != NULL); -+ throttle_group_register_tgm(tgm1, "bar"); -+ throttle_group_register_tgm(tgm2, "foo"); -+ throttle_group_register_tgm(tgm3, "bar"); - -- g_assert(!strcmp(throttle_group_get_name(blk1), "bar")); -- g_assert(!strcmp(throttle_group_get_name(blk2), "foo")); -- g_assert(blkp1->throttle_state == blkp3->throttle_state); -+ g_assert(tgm1->throttle_state != NULL); -+ g_assert(tgm2->throttle_state != NULL); -+ g_assert(tgm3->throttle_state != NULL); -+ -+ g_assert(!strcmp(throttle_group_get_name(tgm1), "bar")); -+ g_assert(!strcmp(throttle_group_get_name(tgm2), "foo")); -+ g_assert(tgm1->throttle_state == tgm3->throttle_state); - - /* Setting the config of a group member affects the whole group */ - throttle_config_init(&cfg1); -@@ -624,29 +629,29 @@ static void test_groups(void) - cfg1.buckets[THROTTLE_BPS_WRITE].avg = 285000; - cfg1.buckets[THROTTLE_OPS_READ].avg = 20000; - cfg1.buckets[THROTTLE_OPS_WRITE].avg = 12000; -- throttle_group_config(blk1, &cfg1); -+ throttle_group_config(tgm1, &cfg1); - -- throttle_group_get_config(blk1, &cfg1); -- throttle_group_get_config(blk3, &cfg2); -+ throttle_group_get_config(tgm1, &cfg1); -+ throttle_group_get_config(tgm3, &cfg2); - g_assert(!memcmp(&cfg1, &cfg2, sizeof(cfg1))); - - cfg2.buckets[THROTTLE_BPS_READ].avg = 4547; - cfg2.buckets[THROTTLE_BPS_WRITE].avg = 1349; - cfg2.buckets[THROTTLE_OPS_READ].avg = 123; - cfg2.buckets[THROTTLE_OPS_WRITE].avg = 86; -- throttle_group_config(blk3, &cfg1); -+ throttle_group_config(tgm3, &cfg1); - -- throttle_group_get_config(blk1, &cfg1); -- throttle_group_get_config(blk3, &cfg2); -+ throttle_group_get_config(tgm1, &cfg1); -+ throttle_group_get_config(tgm3, &cfg2); - g_assert(!memcmp(&cfg1, &cfg2, sizeof(cfg1))); - -- throttle_group_unregister_blk(blk1); -- throttle_group_unregister_blk(blk2); -- throttle_group_unregister_blk(blk3); -+ throttle_group_unregister_tgm(tgm1); -+ throttle_group_unregister_tgm(tgm2); -+ throttle_group_unregister_tgm(tgm3); - -- g_assert(blkp1->throttle_state == NULL); -- g_assert(blkp2->throttle_state == NULL); -- g_assert(blkp3->throttle_state == NULL); -+ g_assert(tgm1->throttle_state == NULL); -+ g_assert(tgm2->throttle_state == NULL); -+ g_assert(tgm3->throttle_state == NULL); - } - - int main(int argc, char **argv) --- -1.8.3.1 - diff --git a/SOURCES/kvm-block-nbd-client-nbd_co_send_request-fix-return-code.patch b/SOURCES/kvm-block-nbd-client-nbd_co_send_request-fix-return-code.patch deleted file mode 100644 index 43c3192..0000000 --- a/SOURCES/kvm-block-nbd-client-nbd_co_send_request-fix-return-code.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 3f5ffd9dc9075dff3ab8052d5cfb0cdd2bfd1d7d Mon Sep 17 00:00:00 2001 -From: Eric Blake -Date: Fri, 6 Oct 2017 19:24:09 +0200 -Subject: [PATCH 17/34] block/nbd-client: nbd_co_send_request: fix return code - -RH-Author: Eric Blake -Message-id: <20171006192409.29915-5-eblake@redhat.com> -Patchwork-id: 76912 -O-Subject: [RHEV-7.5 qemu-kvm-rhev PATCH 4/4] block/nbd-client: nbd_co_send_request: fix return code -Bugzilla: 1482478 -RH-Acked-by: Max Reitz -RH-Acked-by: Laurent Vivier -RH-Acked-by: Stefan Hajnoczi - -From: Vladimir Sementsov-Ogievskiy - -It's incorrect to return success rc >= 0 if we skip qio_channel_writev_all() -call due to s->quit. - -Signed-off-by: Vladimir Sementsov-Ogievskiy -Reviewed-by: Eric Blake -Message-Id: <20170920124507.18841-4-vsementsov@virtuozzo.com> -Signed-off-by: Eric Blake -(cherry picked from commit a693437037328a95d815ad5aec37ac2f8e130e58) -Signed-off-by: Miroslav Rezanina ---- - block/nbd-client.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/block/nbd-client.c b/block/nbd-client.c -index ea728ff..ed48fcf 100644 ---- a/block/nbd-client.c -+++ b/block/nbd-client.c -@@ -161,6 +161,8 @@ static int nbd_co_send_request(BlockDriverState *bs, - if (ret != request->len) { - rc = -EIO; - } -+ } else if (rc >= 0) { -+ rc = -EIO; - } - qio_channel_set_cork(s->ioc, false); - } else { --- -1.8.3.1 - diff --git a/SOURCES/kvm-block-qapi-Add-qdev-field-to-query-blockstats-result.patch b/SOURCES/kvm-block-qapi-Add-qdev-field-to-query-blockstats-result.patch new file mode 100644 index 0000000..38a1ccb --- /dev/null +++ b/SOURCES/kvm-block-qapi-Add-qdev-field-to-query-blockstats-result.patch @@ -0,0 +1,111 @@ +From 95bfd60b406ed4cce708b5981d4bc3a007d0cec9 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 7 Aug 2018 14:03:59 +0200 +Subject: [PATCH 06/13] block/qapi: Add 'qdev' field to query-blockstats result + +RH-Author: Kevin Wolf +Message-id: <20180807140401.23995-2-kwolf@redhat.com> +Patchwork-id: 81666 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 1/3] block/qapi: Add 'qdev' field to query-blockstats result +Bugzilla: 1612114 +RH-Acked-by: John Snow +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Markus Armbruster + +Like for query-block, the client needs to identify which BlockBackend +the returned data is for. Anonymous BlockBackends are identified by the +device model they are attached to. Add a 'qdev' field that contains the +qdev ID or QOM path of the attached device model. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +(cherry picked from commit 5a9cb5a97f1e519f249d9ec482d498b78296b51d) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/qapi.c | 10 ++++++++++ + qapi/block-core.json | 14 ++++++++++---- + 2 files changed, 20 insertions(+), 4 deletions(-) + +diff --git a/block/qapi.c b/block/qapi.c +index e12968f..50f867d 100644 +--- a/block/qapi.c ++++ b/block/qapi.c +@@ -597,11 +597,21 @@ BlockStatsList *qmp_query_blockstats(bool has_query_nodes, + BlockStatsList *info = g_malloc0(sizeof(*info)); + AioContext *ctx = blk_get_aio_context(blk); + BlockStats *s; ++ char *qdev; + + aio_context_acquire(ctx); + s = bdrv_query_bds_stats(blk_bs(blk), true); + s->has_device = true; + s->device = g_strdup(blk_name(blk)); ++ ++ qdev = blk_get_attached_dev_id(blk); ++ if (qdev && *qdev) { ++ s->has_qdev = true; ++ s->qdev = qdev; ++ } else { ++ g_free(qdev); ++ } ++ + bdrv_query_blk_stats(s->stats, blk); + aio_context_release(ctx); + +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 8a00bec..c6b42eb 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -867,6 +867,9 @@ + # + # @node-name: The node name of the device. (Since 2.3) + # ++# @qdev: The qdev ID, or if no ID is assigned, the QOM path of the block ++# device. (since 3.0) ++# + # @stats: A @BlockDeviceStats for the device. + # + # @parent: This describes the file block device if it has one. +@@ -880,7 +883,7 @@ + # Since: 0.14.0 + ## + { 'struct': 'BlockStats', +- 'data': {'*device': 'str', '*node-name': 'str', ++ 'data': {'*device': 'str', '*qdev': 'str', '*node-name': 'str', + 'stats': 'BlockDeviceStats', + '*parent': 'BlockStats', + '*backing': 'BlockStats'} } +@@ -942,7 +945,8 @@ + # "idle_time_ns":2953431879, + # "account_invalid":true, + # "account_failed":false +-# } ++# }, ++# "qdev": "/machine/unattached/device[23]" + # }, + # { + # "device":"ide1-cd0", +@@ -960,7 +964,8 @@ + # "wr_merged":0, + # "account_invalid":false, + # "account_failed":false +-# } ++# }, ++# "qdev": "/machine/unattached/device[24]" + # }, + # { + # "device":"floppy0", +@@ -978,7 +983,8 @@ + # "wr_merged":0, + # "account_invalid":false, + # "account_failed":false +-# } ++# }, ++# "qdev": "/machine/unattached/device[16]" + # }, + # { + # "device":"sd0", +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-qapi-Include-anonymous-BBs-in-query-blockstats.patch b/SOURCES/kvm-block-qapi-Include-anonymous-BBs-in-query-blockstats.patch new file mode 100644 index 0000000..830a3fe --- /dev/null +++ b/SOURCES/kvm-block-qapi-Include-anonymous-BBs-in-query-blockstats.patch @@ -0,0 +1,52 @@ +From 50a74a6f33a66effb2c4f28e2c6ca8ca3041d312 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 7 Aug 2018 14:04:00 +0200 +Subject: [PATCH 07/13] block/qapi: Include anonymous BBs in query-blockstats + +RH-Author: Kevin Wolf +Message-id: <20180807140401.23995-3-kwolf@redhat.com> +Patchwork-id: 81664 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 2/3] block/qapi: Include anonymous BBs in query-blockstats +Bugzilla: 1612114 +RH-Acked-by: John Snow +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Markus Armbruster + +Consistent with query-block, query-blockstats should not only include +named BlockBackends, but also those that are anonymous, but belong to a +device model. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +(cherry picked from commit 567dcb31f23657fb71060067b0b1c9ac29110d16) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/qapi.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/block/qapi.c b/block/qapi.c +index 50f867d..339727f 100644 +--- a/block/qapi.c ++++ b/block/qapi.c +@@ -593,12 +593,16 @@ BlockStatsList *qmp_query_blockstats(bool has_query_nodes, + p_next = &info->next; + } + } else { +- for (blk = blk_next(NULL); blk; blk = blk_next(blk)) { ++ for (blk = blk_all_next(NULL); blk; blk = blk_all_next(blk)) { + BlockStatsList *info = g_malloc0(sizeof(*info)); + AioContext *ctx = blk_get_aio_context(blk); + BlockStats *s; + char *qdev; + ++ if (!*blk_name(blk) && !blk_get_attached_dev(blk)) { ++ continue; ++ } ++ + aio_context_acquire(ctx); + s = bdrv_query_bds_stats(blk_bs(blk), true); + s->has_device = true; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-qcow2-bitmap-fix-free_bitmap_clusters.patch b/SOURCES/kvm-block-qcow2-bitmap-fix-free_bitmap_clusters.patch new file mode 100644 index 0000000..bc3942b --- /dev/null +++ b/SOURCES/kvm-block-qcow2-bitmap-fix-free_bitmap_clusters.patch @@ -0,0 +1,46 @@ +From fb76c3aaa2e3d54b20fef63fcc64d2ff5a394b08 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 18 Jul 2018 22:54:44 +0200 +Subject: [PATCH 59/89] block/qcow2-bitmap: fix free_bitmap_clusters + +RH-Author: John Snow +Message-id: <20180718225511.14878-9-jsnow@redhat.com> +Patchwork-id: 81392 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 08/35] block/qcow2-bitmap: fix free_bitmap_clusters +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Vladimir Sementsov-Ogievskiy + +This assert may fail, because bitmap_table is not initialized. Just +drop it, as it's obvious, that bitmap_table_load sets bitmap_table +parameter only when returning zero. + +Reported-by: Pavel Butsykin +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-id: 20180608101225.2575-1-vsementsov@virtuozzo.com +Signed-off-by: Max Reitz +(cherry picked from commit 7eb24009dbf8102fc27d5459bec1cb8a932540c4) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/qcow2-bitmap.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c +index 6e93ec4..3e4e4e4 100644 +--- a/block/qcow2-bitmap.c ++++ b/block/qcow2-bitmap.c +@@ -254,7 +254,6 @@ static int free_bitmap_clusters(BlockDriverState *bs, Qcow2BitmapTable *tb) + + ret = bitmap_table_load(bs, tb, &bitmap_table); + if (ret < 0) { +- assert(bitmap_table == NULL); + return ret; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-qdict-Clean-up-qdict_crumple-a-bit.patch b/SOURCES/kvm-block-qdict-Clean-up-qdict_crumple-a-bit.patch new file mode 100644 index 0000000..d425ce0 --- /dev/null +++ b/SOURCES/kvm-block-qdict-Clean-up-qdict_crumple-a-bit.patch @@ -0,0 +1,91 @@ +From 096bb1ca93a22a0ca874b76c3ad03385a5667f41 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Mon, 18 Jun 2018 08:43:24 +0200 +Subject: [PATCH 17/54] block-qdict: Clean up qdict_crumple() a bit + +RH-Author: Markus Armbruster +Message-id: <20180618084330.30009-18-armbru@redhat.com> +Patchwork-id: 80729 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 17/23] block-qdict: Clean up qdict_crumple() a bit +Bugzilla: 1557995 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +When you mix scalar and non-scalar keys, whether you get an "already +set as scalar" or an "already set as dict" error depends on qdict +iteration order. Neither message makes much sense. Replace by +""Cannot mix scalar and non-scalar keys". This is similar to the +message we get for mixing list and non-list keys. + +I find qdict_crumple()'s first loop hard to understand. Rearrange it +and add a comment. + +Signed-off-by: Markus Armbruster +Signed-off-by: Kevin Wolf +(cherry picked from commit 3692b5d76819e573dedc9004c4b2b0e3dad83530) +Signed-off-by: Miroslav Rezanina +--- + qobject/block-qdict.c | 32 ++++++++++++++++---------------- + 1 file changed, 16 insertions(+), 16 deletions(-) + +diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c +index a4e1c8d..36cf58a 100644 +--- a/qobject/block-qdict.c ++++ b/qobject/block-qdict.c +@@ -403,7 +403,7 @@ static int qdict_is_list(QDict *maybe_list, Error **errp) + QObject *qdict_crumple(const QDict *src, Error **errp) + { + const QDictEntry *ent; +- QDict *two_level, *multi_level = NULL; ++ QDict *two_level, *multi_level = NULL, *child_dict; + QObject *dst = NULL, *child; + size_t i; + char *prefix = NULL; +@@ -422,28 +422,28 @@ QObject *qdict_crumple(const QDict *src, Error **errp) + } + + qdict_split_flat_key(ent->key, &prefix, &suffix); +- + child = qdict_get(two_level, prefix); ++ child_dict = qobject_to(QDict, child); ++ ++ if (child) { ++ /* ++ * If @child_dict, then all previous keys with this prefix ++ * had a suffix. If @suffix, this one has one as well, ++ * and we're good, else there's a clash. ++ */ ++ if (!child_dict || !suffix) { ++ error_setg(errp, "Cannot mix scalar and non-scalar keys"); ++ goto error; ++ } ++ } ++ + if (suffix) { +- QDict *child_dict = qobject_to(QDict, child); + if (!child_dict) { +- if (child) { +- error_setg(errp, "Key %s prefix is already set as a scalar", +- prefix); +- goto error; +- } +- + child_dict = qdict_new(); +- qdict_put_obj(two_level, prefix, QOBJECT(child_dict)); ++ qdict_put(two_level, prefix, child_dict); + } +- + qdict_put_obj(child_dict, suffix, qobject_ref(ent->value)); + } else { +- if (child) { +- error_setg(errp, "Key %s prefix is already set as a dict", +- prefix); +- goto error; +- } + qdict_put_obj(two_level, prefix, qobject_ref(ent->value)); + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-qdict-Simplify-qdict_flatten_qdict.patch b/SOURCES/kvm-block-qdict-Simplify-qdict_flatten_qdict.patch new file mode 100644 index 0000000..7e46be6 --- /dev/null +++ b/SOURCES/kvm-block-qdict-Simplify-qdict_flatten_qdict.patch @@ -0,0 +1,82 @@ +From 637b26d723d07ce653b22c7882037db6661d0bbf Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Mon, 18 Jun 2018 08:43:22 +0200 +Subject: [PATCH 15/54] block-qdict: Simplify qdict_flatten_qdict() + +RH-Author: Markus Armbruster +Message-id: <20180618084330.30009-16-armbru@redhat.com> +Patchwork-id: 80723 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 15/23] block-qdict: Simplify qdict_flatten_qdict() +Bugzilla: 1557995 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +There's no need to restart the loop. We don't elsewhere, e.g. in +qdict_extract_subqdict(), qdict_join() and qemu_opts_absorb_qdict(). +Simplify accordingly. + +Signed-off-by: Markus Armbruster +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit eb0e0f7d3d4a9c585421d05b19ca71df5d69fc47) +Signed-off-by: Miroslav Rezanina +--- + qobject/block-qdict.c | 18 +++--------------- + 1 file changed, 3 insertions(+), 15 deletions(-) + +diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c +index 41f39ab..f32df34 100644 +--- a/qobject/block-qdict.c ++++ b/qobject/block-qdict.c +@@ -89,16 +89,13 @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix) + QObject *value; + const QDictEntry *entry, *next; + char *new_key; +- bool delete; + + entry = qdict_first(qdict); + + while (entry != NULL) { +- + next = qdict_next(qdict, entry); + value = qdict_entry_value(entry); + new_key = NULL; +- delete = false; + + if (prefix) { + new_key = g_strdup_printf("%s.%s", prefix, entry->key); +@@ -109,27 +106,18 @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix) + * itself disappears. */ + qdict_flatten_qdict(qobject_to(QDict, value), target, + new_key ? new_key : entry->key); +- delete = true; ++ qdict_del(qdict, entry->key); + } else if (qobject_type(value) == QTYPE_QLIST) { + qdict_flatten_qlist(qobject_to(QList, value), target, + new_key ? new_key : entry->key); +- delete = true; ++ qdict_del(qdict, entry->key); + } else if (prefix) { + /* All other objects are moved to the target unchanged. */ + qdict_put_obj(target, new_key, qobject_ref(value)); +- delete = true; +- } +- +- g_free(new_key); +- +- if (delete) { + qdict_del(qdict, entry->key); +- +- /* Restart loop after modifying the iterated QDict */ +- entry = qdict_first(qdict); +- continue; + } + ++ g_free(new_key); + entry = next; + } + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-qdict-Simplify-qdict_is_list-some.patch b/SOURCES/kvm-block-qdict-Simplify-qdict_is_list-some.patch new file mode 100644 index 0000000..3ea641d --- /dev/null +++ b/SOURCES/kvm-block-qdict-Simplify-qdict_is_list-some.patch @@ -0,0 +1,69 @@ +From 80e27f95206b2df21b9a53dd3a0956246de495db Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Mon, 18 Jun 2018 08:43:25 +0200 +Subject: [PATCH 18/54] block-qdict: Simplify qdict_is_list() some + +RH-Author: Markus Armbruster +Message-id: <20180618084330.30009-19-armbru@redhat.com> +Patchwork-id: 80741 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 18/23] block-qdict: Simplify qdict_is_list() some +Bugzilla: 1557995 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Signed-off-by: Markus Armbruster +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit c78b8cfbfd53737353dc94dfb99c57d72ce31ab5) +Signed-off-by: Miroslav Rezanina +--- + qobject/block-qdict.c | 27 +++++++++++---------------- + 1 file changed, 11 insertions(+), 16 deletions(-) + +diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c +index 36cf58a..e51a3d2 100644 +--- a/qobject/block-qdict.c ++++ b/qobject/block-qdict.c +@@ -317,27 +317,22 @@ static int qdict_is_list(QDict *maybe_list, Error **errp) + + for (ent = qdict_first(maybe_list); ent != NULL; + ent = qdict_next(maybe_list, ent)) { ++ int is_index = !qemu_strtoi64(ent->key, NULL, 10, &val); + +- if (qemu_strtoi64(ent->key, NULL, 10, &val) == 0) { +- if (is_list == -1) { +- is_list = 1; +- } else if (!is_list) { +- error_setg(errp, +- "Cannot mix list and non-list keys"); +- return -1; +- } ++ if (is_list == -1) { ++ is_list = is_index; ++ } ++ ++ if (is_index != is_list) { ++ error_setg(errp, "Cannot mix list and non-list keys"); ++ return -1; ++ } ++ ++ if (is_index) { + len++; + if (val > max) { + max = val; + } +- } else { +- if (is_list == -1) { +- is_list = 0; +- } else if (is_list) { +- error_setg(errp, +- "Cannot mix list and non-list keys"); +- return -1; +- } + } + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-qdict-Tweak-qdict_flatten_qdict-qdict_flatten_.patch b/SOURCES/kvm-block-qdict-Tweak-qdict_flatten_qdict-qdict_flatten_.patch new file mode 100644 index 0000000..af99836 --- /dev/null +++ b/SOURCES/kvm-block-qdict-Tweak-qdict_flatten_qdict-qdict_flatten_.patch @@ -0,0 +1,77 @@ +From a558dd841d434d95377dadc45c79d1de1b6f8d2d Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Mon, 18 Jun 2018 08:43:23 +0200 +Subject: [PATCH 16/54] block-qdict: Tweak qdict_flatten_qdict(), + qdict_flatten_qlist() + +RH-Author: Markus Armbruster +Message-id: <20180618084330.30009-17-armbru@redhat.com> +Patchwork-id: 80725 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 16/23] block-qdict: Tweak qdict_flatten_qdict(), qdict_flatten_qlist() +Bugzilla: 1557995 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +qdict_flatten_qdict() skips copying scalars from @qdict to @target +when the two are the same. Fair enough, but it uses a non-obvious +test for "same". Replace it by the obvious one. While there, improve +comments. + +Signed-off-by: Markus Armbruster +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit f1b34a248e9785e8cc0d28a1685d2cf4460bb256) +Signed-off-by: Miroslav Rezanina +--- + qobject/block-qdict.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c +index f32df34..a4e1c8d 100644 +--- a/qobject/block-qdict.c ++++ b/qobject/block-qdict.c +@@ -71,12 +71,15 @@ static void qdict_flatten_qlist(QList *qlist, QDict *target, const char *prefix) + value = qlist_entry_obj(entry); + new_key = g_strdup_printf("%s.%i", prefix, i); + ++ /* ++ * Flatten non-empty QDict and QList recursively into @target, ++ * copy other objects to @target ++ */ + if (qobject_type(value) == QTYPE_QDICT) { + qdict_flatten_qdict(qobject_to(QDict, value), target, new_key); + } else if (qobject_type(value) == QTYPE_QLIST) { + qdict_flatten_qlist(qobject_to(QList, value), target, new_key); + } else { +- /* All other types are moved to the target unchanged. */ + qdict_put_obj(target, new_key, qobject_ref(value)); + } + +@@ -101,9 +104,11 @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix) + new_key = g_strdup_printf("%s.%s", prefix, entry->key); + } + ++ /* ++ * Flatten non-empty QDict and QList recursively into @target, ++ * copy other objects to @target ++ */ + if (qobject_type(value) == QTYPE_QDICT) { +- /* Entries of QDicts are processed recursively, the QDict object +- * itself disappears. */ + qdict_flatten_qdict(qobject_to(QDict, value), target, + new_key ? new_key : entry->key); + qdict_del(qdict, entry->key); +@@ -111,8 +116,7 @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix) + qdict_flatten_qlist(qobject_to(QList, value), target, + new_key ? new_key : entry->key); + qdict_del(qdict, entry->key); +- } else if (prefix) { +- /* All other objects are moved to the target unchanged. */ ++ } else if (target != qdict) { + qdict_put_obj(target, new_key, qobject_ref(value)); + qdict_del(qdict, entry->key); + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-quorum-Support-BDRV_REQ_WRITE_UNCHANGED.patch b/SOURCES/kvm-block-quorum-Support-BDRV_REQ_WRITE_UNCHANGED.patch new file mode 100644 index 0000000..8803221 --- /dev/null +++ b/SOURCES/kvm-block-quorum-Support-BDRV_REQ_WRITE_UNCHANGED.patch @@ -0,0 +1,114 @@ +From 34e748aa7dc2215fd2d8f03e491f1a2a450ba5d0 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 16:12:08 +0200 +Subject: [PATCH 32/54] block/quorum: Support BDRV_REQ_WRITE_UNCHANGED + +RH-Author: Max Reitz +Message-id: <20180618161212.14444-7-mreitz@redhat.com> +Patchwork-id: 80770 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 06/10] block/quorum: Support BDRV_REQ_WRITE_UNCHANGED +Bugzilla: 1518738 +RH-Acked-by: John Snow +RH-Acked-by: Kevin Wolf +RH-Acked-by: Miroslav Rezanina + +We just need to forward it to quorum's children (except in case of a +rewrite because of corruption), but for that we first have to support +flags in child requests at all. + +Signed-off-by: Max Reitz +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Alberto Garcia +Message-id: 20180421132929.21610-6-mreitz@redhat.com +Reviewed-by: Kevin Wolf +Signed-off-by: Max Reitz +(cherry picked from commit 1b1a920b713af6af795d49d0e3d2a8a65020bf82) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + block/quorum.c | 19 +++++++++++++------ + 1 file changed, 13 insertions(+), 6 deletions(-) + +diff --git a/block/quorum.c b/block/quorum.c +index f1f39ba..0d90a02 100644 +--- a/block/quorum.c ++++ b/block/quorum.c +@@ -116,6 +116,7 @@ struct QuorumAIOCB { + /* Request metadata */ + uint64_t offset; + uint64_t bytes; ++ int flags; + + QEMUIOVector *qiov; /* calling IOV */ + +@@ -158,7 +159,8 @@ static bool quorum_64bits_compare(QuorumVoteValue *a, QuorumVoteValue *b) + static QuorumAIOCB *quorum_aio_get(BlockDriverState *bs, + QEMUIOVector *qiov, + uint64_t offset, +- uint64_t bytes) ++ uint64_t bytes, ++ int flags) + { + BDRVQuorumState *s = bs->opaque; + QuorumAIOCB *acb = g_new(QuorumAIOCB, 1); +@@ -169,6 +171,7 @@ static QuorumAIOCB *quorum_aio_get(BlockDriverState *bs, + .bs = bs, + .offset = offset, + .bytes = bytes, ++ .flags = flags, + .qiov = qiov, + .votes.compare = quorum_sha256_compare, + .votes.vote_list = QLIST_HEAD_INITIALIZER(acb.votes.vote_list), +@@ -272,9 +275,11 @@ static void quorum_rewrite_entry(void *opaque) + BDRVQuorumState *s = acb->bs->opaque; + + /* Ignore any errors, it's just a correction attempt for already +- * corrupted data. */ ++ * corrupted data. ++ * Mask out BDRV_REQ_WRITE_UNCHANGED because this overwrites the ++ * area with different data from the other children. */ + bdrv_co_pwritev(s->children[co->idx], acb->offset, acb->bytes, +- acb->qiov, 0); ++ acb->qiov, acb->flags & ~BDRV_REQ_WRITE_UNCHANGED); + + /* Wake up the caller after the last rewrite */ + acb->rewrite_count--; +@@ -674,7 +679,7 @@ static int quorum_co_preadv(BlockDriverState *bs, uint64_t offset, + uint64_t bytes, QEMUIOVector *qiov, int flags) + { + BDRVQuorumState *s = bs->opaque; +- QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes); ++ QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes, flags); + int ret; + + acb->is_read = true; +@@ -700,7 +705,7 @@ static void write_quorum_entry(void *opaque) + + sacb->bs = s->children[i]->bs; + sacb->ret = bdrv_co_pwritev(s->children[i], acb->offset, acb->bytes, +- acb->qiov, 0); ++ acb->qiov, acb->flags); + if (sacb->ret == 0) { + acb->success_count++; + } else { +@@ -720,7 +725,7 @@ static int quorum_co_pwritev(BlockDriverState *bs, uint64_t offset, + uint64_t bytes, QEMUIOVector *qiov, int flags) + { + BDRVQuorumState *s = bs->opaque; +- QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes); ++ QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes, flags); + int i, ret; + + for (i = 0; i < s->num_children; i++) { +@@ -962,6 +967,8 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags, + } + s->next_child_index = s->num_children; + ++ bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED; ++ + g_free(opened); + goto exit; + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-rbd-Attempt-to-parse-legacy-filenames.patch b/SOURCES/kvm-block-rbd-Attempt-to-parse-legacy-filenames.patch new file mode 100644 index 0000000..5601076 --- /dev/null +++ b/SOURCES/kvm-block-rbd-Attempt-to-parse-legacy-filenames.patch @@ -0,0 +1,117 @@ +From ba592010c82c1302c611f6023d4abda24ee3b689 Mon Sep 17 00:00:00 2001 +From: Jeffrey Cody +Date: Wed, 12 Sep 2018 13:45:43 +0200 +Subject: [PATCH 04/49] block/rbd: Attempt to parse legacy filenames + +RH-Author: Jeffrey Cody +Message-id: <819d451b971d87d47d5bc73feaf20be5bf42e6ef.1536759805.git.jcody@redhat.com> +Patchwork-id: 82140 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 2/3] block/rbd: Attempt to parse legacy filenames +Bugzilla: 1610605 +RH-Acked-by: Eric Blake +RH-Acked-by: John Snow +RH-Acked-by: Fam Zheng + +When we converted rbd to get rid of the older key/value-centric +encoding format, we broke compatibility with image files with backing +file strings encoded in the old format. + +This leaves a bit of an ugly conundrum, and a hacky solution. + +If the initial attempt to parse the "proper" options fails, it assumes +that we may have an older key/value encoded filename. Fall back to +attempting to parse the filename, and extract the required options from +it. If that fails, pass along the original error message. + +We do not support mixed modern usage alongside legacy keyvalue pair +usage. + +A deprecation warning has been added, although care should be taken +when actually deprecating since the impact is not limited to +commandline or qapi usage, but also opening existing images. + +Reviewed-by: Eric Blake +Signed-off-by: Jeff Cody +Message-id: 15b332e5432ad069441f7275a46080f465d789a0.1536704901.git.jcody@redhat.com +Signed-off-by: Jeff Cody +(cherry picked from commit 866543123c3cd190c44b4caf7c9ed82844c0bcc6) +Signed-off-by: Jeff Cody +Signed-off-by: Miroslav Rezanina +--- + block/rbd.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 51 insertions(+), 2 deletions(-) + +diff --git a/block/rbd.c b/block/rbd.c +index 1e4d339..8f81fbc 100644 +--- a/block/rbd.c ++++ b/block/rbd.c +@@ -671,6 +671,33 @@ static int qemu_rbd_convert_options(QDict *options, BlockdevOptionsRbd **opts, + return 0; + } + ++static int qemu_rbd_attempt_legacy_options(QDict *options, ++ BlockdevOptionsRbd **opts, ++ char **keypairs) ++{ ++ char *filename; ++ int r; ++ ++ filename = g_strdup(qdict_get_try_str(options, "filename")); ++ if (!filename) { ++ return -EINVAL; ++ } ++ qdict_del(options, "filename"); ++ ++ qemu_rbd_parse_filename(filename, options, NULL); ++ ++ /* keypairs freed by caller */ ++ *keypairs = g_strdup(qdict_get_try_str(options, "=keyvalue-pairs")); ++ if (*keypairs) { ++ qdict_del(options, "=keyvalue-pairs"); ++ } ++ ++ r = qemu_rbd_convert_options(options, opts, NULL); ++ ++ g_free(filename); ++ return r; ++} ++ + static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags, + Error **errp) + { +@@ -693,8 +720,30 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags, + + r = qemu_rbd_convert_options(options, &opts, &local_err); + if (local_err) { +- error_propagate(errp, local_err); +- goto out; ++ /* If keypairs are present, that means some options are present in ++ * the modern option format. Don't attempt to parse legacy option ++ * formats, as we won't support mixed usage. */ ++ if (keypairs) { ++ error_propagate(errp, local_err); ++ goto out; ++ } ++ ++ /* If the initial attempt to convert and process the options failed, ++ * we may be attempting to open an image file that has the rbd options ++ * specified in the older format consisting of all key/value pairs ++ * encoded in the filename. Go ahead and attempt to parse the ++ * filename, and see if we can pull out the required options. */ ++ r = qemu_rbd_attempt_legacy_options(options, &opts, &keypairs); ++ if (r < 0) { ++ error_propagate(errp, local_err); ++ goto out; ++ } ++ /* Take care whenever deciding to actually deprecate; once this ability ++ * is removed, we will not be able to open any images with legacy-styled ++ * backing image strings. */ ++ error_report("RBD options encoded in the filename as keyvalue pairs " ++ "is deprecated. Future versions may cease to parse " ++ "these options in the future."); + } + + /* Remove the processed options from the QDict (the visitor processes +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-rbd-add-iotest-for-rbd-legacy-keyvalue-filenam.patch b/SOURCES/kvm-block-rbd-add-iotest-for-rbd-legacy-keyvalue-filenam.patch new file mode 100644 index 0000000..db3bc3b --- /dev/null +++ b/SOURCES/kvm-block-rbd-add-iotest-for-rbd-legacy-keyvalue-filenam.patch @@ -0,0 +1,136 @@ +From b97181cd18e5427bcabcb5afe83f25b5352ec248 Mon Sep 17 00:00:00 2001 +From: Jeffrey Cody +Date: Wed, 12 Sep 2018 13:45:44 +0200 +Subject: [PATCH 05/49] block/rbd: add iotest for rbd legacy keyvalue filename + parsing + +RH-Author: Jeffrey Cody +Message-id: <5da98ec8bde6bc41a6848d526e689038ec8c8007.1536759805.git.jcody@redhat.com> +Patchwork-id: 82142 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 3/3] block/rbd: add iotest for rbd legacy keyvalue filename parsing +Bugzilla: 1610605 +RH-Acked-by: Eric Blake +RH-Acked-by: John Snow +RH-Acked-by: Fam Zheng + +This is a small test that will check for the ability to parse +both legacy and modern options for rbd. + +The way the test is set up is for failure to occur, but without +having to wait to timeout on a non-existent rbd server. The error +messages in the success path show that the arguments were parsed. + +The failure behavior prior to the patch series that has this test, is +qemu-img complaining about mandatory options (e.g. 'pool') not being +provided. + +Reviewed-by: Eric Blake +Signed-off-by: Jeff Cody +Message-id: f830580e339b974a83ed4870d11adcdc17f49a47.1536704901.git.jcody@redhat.com +Signed-off-by: Jeff Cody +(cherry picked from commit 4ea3b5e9136c39515750534b01c0ed8edaddfcd7) +Signed-off-by: Jeff Cody +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/231 | 62 ++++++++++++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/231.out | 9 +++++++ + tests/qemu-iotests/group | 1 + + 3 files changed, 72 insertions(+) + create mode 100755 tests/qemu-iotests/231 + create mode 100644 tests/qemu-iotests/231.out + +diff --git a/tests/qemu-iotests/231 b/tests/qemu-iotests/231 +new file mode 100755 +index 0000000..3e28370 +--- /dev/null ++++ b/tests/qemu-iotests/231 +@@ -0,0 +1,62 @@ ++#!/bin/bash ++# ++# Test legacy and modern option parsing for rbd/ceph. This will not ++# actually connect to a ceph server, but rather looks for the appropriate ++# error message that indicates we parsed the options correctly. ++# ++# Copyright (C) 2018 Red Hat, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++ ++# creator ++owner=jcody@redhat.com ++ ++seq=`basename $0` ++echo "QA output created by $seq" ++ ++here=`pwd` ++status=1 # failure is the default! ++ ++_cleanup() ++{ ++ rm "${BOGUS_CONF}" ++} ++trap "_cleanup; exit \$status" 0 1 2 3 15 ++ ++# get standard environment, filters and checks ++. ./common.rc ++. ./common.filter ++ ++_supported_fmt generic ++_supported_proto rbd ++_supported_os Linux ++ ++BOGUS_CONF=${TEST_DIR}/ceph-$$.conf ++touch "${BOGUS_CONF}" ++ ++_filter_conf() ++{ ++ sed -e "s#$BOGUS_CONF#BOGUS_CONF#g" ++} ++ ++# We expect this to fail, with no monitor ip provided and a null conf file. Just want it ++# to fail in the right way. ++$QEMU_IMG info "json:{'file.driver':'rbd','file.filename':'rbd:rbd/bogus:conf=${BOGUS_CONF}'}" 2>&1 | _filter_conf ++$QEMU_IMG info "json:{'file.driver':'rbd','file.pool':'rbd','file.image':'bogus','file.conf':'${BOGUS_CONF}'}" 2>&1 | _filter_conf ++ ++# success, all done ++echo "*** done" ++rm -f $seq.full ++status=0 +diff --git a/tests/qemu-iotests/231.out b/tests/qemu-iotests/231.out +new file mode 100644 +index 0000000..579ba11 +--- /dev/null ++++ b/tests/qemu-iotests/231.out +@@ -0,0 +1,9 @@ ++QA output created by 231 ++qemu-img: RBD options encoded in the filename as keyvalue pairs is deprecated. Future versions may cease to parse these options in the future. ++unable to get monitor info from DNS SRV with service name: ceph-mon ++no monitors specified to connect to. ++qemu-img: Could not open 'json:{'file.driver':'rbd','file.filename':'rbd:rbd/bogus:conf=BOGUS_CONF'}': error connecting: No such file or directory ++unable to get monitor info from DNS SRV with service name: ceph-mon ++no monitors specified to connect to. ++qemu-img: Could not open 'json:{'file.driver':'rbd','file.pool':'rbd','file.image':'bogus','file.conf':'BOGUS_CONF'}': error connecting: No such file or directory ++*** done +diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group +index 3817d28..06a7107 100644 +--- a/tests/qemu-iotests/group ++++ b/tests/qemu-iotests/group +@@ -224,3 +224,4 @@ + 226 auto quick + 227 auto quick + 229 auto quick ++231 auto quick +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-rbd-pull-out-qemu_rbd_convert_options.patch b/SOURCES/kvm-block-rbd-pull-out-qemu_rbd_convert_options.patch new file mode 100644 index 0000000..8b136d2 --- /dev/null +++ b/SOURCES/kvm-block-rbd-pull-out-qemu_rbd_convert_options.patch @@ -0,0 +1,93 @@ +From 0b239ab1df3f430f6d1163dc9571e89b99939812 Mon Sep 17 00:00:00 2001 +From: Jeffrey Cody +Date: Wed, 12 Sep 2018 13:45:42 +0200 +Subject: [PATCH 03/49] block/rbd: pull out qemu_rbd_convert_options + +RH-Author: Jeffrey Cody +Message-id: <695a2a1c89a6bfd5076d050f5396aa7937e00cc5.1536759805.git.jcody@redhat.com> +Patchwork-id: 82143 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/3] block/rbd: pull out qemu_rbd_convert_options +Bugzilla: 1610605 +RH-Acked-by: Eric Blake +RH-Acked-by: John Snow +RH-Acked-by: Fam Zheng + +Code movement to pull the conversion from Qdict to BlockdevOptionsRbd +into a helper function. + +Reviewed-by: Eric Blake +Reviewed-by: John Snow +Signed-off-by: Jeff Cody +Message-id: 5b49a980f2cde6610ab1df41bb0277d00b5db893.1536704901.git.jcody@redhat.com +Signed-off-by: Jeff Cody +(cherry picked from commit 862e99966b5b59c107255fa806af40cf00ecacec) +Signed-off-by: Jeff Cody +Signed-off-by: Miroslav Rezanina +--- + block/rbd.c | 36 ++++++++++++++++++++++++------------ + 1 file changed, 24 insertions(+), 12 deletions(-) + +diff --git a/block/rbd.c b/block/rbd.c +index b93046b..1e4d339 100644 +--- a/block/rbd.c ++++ b/block/rbd.c +@@ -648,12 +648,34 @@ failed_opts: + return r; + } + ++static int qemu_rbd_convert_options(QDict *options, BlockdevOptionsRbd **opts, ++ Error **errp) ++{ ++ Visitor *v; ++ Error *local_err = NULL; ++ ++ /* Convert the remaining options into a QAPI object */ ++ v = qobject_input_visitor_new_flat_confused(options, errp); ++ if (!v) { ++ return -EINVAL; ++ } ++ ++ visit_type_BlockdevOptionsRbd(v, NULL, opts, &local_err); ++ visit_free(v); ++ ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ + static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags, + Error **errp) + { + BDRVRBDState *s = bs->opaque; + BlockdevOptionsRbd *opts = NULL; +- Visitor *v; + const QDictEntry *e; + Error *local_err = NULL; + char *keypairs, *secretid; +@@ -669,19 +691,9 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags, + qdict_del(options, "password-secret"); + } + +- /* Convert the remaining options into a QAPI object */ +- v = qobject_input_visitor_new_flat_confused(options, errp); +- if (!v) { +- r = -EINVAL; +- goto out; +- } +- +- visit_type_BlockdevOptionsRbd(v, NULL, &opts, &local_err); +- visit_free(v); +- ++ r = qemu_rbd_convert_options(options, &opts, &local_err); + if (local_err) { + error_propagate(errp, local_err); +- r = -EINVAL; + goto out; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-rename-bdrv_co_drain-to-bdrv_co_drain_begin.patch b/SOURCES/kvm-block-rename-bdrv_co_drain-to-bdrv_co_drain_begin.patch deleted file mode 100644 index 3c18713..0000000 --- a/SOURCES/kvm-block-rename-bdrv_co_drain-to-bdrv_co_drain_begin.patch +++ /dev/null @@ -1,108 +0,0 @@ -From 5185df6533f3e1f3c428e6d7b11a1fe372d0357b Mon Sep 17 00:00:00 2001 -From: Jeffrey Cody -Date: Thu, 30 Nov 2017 22:49:06 +0100 -Subject: [PATCH 02/21] block: rename bdrv_co_drain to bdrv_co_drain_begin - -RH-Author: Jeffrey Cody -Message-id: -Patchwork-id: 78039 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 02/11] block: rename bdrv_co_drain to bdrv_co_drain_begin -Bugzilla: 1506531 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: John Snow - -From: Manos Pitsidianakis - -Reviewed-by: Stefan Hajnoczi -Reviewed-by: Fam Zheng -Signed-off-by: Manos Pitsidianakis -Reviewed-by: Stefan Hajnoczi -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit f8ea8dacf0de636e2c0f13b90c0d75db97dc9b44) -Signed-off-by: Jeff Cody -Signed-off-by: Miroslav Rezanina ---- - block/io.c | 4 ++-- - block/qed.c | 6 +++--- - include/block/block_int.h | 4 ++-- - 3 files changed, 7 insertions(+), 7 deletions(-) - -diff --git a/block/io.c b/block/io.c -index 93fb802..3a717bc 100644 ---- a/block/io.c -+++ b/block/io.c -@@ -162,7 +162,7 @@ static void coroutine_fn bdrv_drain_invoke_entry(void *opaque) - BlockDriverState *bs = data->bs; - - if (data->begin) { -- bs->drv->bdrv_co_drain(bs); -+ bs->drv->bdrv_co_drain_begin(bs); - } else { - bs->drv->bdrv_co_drain_end(bs); - } -@@ -176,7 +176,7 @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin) - { - BdrvCoDrainData data = { .bs = bs, .done = false, .begin = begin}; - -- if (!bs->drv || (begin && !bs->drv->bdrv_co_drain) || -+ if (!bs->drv || (begin && !bs->drv->bdrv_co_drain_begin) || - (!begin && !bs->drv->bdrv_co_drain_end)) { - return; - } -diff --git a/block/qed.c b/block/qed.c -index dc54bf4..62d12db 100644 ---- a/block/qed.c -+++ b/block/qed.c -@@ -265,7 +265,7 @@ static bool qed_plug_allocating_write_reqs(BDRVQEDState *s) - assert(!s->allocating_write_reqs_plugged); - if (s->allocating_acb != NULL) { - /* Another allocating write came concurrently. This cannot happen -- * from bdrv_qed_co_drain, but it can happen when the timer runs. -+ * from bdrv_qed_co_drain_begin, but it can happen when the timer runs. - */ - qemu_co_mutex_unlock(&s->table_lock); - return false; -@@ -358,7 +358,7 @@ static void bdrv_qed_attach_aio_context(BlockDriverState *bs, - } - } - --static void coroutine_fn bdrv_qed_co_drain(BlockDriverState *bs) -+static void coroutine_fn bdrv_qed_co_drain_begin(BlockDriverState *bs) - { - BDRVQEDState *s = bs->opaque; - -@@ -1608,7 +1608,7 @@ static BlockDriver bdrv_qed = { - .bdrv_check = bdrv_qed_check, - .bdrv_detach_aio_context = bdrv_qed_detach_aio_context, - .bdrv_attach_aio_context = bdrv_qed_attach_aio_context, -- .bdrv_co_drain = bdrv_qed_co_drain, -+ .bdrv_co_drain_begin = bdrv_qed_co_drain_begin, - }; - - static void bdrv_qed_init(void) -diff --git a/include/block/block_int.h b/include/block/block_int.h -index 98d02ba..e02d540 100644 ---- a/include/block/block_int.h -+++ b/include/block/block_int.h -@@ -320,7 +320,7 @@ struct BlockDriver { - int (*bdrv_probe_geometry)(BlockDriverState *bs, HDGeometry *geo); - - /** -- * bdrv_co_drain is called if implemented in the beginning of a -+ * bdrv_co_drain_begin is called if implemented in the beginning of a - * drain operation to drain and stop any internal sources of requests in - * the driver. - * bdrv_co_drain_end is called if implemented at the end of the drain. -@@ -329,7 +329,7 @@ struct BlockDriver { - * requests, or toggle an internal state. After the end of the drain new - * requests will continue normally. - */ -- void coroutine_fn (*bdrv_co_drain)(BlockDriverState *bs); -+ void coroutine_fn (*bdrv_co_drain_begin)(BlockDriverState *bs); - void coroutine_fn (*bdrv_co_drain_end)(BlockDriverState *bs); - - void (*bdrv_add_child)(BlockDriverState *parent, BlockDriverState *child, --- -1.8.3.1 - diff --git a/SOURCES/kvm-block-reopen-Queue-children-after-their-parents.patch b/SOURCES/kvm-block-reopen-Queue-children-after-their-parents.patch deleted file mode 100644 index 2aecc46..0000000 --- a/SOURCES/kvm-block-reopen-Queue-children-after-their-parents.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 32f7f67152cf7ffe36917a2c436eb89871dcee92 Mon Sep 17 00:00:00 2001 -From: Kevin Wolf -Date: Mon, 4 Dec 2017 12:10:04 +0100 -Subject: [PATCH 33/36] block: reopen: Queue children after their parents - -RH-Author: Kevin Wolf -Message-id: <20171204121007.12964-6-kwolf@redhat.com> -Patchwork-id: 78107 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 5/8] block: reopen: Queue children after their parents -Bugzilla: 1492178 -RH-Acked-by: Fam Zheng -RH-Acked-by: Max Reitz -RH-Acked-by: Jeffrey Cody - -We will calculate the required new permissions in the prepare stage of a -reopen. Required permissions of children can be influenced by the -changes made to their parents, but parents are independent from their -children. This means that permissions need to be calculated top-down. In -order to achieve this, queue parents before their children rather than -queuing the children first. - -Signed-off-by: Kevin Wolf -Reviewed-by: Eric Blake -(cherry picked from commit 1857c97b76af02537b954c86dab066503950a4fd) -Signed-off-by: Miroslav Rezanina ---- - block.c | 26 +++++++++++++------------- - 1 file changed, 13 insertions(+), 13 deletions(-) - -diff --git a/block.c b/block.c -index 5cce274..0a7e2c6 100644 ---- a/block.c -+++ b/block.c -@@ -2767,6 +2767,19 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, - flags |= BDRV_O_ALLOW_RDWR; - } - -+ if (!bs_entry) { -+ bs_entry = g_new0(BlockReopenQueueEntry, 1); -+ QSIMPLEQ_INSERT_TAIL(bs_queue, bs_entry, entry); -+ } else { -+ QDECREF(bs_entry->state.options); -+ QDECREF(bs_entry->state.explicit_options); -+ } -+ -+ bs_entry->state.bs = bs; -+ bs_entry->state.options = options; -+ bs_entry->state.explicit_options = explicit_options; -+ bs_entry->state.flags = flags; -+ - QLIST_FOREACH(child, &bs->children, next) { - QDict *new_child_options; - char *child_key_dot; -@@ -2786,19 +2799,6 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, - child->role, options, flags); - } - -- if (!bs_entry) { -- bs_entry = g_new0(BlockReopenQueueEntry, 1); -- QSIMPLEQ_INSERT_TAIL(bs_queue, bs_entry, entry); -- } else { -- QDECREF(bs_entry->state.options); -- QDECREF(bs_entry->state.explicit_options); -- } -- -- bs_entry->state.bs = bs; -- bs_entry->state.options = options; -- bs_entry->state.explicit_options = explicit_options; -- bs_entry->state.flags = flags; -- - return bs_queue; - } - --- -1.8.3.1 - diff --git a/SOURCES/kvm-block-split-flags-in-copy_range.patch b/SOURCES/kvm-block-split-flags-in-copy_range.patch new file mode 100644 index 0000000..ba8198a --- /dev/null +++ b/SOURCES/kvm-block-split-flags-in-copy_range.patch @@ -0,0 +1,466 @@ +From 86b0f689bdc89a928f41ba737b43079df6574359 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Tue, 24 Jul 2018 13:01:08 +0200 +Subject: [PATCH 71/89] block: split flags in copy_range + +RH-Author: John Snow +Message-id: <20180718225511.14878-21-jsnow@redhat.com> +Patchwork-id: 81415 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 20/35] block: split flags in copy_range +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Vladimir Sementsov-Ogievskiy + +Pass read flags and write flags separately. This is needed to handle +coming BDRV_REQ_NO_SERIALISING clearly in following patches. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: Fam Zheng +Signed-off-by: Kevin Wolf +(cherry picked from commit 67b51fb998c697afb5d744066fcbde53e04fe941) +Signed-off-by: John Snow +--- + block/backup.c | 2 +- + block/block-backend.c | 5 +++-- + block/file-posix.c | 21 +++++++++++-------- + block/io.c | 46 +++++++++++++++++++++++------------------- + block/iscsi.c | 9 ++++++--- + block/qcow2.c | 20 +++++++++--------- + block/raw-format.c | 24 ++++++++++++++-------- + include/block/block.h | 3 ++- + include/block/block_int.h | 14 +++++++++---- + include/sysemu/block-backend.h | 3 ++- + qemu-img.c | 2 +- + 11 files changed, 90 insertions(+), 59 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index adb3cbd..369155a 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -163,7 +163,7 @@ static int coroutine_fn backup_cow_with_offload(BackupBlockJob *job, + hbitmap_reset(job->copy_bitmap, start / job->cluster_size, + nr_clusters); + ret = blk_co_copy_range(blk, start, job->target, start, nbytes, +- is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0); ++ is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0, 0); + if (ret < 0) { + trace_backup_do_cow_copy_range_fail(job, start, ret); + hbitmap_set(job->copy_bitmap, start / job->cluster_size, +diff --git a/block/block-backend.c b/block/block-backend.c +index a469fc6..2262506 100644 +--- a/block/block-backend.c ++++ b/block/block-backend.c +@@ -2244,7 +2244,8 @@ void blk_unregister_buf(BlockBackend *blk, void *host) + + int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in, + BlockBackend *blk_out, int64_t off_out, +- int bytes, BdrvRequestFlags flags) ++ int bytes, BdrvRequestFlags read_flags, ++ BdrvRequestFlags write_flags) + { + int r; + r = blk_check_byte_request(blk_in, off_in, bytes); +@@ -2257,5 +2258,5 @@ int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in, + } + return bdrv_co_copy_range(blk_in->root, off_in, + blk_out->root, off_out, +- bytes, flags); ++ bytes, read_flags, write_flags); + } +diff --git a/block/file-posix.c b/block/file-posix.c +index 06ec67d..c12cdb7 100644 +--- a/block/file-posix.c ++++ b/block/file-posix.c +@@ -2476,18 +2476,23 @@ static void raw_abort_perm_update(BlockDriverState *bs) + raw_handle_perm_lock(bs, RAW_PL_ABORT, 0, 0, NULL); + } + +-static int coroutine_fn raw_co_copy_range_from(BlockDriverState *bs, +- BdrvChild *src, uint64_t src_offset, +- BdrvChild *dst, uint64_t dst_offset, +- uint64_t bytes, BdrvRequestFlags flags) ++static int coroutine_fn raw_co_copy_range_from( ++ BlockDriverState *bs, BdrvChild *src, uint64_t src_offset, ++ BdrvChild *dst, uint64_t dst_offset, uint64_t bytes, ++ BdrvRequestFlags read_flags, BdrvRequestFlags write_flags) + { +- return bdrv_co_copy_range_to(src, src_offset, dst, dst_offset, bytes, flags); ++ return bdrv_co_copy_range_to(src, src_offset, dst, dst_offset, bytes, ++ read_flags, write_flags); + } + + static int coroutine_fn raw_co_copy_range_to(BlockDriverState *bs, +- BdrvChild *src, uint64_t src_offset, +- BdrvChild *dst, uint64_t dst_offset, +- uint64_t bytes, BdrvRequestFlags flags) ++ BdrvChild *src, ++ uint64_t src_offset, ++ BdrvChild *dst, ++ uint64_t dst_offset, ++ uint64_t bytes, ++ BdrvRequestFlags read_flags, ++ BdrvRequestFlags write_flags) + { + BDRVRawState *s = bs->opaque; + BDRVRawState *src_s; +diff --git a/block/io.c b/block/io.c +index f8de42f..2d04289 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -2841,13 +2841,11 @@ void bdrv_unregister_buf(BlockDriverState *bs, void *host) + } + } + +-static int coroutine_fn bdrv_co_copy_range_internal(BdrvChild *src, +- uint64_t src_offset, +- BdrvChild *dst, +- uint64_t dst_offset, +- uint64_t bytes, +- BdrvRequestFlags flags, +- bool recurse_src) ++static int coroutine_fn bdrv_co_copy_range_internal( ++ BdrvChild *src, uint64_t src_offset, BdrvChild *dst, ++ uint64_t dst_offset, uint64_t bytes, ++ BdrvRequestFlags read_flags, BdrvRequestFlags write_flags, ++ bool recurse_src) + { + BdrvTrackedRequest req; + int ret; +@@ -2860,8 +2858,8 @@ static int coroutine_fn bdrv_co_copy_range_internal(BdrvChild *src, + if (ret) { + return ret; + } +- if (flags & BDRV_REQ_ZERO_WRITE) { +- return bdrv_co_pwrite_zeroes(dst, dst_offset, bytes, flags); ++ if (write_flags & BDRV_REQ_ZERO_WRITE) { ++ return bdrv_co_pwrite_zeroes(dst, dst_offset, bytes, write_flags); + } + + if (!src || !src->bs) { +@@ -2883,14 +2881,15 @@ static int coroutine_fn bdrv_co_copy_range_internal(BdrvChild *src, + tracked_request_begin(&req, src->bs, src_offset, bytes, + BDRV_TRACKED_READ); + +- if (!(flags & BDRV_REQ_NO_SERIALISING)) { ++ if (!(read_flags & BDRV_REQ_NO_SERIALISING)) { + wait_serialising_requests(&req); + } + + ret = src->bs->drv->bdrv_co_copy_range_from(src->bs, + src, src_offset, + dst, dst_offset, +- bytes, flags); ++ bytes, ++ read_flags, write_flags); + + tracked_request_end(&req); + bdrv_dec_in_flight(src->bs); +@@ -2899,15 +2898,15 @@ static int coroutine_fn bdrv_co_copy_range_internal(BdrvChild *src, + tracked_request_begin(&req, dst->bs, dst_offset, bytes, + BDRV_TRACKED_WRITE); + +- /* BDRV_REQ_NO_SERIALISING is only for read operation, +- * so we ignore it in flags. +- */ ++ /* BDRV_REQ_NO_SERIALISING is only for read operation */ ++ assert(!(write_flags & BDRV_REQ_NO_SERIALISING)); + wait_serialising_requests(&req); + + ret = dst->bs->drv->bdrv_co_copy_range_to(dst->bs, + src, src_offset, + dst, dst_offset, +- bytes, flags); ++ bytes, ++ read_flags, write_flags); + + tracked_request_end(&req); + bdrv_dec_in_flight(dst->bs); +@@ -2922,10 +2921,12 @@ static int coroutine_fn bdrv_co_copy_range_internal(BdrvChild *src, + * semantics. */ + int coroutine_fn bdrv_co_copy_range_from(BdrvChild *src, uint64_t src_offset, + BdrvChild *dst, uint64_t dst_offset, +- uint64_t bytes, BdrvRequestFlags flags) ++ uint64_t bytes, ++ BdrvRequestFlags read_flags, ++ BdrvRequestFlags write_flags) + { + return bdrv_co_copy_range_internal(src, src_offset, dst, dst_offset, +- bytes, flags, true); ++ bytes, read_flags, write_flags, true); + } + + /* Copy range from @src to @dst. +@@ -2934,19 +2935,22 @@ int coroutine_fn bdrv_co_copy_range_from(BdrvChild *src, uint64_t src_offset, + * semantics. */ + int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, uint64_t src_offset, + BdrvChild *dst, uint64_t dst_offset, +- uint64_t bytes, BdrvRequestFlags flags) ++ uint64_t bytes, ++ BdrvRequestFlags read_flags, ++ BdrvRequestFlags write_flags) + { + return bdrv_co_copy_range_internal(src, src_offset, dst, dst_offset, +- bytes, flags, false); ++ bytes, read_flags, write_flags, false); + } + + int coroutine_fn bdrv_co_copy_range(BdrvChild *src, uint64_t src_offset, + BdrvChild *dst, uint64_t dst_offset, +- uint64_t bytes, BdrvRequestFlags flags) ++ uint64_t bytes, BdrvRequestFlags read_flags, ++ BdrvRequestFlags write_flags) + { + return bdrv_co_copy_range_from(src, src_offset, + dst, dst_offset, +- bytes, flags); ++ bytes, read_flags, write_flags); + } + + static void bdrv_parent_cb_resize(BlockDriverState *bs) +diff --git a/block/iscsi.c b/block/iscsi.c +index 5047e83..2b45458 100644 +--- a/block/iscsi.c ++++ b/block/iscsi.c +@@ -2193,9 +2193,11 @@ static int coroutine_fn iscsi_co_copy_range_from(BlockDriverState *bs, + BdrvChild *dst, + uint64_t dst_offset, + uint64_t bytes, +- BdrvRequestFlags flags) ++ BdrvRequestFlags read_flags, ++ BdrvRequestFlags write_flags) + { +- return bdrv_co_copy_range_to(src, src_offset, dst, dst_offset, bytes, flags); ++ return bdrv_co_copy_range_to(src, src_offset, dst, dst_offset, bytes, ++ read_flags, write_flags); + } + + static struct scsi_task *iscsi_xcopy_task(int param_len) +@@ -2332,7 +2334,8 @@ static int coroutine_fn iscsi_co_copy_range_to(BlockDriverState *bs, + BdrvChild *dst, + uint64_t dst_offset, + uint64_t bytes, +- BdrvRequestFlags flags) ++ BdrvRequestFlags read_flags, ++ BdrvRequestFlags write_flags) + { + IscsiLun *dst_lun = dst->bs->opaque; + IscsiLun *src_lun; +diff --git a/block/qcow2.c b/block/qcow2.c +index e171a99..1ea7203 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -3248,13 +3248,14 @@ static int coroutine_fn + qcow2_co_copy_range_from(BlockDriverState *bs, + BdrvChild *src, uint64_t src_offset, + BdrvChild *dst, uint64_t dst_offset, +- uint64_t bytes, BdrvRequestFlags flags) ++ uint64_t bytes, BdrvRequestFlags read_flags, ++ BdrvRequestFlags write_flags) + { + BDRVQcow2State *s = bs->opaque; + int ret; + unsigned int cur_bytes; /* number of bytes in current iteration */ + BdrvChild *child = NULL; +- BdrvRequestFlags cur_flags; ++ BdrvRequestFlags cur_write_flags; + + assert(!bs->encrypted); + qemu_co_mutex_lock(&s->lock); +@@ -3263,7 +3264,7 @@ qcow2_co_copy_range_from(BlockDriverState *bs, + uint64_t copy_offset = 0; + /* prepare next request */ + cur_bytes = MIN(bytes, INT_MAX); +- cur_flags = flags; ++ cur_write_flags = write_flags; + + ret = qcow2_get_cluster_offset(bs, src_offset, &cur_bytes, ©_offset); + if (ret < 0) { +@@ -3275,20 +3276,20 @@ qcow2_co_copy_range_from(BlockDriverState *bs, + if (bs->backing && bs->backing->bs) { + int64_t backing_length = bdrv_getlength(bs->backing->bs); + if (src_offset >= backing_length) { +- cur_flags |= BDRV_REQ_ZERO_WRITE; ++ cur_write_flags |= BDRV_REQ_ZERO_WRITE; + } else { + child = bs->backing; + cur_bytes = MIN(cur_bytes, backing_length - src_offset); + copy_offset = src_offset; + } + } else { +- cur_flags |= BDRV_REQ_ZERO_WRITE; ++ cur_write_flags |= BDRV_REQ_ZERO_WRITE; + } + break; + + case QCOW2_CLUSTER_ZERO_PLAIN: + case QCOW2_CLUSTER_ZERO_ALLOC: +- cur_flags |= BDRV_REQ_ZERO_WRITE; ++ cur_write_flags |= BDRV_REQ_ZERO_WRITE; + break; + + case QCOW2_CLUSTER_COMPRESSED: +@@ -3312,7 +3313,7 @@ qcow2_co_copy_range_from(BlockDriverState *bs, + ret = bdrv_co_copy_range_from(child, + copy_offset, + dst, dst_offset, +- cur_bytes, cur_flags); ++ cur_bytes, read_flags, cur_write_flags); + qemu_co_mutex_lock(&s->lock); + if (ret < 0) { + goto out; +@@ -3333,7 +3334,8 @@ static int coroutine_fn + qcow2_co_copy_range_to(BlockDriverState *bs, + BdrvChild *src, uint64_t src_offset, + BdrvChild *dst, uint64_t dst_offset, +- uint64_t bytes, BdrvRequestFlags flags) ++ uint64_t bytes, BdrvRequestFlags read_flags, ++ BdrvRequestFlags write_flags) + { + BDRVQcow2State *s = bs->opaque; + int offset_in_cluster; +@@ -3377,7 +3379,7 @@ qcow2_co_copy_range_to(BlockDriverState *bs, + ret = bdrv_co_copy_range_to(src, src_offset, + bs->file, + cluster_offset + offset_in_cluster, +- cur_bytes, flags); ++ cur_bytes, read_flags, write_flags); + qemu_co_mutex_lock(&s->lock); + if (ret < 0) { + goto fail; +diff --git a/block/raw-format.c b/block/raw-format.c +index b78da56..a359198 100644 +--- a/block/raw-format.c ++++ b/block/raw-format.c +@@ -498,9 +498,13 @@ static int raw_probe_geometry(BlockDriverState *bs, HDGeometry *geo) + } + + static int coroutine_fn raw_co_copy_range_from(BlockDriverState *bs, +- BdrvChild *src, uint64_t src_offset, +- BdrvChild *dst, uint64_t dst_offset, +- uint64_t bytes, BdrvRequestFlags flags) ++ BdrvChild *src, ++ uint64_t src_offset, ++ BdrvChild *dst, ++ uint64_t dst_offset, ++ uint64_t bytes, ++ BdrvRequestFlags read_flags, ++ BdrvRequestFlags write_flags) + { + int ret; + +@@ -509,13 +513,17 @@ static int coroutine_fn raw_co_copy_range_from(BlockDriverState *bs, + return ret; + } + return bdrv_co_copy_range_from(bs->file, src_offset, dst, dst_offset, +- bytes, flags); ++ bytes, read_flags, write_flags); + } + + static int coroutine_fn raw_co_copy_range_to(BlockDriverState *bs, +- BdrvChild *src, uint64_t src_offset, +- BdrvChild *dst, uint64_t dst_offset, +- uint64_t bytes, BdrvRequestFlags flags) ++ BdrvChild *src, ++ uint64_t src_offset, ++ BdrvChild *dst, ++ uint64_t dst_offset, ++ uint64_t bytes, ++ BdrvRequestFlags read_flags, ++ BdrvRequestFlags write_flags) + { + int ret; + +@@ -524,7 +532,7 @@ static int coroutine_fn raw_co_copy_range_to(BlockDriverState *bs, + return ret; + } + return bdrv_co_copy_range_to(src, src_offset, bs->file, dst_offset, bytes, +- flags); ++ read_flags, write_flags); + } + + BlockDriver bdrv_raw = { +diff --git a/include/block/block.h b/include/block/block.h +index 716fb5b..409db21 100644 +--- a/include/block/block.h ++++ b/include/block/block.h +@@ -661,5 +661,6 @@ void bdrv_unregister_buf(BlockDriverState *bs, void *host); + **/ + int coroutine_fn bdrv_co_copy_range(BdrvChild *src, uint64_t src_offset, + BdrvChild *dst, uint64_t dst_offset, +- uint64_t bytes, BdrvRequestFlags flags); ++ uint64_t bytes, BdrvRequestFlags read_flags, ++ BdrvRequestFlags write_flags); + #endif +diff --git a/include/block/block_int.h b/include/block/block_int.h +index 27e168f..b05cf11 100644 +--- a/include/block/block_int.h ++++ b/include/block/block_int.h +@@ -220,7 +220,8 @@ struct BlockDriver { + BdrvChild *dst, + uint64_t dst_offset, + uint64_t bytes, +- BdrvRequestFlags flags); ++ BdrvRequestFlags read_flags, ++ BdrvRequestFlags write_flags); + + /* Map [offset, offset + nbytes) range onto a child of bs to copy data to, + * and invoke bdrv_co_copy_range_to(child, src, ...), or perform the copy +@@ -236,7 +237,8 @@ struct BlockDriver { + BdrvChild *dst, + uint64_t dst_offset, + uint64_t bytes, +- BdrvRequestFlags flags); ++ BdrvRequestFlags read_flags, ++ BdrvRequestFlags write_flags); + + /* + * Building block for bdrv_block_status[_above] and +@@ -1125,10 +1127,14 @@ void blockdev_close_all_bdrv_states(void); + + int coroutine_fn bdrv_co_copy_range_from(BdrvChild *src, uint64_t src_offset, + BdrvChild *dst, uint64_t dst_offset, +- uint64_t bytes, BdrvRequestFlags flags); ++ uint64_t bytes, ++ BdrvRequestFlags read_flags, ++ BdrvRequestFlags write_flags); + int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, uint64_t src_offset, + BdrvChild *dst, uint64_t dst_offset, +- uint64_t bytes, BdrvRequestFlags flags); ++ uint64_t bytes, ++ BdrvRequestFlags read_flags, ++ BdrvRequestFlags write_flags); + + int refresh_total_sectors(BlockDriverState *bs, int64_t hint); + +diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h +index 8d03d49..830d873 100644 +--- a/include/sysemu/block-backend.h ++++ b/include/sysemu/block-backend.h +@@ -234,6 +234,7 @@ void blk_unregister_buf(BlockBackend *blk, void *host); + + int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in, + BlockBackend *blk_out, int64_t off_out, +- int bytes, BdrvRequestFlags flags); ++ int bytes, BdrvRequestFlags read_flags, ++ BdrvRequestFlags write_flags); + + #endif +diff --git a/qemu-img.c b/qemu-img.c +index b2ef54e..eaee6d6 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -1786,7 +1786,7 @@ static int coroutine_fn convert_co_copy_range(ImgConvertState *s, int64_t sector + + ret = blk_co_copy_range(blk, offset, s->target, + sector_num << BDRV_SECTOR_BITS, +- n << BDRV_SECTOR_BITS, 0); ++ n << BDRV_SECTOR_BITS, 0, 0); + if (ret < 0) { + return ret; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-stream-add-block-job-creation-flags.patch b/SOURCES/kvm-block-stream-add-block-job-creation-flags.patch new file mode 100644 index 0000000..2b09163 --- /dev/null +++ b/SOURCES/kvm-block-stream-add-block-job-creation-flags.patch @@ -0,0 +1,100 @@ +From 360e16997de84bddd37f5262f33d98b96b8aae2f Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 10 Sep 2018 18:17:50 +0200 +Subject: [PATCH 12/25] block/stream: add block job creation flags + +RH-Author: John Snow +Message-id: <20180910181803.11781-13-jsnow@redhat.com> +Patchwork-id: 82089 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 12/25] block/stream: add block job creation flags +Bugzilla: 1626061 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Add support for taking and passing forward job creation flags. + +Signed-off-by: John Snow +Reviewed-by: Max Reitz +Reviewed-by: Jeff Cody +Message-id: 20180906130225.5118-4-jsnow@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit 764cffd288722a4799e7cae0eb679d80fd636fdc) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/stream.c | 5 +++-- + blockdev.c | 3 ++- + include/block/block_int.h | 5 ++++- + 3 files changed, 9 insertions(+), 4 deletions(-) + +diff --git a/block/stream.c b/block/stream.c +index 67e1e72..700eb23 100644 +--- a/block/stream.c ++++ b/block/stream.c +@@ -214,7 +214,8 @@ static const BlockJobDriver stream_job_driver = { + + void stream_start(const char *job_id, BlockDriverState *bs, + BlockDriverState *base, const char *backing_file_str, +- int64_t speed, BlockdevOnError on_error, Error **errp) ++ int creation_flags, int64_t speed, ++ BlockdevOnError on_error, Error **errp) + { + StreamBlockJob *s; + BlockDriverState *iter; +@@ -236,7 +237,7 @@ void stream_start(const char *job_id, BlockDriverState *bs, + BLK_PERM_GRAPH_MOD, + BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED | + BLK_PERM_WRITE, +- speed, JOB_DEFAULT, NULL, NULL, errp); ++ speed, creation_flags, NULL, NULL, errp); + if (!s) { + goto fail; + } +diff --git a/blockdev.c b/blockdev.c +index 5d38e17..c4a1801 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -3280,6 +3280,7 @@ void qmp_block_stream(bool has_job_id, const char *job_id, const char *device, + AioContext *aio_context; + Error *local_err = NULL; + const char *base_name = NULL; ++ int job_flags = JOB_DEFAULT; + + if (!has_on_error) { + on_error = BLOCKDEV_ON_ERROR_REPORT; +@@ -3342,7 +3343,7 @@ void qmp_block_stream(bool has_job_id, const char *job_id, const char *device, + base_name = has_backing_file ? backing_file : base_name; + + stream_start(has_job_id ? job_id : NULL, bs, base_bs, base_name, +- has_speed ? speed : 0, on_error, &local_err); ++ job_flags, has_speed ? speed : 0, on_error, &local_err); + if (local_err) { + error_propagate(errp, local_err); + goto out; +diff --git a/include/block/block_int.h b/include/block/block_int.h +index 07517cf..341cbe8 100644 +--- a/include/block/block_int.h ++++ b/include/block/block_int.h +@@ -929,6 +929,8 @@ int is_windows_drive(const char *filename); + * flatten the whole backing file chain onto @bs. + * @backing_file_str: The file name that will be written to @bs as the + * the new backing file if the job completes. Ignored if @base is %NULL. ++ * @creation_flags: Flags that control the behavior of the Job lifetime. ++ * See @BlockJobCreateFlags + * @speed: The maximum speed, in bytes per second, or 0 for unlimited. + * @on_error: The action to take upon error. + * @errp: Error object. +@@ -942,7 +944,8 @@ int is_windows_drive(const char *filename); + */ + void stream_start(const char *job_id, BlockDriverState *bs, + BlockDriverState *base, const char *backing_file_str, +- int64_t speed, BlockdevOnError on_error, Error **errp); ++ int creation_flags, int64_t speed, ++ BlockdevOnError on_error, Error **errp); + + /** + * commit_start: +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-stream-refactor-stream-to-use-job-callbacks.patch b/SOURCES/kvm-block-stream-refactor-stream-to-use-job-callbacks.patch new file mode 100644 index 0000000..2e030ec --- /dev/null +++ b/SOURCES/kvm-block-stream-refactor-stream-to-use-job-callbacks.patch @@ -0,0 +1,94 @@ +From eca4127792a09e2bf10fdabc5780a2294a2d07da Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 10 Sep 2018 18:17:54 +0200 +Subject: [PATCH 16/25] block/stream: refactor stream to use job callbacks + +RH-Author: John Snow +Message-id: <20180910181803.11781-17-jsnow@redhat.com> +Patchwork-id: 82093 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 16/25] block/stream: refactor stream to use job callbacks +Bugzilla: 1626061 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Signed-off-by: John Snow +Reviewed-by: Max Reitz +Message-id: 20180906130225.5118-8-jsnow@redhat.com +Reviewed-by: Jeff Cody +Signed-off-by: Max Reitz +(cherry picked from commit 98ebc93c760372630ab181efbc2302f3b6919cd8) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/stream.c | 23 +++++++++++++++-------- + 1 file changed, 15 insertions(+), 8 deletions(-) + +diff --git a/block/stream.c b/block/stream.c +index 700eb23..81a7ec8 100644 +--- a/block/stream.c ++++ b/block/stream.c +@@ -54,16 +54,16 @@ static int coroutine_fn stream_populate(BlockBackend *blk, + return blk_co_preadv(blk, offset, qiov.size, &qiov, BDRV_REQ_COPY_ON_READ); + } + +-static void stream_exit(Job *job) ++static int stream_prepare(Job *job) + { + StreamBlockJob *s = container_of(job, StreamBlockJob, common.job); + BlockJob *bjob = &s->common; + BlockDriverState *bs = blk_bs(bjob->blk); + BlockDriverState *base = s->base; + Error *local_err = NULL; +- int ret = job->ret; ++ int ret = 0; + +- if (!job_is_cancelled(job) && bs->backing && ret == 0) { ++ if (bs->backing) { + const char *base_id = NULL, *base_fmt = NULL; + if (base) { + base_id = s->backing_file_str; +@@ -75,12 +75,19 @@ static void stream_exit(Job *job) + bdrv_set_backing_hd(bs, base, &local_err); + if (local_err) { + error_report_err(local_err); +- ret = -EPERM; +- goto out; ++ return -EPERM; + } + } + +-out: ++ return ret; ++} ++ ++static void stream_clean(Job *job) ++{ ++ StreamBlockJob *s = container_of(job, StreamBlockJob, common.job); ++ BlockJob *bjob = &s->common; ++ BlockDriverState *bs = blk_bs(bjob->blk); ++ + /* Reopen the image back in read-only mode if necessary */ + if (s->bs_flags != bdrv_get_flags(bs)) { + /* Give up write permissions before making it read-only */ +@@ -89,7 +96,6 @@ out: + } + + g_free(s->backing_file_str); +- job->ret = ret; + } + + static int coroutine_fn stream_run(Job *job, Error **errp) +@@ -206,7 +212,8 @@ static const BlockJobDriver stream_job_driver = { + .job_type = JOB_TYPE_STREAM, + .free = block_job_free, + .run = stream_run, +- .exit = stream_exit, ++ .prepare = stream_prepare, ++ .clean = stream_clean, + .user_resume = block_job_user_resume, + .drain = block_job_drain, + }, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-throttle-groups.c-allocate-RestartData-on-the-.patch b/SOURCES/kvm-block-throttle-groups.c-allocate-RestartData-on-the-.patch deleted file mode 100644 index 42bde0b..0000000 --- a/SOURCES/kvm-block-throttle-groups.c-allocate-RestartData-on-the-.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 6ce7177922a538b653910bde85d4f03fe2a299d7 Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Wed, 3 Jan 2018 11:30:21 +0100 -Subject: [PATCH 8/9] block/throttle-groups.c: allocate RestartData on the heap - -RH-Author: Stefan Hajnoczi -Message-id: <20180103113021.6954-2-stefanha@redhat.com> -Patchwork-id: 78510 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 1/1] block/throttle-groups.c: allocate RestartData on the heap -Bugzilla: 1525868 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Fam Zheng -RH-Acked-by: Jeffrey Cody - -From: Manos Pitsidianakis - -RestartData is the opaque data of the throttle_group_restart_queue_entry -coroutine. By being stack allocated, it isn't available anymore if -aio_co_enter schedules the coroutine with a bottom half and runs after -throttle_group_restart_queue returns. - -Cc: qemu-stable@nongnu.org -Signed-off-by: Manos Pitsidianakis -Reviewed-by: Eric Blake -Reviewed-by: Alberto Garcia -Signed-off-by: Kevin Wolf -(cherry picked from commit 43a5dc02fd6070827d5c4ff652b885219fa8cbe1) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - block/throttle-groups.c | 12 +++++++----- - 1 file changed, 7 insertions(+), 5 deletions(-) - -diff --git a/block/throttle-groups.c b/block/throttle-groups.c -index 35c22ac..e6ba336 100644 ---- a/block/throttle-groups.c -+++ b/block/throttle-groups.c -@@ -387,17 +387,19 @@ static void coroutine_fn throttle_group_restart_queue_entry(void *opaque) - schedule_next_request(tgm, is_write); - qemu_mutex_unlock(&tg->lock); - } -+ -+ g_free(data); - } - - static void throttle_group_restart_queue(ThrottleGroupMember *tgm, bool is_write) - { - Coroutine *co; -- RestartData rd = { -- .tgm = tgm, -- .is_write = is_write -- }; -+ RestartData *rd = g_new0(RestartData, 1); -+ -+ rd->tgm = tgm; -+ rd->is_write = is_write; - -- co = qemu_coroutine_create(throttle_group_restart_queue_entry, &rd); -+ co = qemu_coroutine_create(throttle_group_restart_queue_entry, rd); - aio_co_enter(tgm->aio_context, co); - } - --- -1.8.3.1 - diff --git a/SOURCES/kvm-block-tidy-ThrottleGroupMember-initializations.patch b/SOURCES/kvm-block-tidy-ThrottleGroupMember-initializations.patch deleted file mode 100644 index 2ac2588..0000000 --- a/SOURCES/kvm-block-tidy-ThrottleGroupMember-initializations.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 339d01accebcd27e23600e709ef426cdb794cf2e Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Fri, 17 Nov 2017 11:19:02 +0100 -Subject: [PATCH 03/15] block: tidy ThrottleGroupMember initializations - -RH-Author: Stefan Hajnoczi -Message-id: <20171117111908.8815-4-stefanha@redhat.com> -Patchwork-id: 77739 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 3/9] block: tidy ThrottleGroupMember initializations -Bugzilla: 1492295 -RH-Acked-by: John Snow -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth - -From: Manos Pitsidianakis - -Move the CoMutex and CoQueue inits inside throttle_group_register_tgm() -which is called whenever a ThrottleGroupMember is initialized. There's -no need for them to be separate. - -Reviewed-by: Alberto Garcia -Reviewed-by: Stefan Hajnoczi -Signed-off-by: Manos Pitsidianakis -Signed-off-by: Kevin Wolf -(cherry picked from commit f738cfc843055238ad969782db69156929873832) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - block/block-backend.c | 3 --- - block/throttle-groups.c | 3 +++ - 2 files changed, 3 insertions(+), 3 deletions(-) - -diff --git a/block/block-backend.c b/block/block-backend.c -index 515be10..6826476 100644 ---- a/block/block-backend.c -+++ b/block/block-backend.c -@@ -273,9 +273,6 @@ BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm) - blk->shared_perm = shared_perm; - blk_set_enable_write_cache(blk, true); - -- qemu_co_mutex_init(&blk->public.throttle_group_member.throttled_reqs_lock); -- qemu_co_queue_init(&blk->public.throttle_group_member.throttled_reqs[0]); -- qemu_co_queue_init(&blk->public.throttle_group_member.throttled_reqs[1]); - block_acct_init(&blk->stats); - - notifier_list_init(&blk->remove_bs_notifiers); -diff --git a/block/throttle-groups.c b/block/throttle-groups.c -index 3b07b25..7749cf0 100644 ---- a/block/throttle-groups.c -+++ b/block/throttle-groups.c -@@ -508,6 +508,9 @@ void throttle_group_register_tgm(ThrottleGroupMember *tgm, - read_timer_cb, - write_timer_cb, - tgm); -+ qemu_co_mutex_init(&tgm->throttled_reqs_lock); -+ qemu_co_queue_init(&tgm->throttled_reqs[0]); -+ qemu_co_queue_init(&tgm->throttled_reqs[1]); - - qemu_mutex_unlock(&tg->lock); - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-block-use-1-MB-bounce-buffers-for-crypto-instead-of-.patch b/SOURCES/kvm-block-use-1-MB-bounce-buffers-for-crypto-instead-of-.patch deleted file mode 100644 index 81de0ac..0000000 --- a/SOURCES/kvm-block-use-1-MB-bounce-buffers-for-crypto-instead-of-.patch +++ /dev/null @@ -1,113 +0,0 @@ -From 16e6d181f5e881082a42dbae18c8f002fbbe689a Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Fri, 1 Dec 2017 10:44:46 +0100 -Subject: [PATCH 10/36] block: use 1 MB bounce buffers for crypto instead of - 16KB - -RH-Author: Daniel P. Berrange -Message-id: <20171201104446.7973-1-berrange@redhat.com> -Patchwork-id: 78063 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH] block: use 1 MB bounce buffers for crypto instead of 16KB -Bugzilla: 1500334 -RH-Acked-by: Max Reitz -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Stefan Hajnoczi - -Using 16KB bounce buffers creates a significant performance -penalty for I/O to encrypted volumes on storage which high -I/O latency (rotating rust & network drives), because it -triggers lots of fairly small I/O operations. - -On tests with rotating rust, and cache=none|directsync, -write speed increased from 2MiB/s to 32MiB/s, on a par -with that achieved by the in-kernel luks driver. With -other cache modes the in-kernel driver is still notably -faster because it is able to report completion of the -I/O request before any encryption is done, while the -in-QEMU driver must encrypt the data before completion. - -Signed-off-by: Daniel P. Berrange -Message-id: 20170927125340.12360-2-berrange@redhat.com -Reviewed-by: Eric Blake -Reviewed-by: Max Reitz -Signed-off-by: Max Reitz -(cherry picked from commit 161253e2d0a83a1b33bca019c6e926013e1a03db) -Signed-off-by: Miroslav Rezanina ---- - block/crypto.c | 28 +++++++++++++++------------- - 1 file changed, 15 insertions(+), 13 deletions(-) - -diff --git a/block/crypto.c b/block/crypto.c -index 58ef6f2..684cabe 100644 ---- a/block/crypto.c -+++ b/block/crypto.c -@@ -379,7 +379,11 @@ static void block_crypto_close(BlockDriverState *bs) - } - - --#define BLOCK_CRYPTO_MAX_SECTORS 32 -+/* -+ * 1 MB bounce buffer gives good performance / memory tradeoff -+ * when using cache=none|directsync. -+ */ -+#define BLOCK_CRYPTO_MAX_IO_SIZE (1024 * 1024) - - static coroutine_fn int - block_crypto_co_readv(BlockDriverState *bs, int64_t sector_num, -@@ -396,12 +400,11 @@ block_crypto_co_readv(BlockDriverState *bs, int64_t sector_num, - - qemu_iovec_init(&hd_qiov, qiov->niov); - -- /* Bounce buffer so we have a linear mem region for -- * entire sector. XXX optimize so we avoid bounce -- * buffer in case that qiov->niov == 1 -+ /* Bounce buffer because we don't wish to expose cipher text -+ * in qiov which points to guest memory. - */ - cipher_data = -- qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_SECTORS * 512, -+ qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_IO_SIZE, - qiov->size)); - if (cipher_data == NULL) { - ret = -ENOMEM; -@@ -411,8 +414,8 @@ block_crypto_co_readv(BlockDriverState *bs, int64_t sector_num, - while (remaining_sectors) { - cur_nr_sectors = remaining_sectors; - -- if (cur_nr_sectors > BLOCK_CRYPTO_MAX_SECTORS) { -- cur_nr_sectors = BLOCK_CRYPTO_MAX_SECTORS; -+ if (cur_nr_sectors > (BLOCK_CRYPTO_MAX_IO_SIZE / 512)) { -+ cur_nr_sectors = (BLOCK_CRYPTO_MAX_IO_SIZE / 512); - } - - qemu_iovec_reset(&hd_qiov); -@@ -464,12 +467,11 @@ block_crypto_co_writev(BlockDriverState *bs, int64_t sector_num, - - qemu_iovec_init(&hd_qiov, qiov->niov); - -- /* Bounce buffer so we have a linear mem region for -- * entire sector. XXX optimize so we avoid bounce -- * buffer in case that qiov->niov == 1 -+ /* Bounce buffer because we're not permitted to touch -+ * contents of qiov - it points to guest memory. - */ - cipher_data = -- qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_SECTORS * 512, -+ qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_IO_SIZE, - qiov->size)); - if (cipher_data == NULL) { - ret = -ENOMEM; -@@ -479,8 +481,8 @@ block_crypto_co_writev(BlockDriverState *bs, int64_t sector_num, - while (remaining_sectors) { - cur_nr_sectors = remaining_sectors; - -- if (cur_nr_sectors > BLOCK_CRYPTO_MAX_SECTORS) { -- cur_nr_sectors = BLOCK_CRYPTO_MAX_SECTORS; -+ if (cur_nr_sectors > (BLOCK_CRYPTO_MAX_IO_SIZE / 512)) { -+ cur_nr_sectors = (BLOCK_CRYPTO_MAX_IO_SIZE / 512); - } - - qemu_iovec_to_buf(qiov, bytes_done, --- -1.8.3.1 - diff --git a/SOURCES/kvm-block-vxhs-improve-error-message-for-missing-bad-vxh.patch b/SOURCES/kvm-block-vxhs-improve-error-message-for-missing-bad-vxh.patch deleted file mode 100644 index d7e2e1a..0000000 --- a/SOURCES/kvm-block-vxhs-improve-error-message-for-missing-bad-vxh.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 23c1a34ecd6ca7f986ffff7a04deeb3eab0948c9 Mon Sep 17 00:00:00 2001 -From: Jeffrey Cody -Date: Mon, 11 Dec 2017 22:38:12 +0100 -Subject: [PATCH 2/6] block/vxhs: improve error message for missing / bad vxhs - module - -RH-Author: Jeffrey Cody -Message-id: <59af10d83125fff42beacd30dbca83d50409bbed.1513031708.git.jcody@redhat.com> -Patchwork-id: 78305 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 1/1] block/vxhs: improve error message for missing / bad vxhs module -Bugzilla: 1505654 -RH-Acked-by: Markus Armbruster -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Laszlo Ersek - -[Downstream only, as the module load of libvxhs is downstream only] - -In the case of missing libvxhs libraries, the original error message, -while technically accurate, may lead a user to think there is a QEMU bug -if trying to using the VXHS protocol. Update the message so that it is -clear that the likely issue is that the Veritas QEMU libvxhs RPM is not -installed (or not installed correctly, if there are permission or file -corruption issues, etc.). - -An example error message before this change: - -> qemu-img info vxhs://localhost/test -qemu-img: Could not open 'vxhs://localhost/test': \ - error loading libvxhs: /usr/lib64/qemu/libvxhs.so.1: \ - cannot open shared object file: No such file or directory - -An example error message after this change: - -> qemu-img info vxhs://localhost/test -qemu-img: Could not open 'vxhs://localhost/test': \ - The VXHS library from Veritas might not be installed correctly \ - (/usr/lib64/qemu/libvxhs.so.1: \ - cannot open shared object file: No such file or directory) - -Signed-off-by: Jeff Cody -Signed-off-by: Miroslav Rezanina ---- - block/vxhs.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/block/vxhs.c b/block/vxhs.c -index a18154c..68edb51 100644 ---- a/block/vxhs.c -+++ b/block/vxhs.c -@@ -115,7 +115,8 @@ static void bdrv_vxhs_load_libs(Error **errp) - libvxhs_handle = g_module_open(LIBVXHS_FULL_PATHNAME, - G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); - if (!libvxhs_handle) { -- error_setg(errp, "error loading libvxhs: %s", g_module_error()); -+ error_setg(errp, "The VXHS library from Veritas might not be installed " -+ "correctly (%s)", g_module_error()); - return; - } - --- -1.8.3.1 - diff --git a/SOURCES/kvm-blockdev-Report-proper-error-class-in-__com.redhat.d.patch b/SOURCES/kvm-blockdev-Report-proper-error-class-in-__com.redhat.d.patch deleted file mode 100644 index 02b5b83..0000000 --- a/SOURCES/kvm-blockdev-Report-proper-error-class-in-__com.redhat.d.patch +++ /dev/null @@ -1,50 +0,0 @@ -From bacc2236309db4099bbbfe7125efaa7ad83739d8 Mon Sep 17 00:00:00 2001 -From: Eric Blake -Date: Fri, 1 Dec 2017 03:12:21 +0100 -Subject: [PATCH 09/36] blockdev: Report proper error class in - __com.redhat.drive_del - -RH-Author: Eric Blake -Message-id: <20171201031221.26738-1-eblake@redhat.com> -Patchwork-id: 78060 -O-Subject: [RHEV-7.5 qemu-kvm-rhev PATCH] blockdev: Report proper error class in __com.redhat.drive_del -Bugzilla: 1487515 -RH-Acked-by: Markus Armbruster -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Jeffrey Cody - -From: Eric Blake -Signed-off-by: Miroslav Rezanina ---- - blockdev.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/blockdev.c b/blockdev.c -index 0f063ec..6a37934 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -2909,7 +2909,8 @@ void qmp___com_redhat_drive_del(const char *id, Error **errp) - - blk = blk_by_name(id); - if (!blk) { -- error_setg(errp, "Device '%s' not found", id); -+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, -+ "Device '%s' not found", id); - return; - } - --- -1.8.3.1 - diff --git a/SOURCES/kvm-blockdev-add-x-blockdev-set-iothread-force-boolean.patch b/SOURCES/kvm-blockdev-add-x-blockdev-set-iothread-force-boolean.patch deleted file mode 100644 index 4d6ba25..0000000 --- a/SOURCES/kvm-blockdev-add-x-blockdev-set-iothread-force-boolean.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 322e74b00634817abd82f66d8c98effc07d532a8 Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Fri, 22 Dec 2017 11:08:57 +0100 -Subject: [PATCH 39/42] blockdev: add x-blockdev-set-iothread force boolean - -RH-Author: Stefan Hajnoczi -Message-id: <20171222110900.24813-18-stefanha@redhat.com> -Patchwork-id: 78495 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 17/20] blockdev: add x-blockdev-set-iothread force boolean -Bugzilla: 1519721 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -When a node is already associated with a BlockBackend the -x-blockdev-set-iothread command refuses to set the IOThread. This is to -prevent accidentally changing the IOThread when the nodes are in use. - -When the nodes are created with -drive they automatically get a -BlockBackend. In that case we know nothing is using them yet and it's -safe to set the IOThread. Add a force boolean to override the check. - -Signed-off-by: Stefan Hajnoczi -Reviewed-by: Eric Blake -Message-id: 20171207201320.19284-4-stefanha@redhat.com -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit 882e9b89af7c1086d97cee11b2437337e756fa00) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - blockdev.c | 11 ++++++----- - qapi/block-core.json | 6 +++++- - 2 files changed, 11 insertions(+), 6 deletions(-) - -diff --git a/blockdev.c b/blockdev.c -index 6cbe627..17e2cf1 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -4192,7 +4192,7 @@ BlockJobInfoList *qmp_query_block_jobs(Error **errp) - } - - void qmp_x_blockdev_set_iothread(const char *node_name, StrOrNull *iothread, -- Error **errp) -+ bool has_force, bool force, Error **errp) - { - AioContext *old_context; - AioContext *new_context; -@@ -4204,10 +4204,11 @@ void qmp_x_blockdev_set_iothread(const char *node_name, StrOrNull *iothread, - return; - } - -- /* If we want to allow more extreme test scenarios this guard could be -- * removed. For now it protects against accidents. */ -- if (bdrv_has_blk(bs)) { -- error_setg(errp, "Node %s is in use", node_name); -+ /* Protects against accidents. */ -+ if (!(has_force && force) && bdrv_has_blk(bs)) { -+ error_setg(errp, "Node %s is associated with a BlockBackend and could " -+ "be in use (use force=true to override this check)", -+ node_name); - return; - } - -diff --git a/qapi/block-core.json b/qapi/block-core.json -index d579c99..305f7ff 100644 ---- a/qapi/block-core.json -+++ b/qapi/block-core.json -@@ -3895,6 +3895,9 @@ - # - # @iothread: the name of the IOThread object or null for the main loop - # -+# @force: true if the node and its children should be moved when a BlockBackend -+# is already attached -+# - # Note: this command is experimental and intended for test cases that need - # control over IOThreads only. - # -@@ -3917,4 +3920,5 @@ - ## - { 'command': 'x-blockdev-set-iothread', - 'data' : { 'node-name': 'str', -- 'iothread': 'StrOrNull' } } -+ 'iothread': 'StrOrNull', -+ '*force': 'bool' } } --- -1.8.3.1 - diff --git a/SOURCES/kvm-blockdev-add-x-blockdev-set-iothread-testing-command.patch b/SOURCES/kvm-blockdev-add-x-blockdev-set-iothread-testing-command.patch deleted file mode 100644 index ab65da4..0000000 --- a/SOURCES/kvm-blockdev-add-x-blockdev-set-iothread-testing-command.patch +++ /dev/null @@ -1,143 +0,0 @@ -From 0ee9b6146fd9b451c21f3428fb363d5e659693b7 Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Fri, 22 Dec 2017 11:08:55 +0100 -Subject: [PATCH 37/42] blockdev: add x-blockdev-set-iothread testing command - -RH-Author: Stefan Hajnoczi -Message-id: <20171222110900.24813-16-stefanha@redhat.com> -Patchwork-id: 78494 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 15/20] blockdev: add x-blockdev-set-iothread testing command -Bugzilla: 1519721 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -Currently there is no easy way for iotests to ensure that a BDS is bound -to a particular IOThread. Normally the virtio-blk device calls -blk_set_aio_context() when dataplane is enabled during guest driver -initialization. This never happens in iotests since -machine -accel=qtest means there is no guest activity (including device driver -initialization). - -This patch adds a QMP command to explicitly assign IOThreads in test -cases. See qapi/block-core.json for a description of the command. - -Signed-off-by: Stefan Hajnoczi -Reviewed-by: Kevin Wolf -Reviewed-by: Eric Blake -Message-id: 20171206144550.22295-9-stefanha@redhat.com -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit ca00bbb153d03c5338d8c8136812163f463f841e) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - blockdev.c | 41 +++++++++++++++++++++++++++++++++++++++++ - qapi/block-core.json | 36 ++++++++++++++++++++++++++++++++++++ - 2 files changed, 77 insertions(+) - -diff --git a/blockdev.c b/blockdev.c -index f118444..6cbe627 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -46,6 +46,7 @@ - #include "qapi/qobject-output-visitor.h" - #include "qapi/util.h" - #include "sysemu/sysemu.h" -+#include "sysemu/iothread.h" - #include "block/block_int.h" - #include "qmp-commands.h" - #include "block/trace.h" -@@ -4190,6 +4191,46 @@ BlockJobInfoList *qmp_query_block_jobs(Error **errp) - return head; - } - -+void qmp_x_blockdev_set_iothread(const char *node_name, StrOrNull *iothread, -+ Error **errp) -+{ -+ AioContext *old_context; -+ AioContext *new_context; -+ BlockDriverState *bs; -+ -+ bs = bdrv_find_node(node_name); -+ if (!bs) { -+ error_setg(errp, "Cannot find node %s", node_name); -+ return; -+ } -+ -+ /* If we want to allow more extreme test scenarios this guard could be -+ * removed. For now it protects against accidents. */ -+ if (bdrv_has_blk(bs)) { -+ error_setg(errp, "Node %s is in use", node_name); -+ return; -+ } -+ -+ if (iothread->type == QTYPE_QSTRING) { -+ IOThread *obj = iothread_by_id(iothread->u.s); -+ if (!obj) { -+ error_setg(errp, "Cannot find iothread %s", iothread->u.s); -+ return; -+ } -+ -+ new_context = iothread_get_aio_context(obj); -+ } else { -+ new_context = qemu_get_aio_context(); -+ } -+ -+ old_context = bdrv_get_aio_context(bs); -+ aio_context_acquire(old_context); -+ -+ bdrv_set_aio_context(bs, new_context); -+ -+ aio_context_release(old_context); -+} -+ - QemuOptsList qemu_common_drive_opts = { - .name = "drive", - .head = QTAILQ_HEAD_INITIALIZER(qemu_common_drive_opts.head), -diff --git a/qapi/block-core.json b/qapi/block-core.json -index 15fc08f..d579c99 100644 ---- a/qapi/block-core.json -+++ b/qapi/block-core.json -@@ -3882,3 +3882,39 @@ - 'data' : { 'parent': 'str', - '*child': 'str', - '*node': 'str' } } -+ -+## -+# @x-blockdev-set-iothread: -+# -+# Move @node and its children into the @iothread. If @iothread is null then -+# move @node and its children into the main loop. -+# -+# The node must not be attached to a BlockBackend. -+# -+# @node-name: the name of the block driver node -+# -+# @iothread: the name of the IOThread object or null for the main loop -+# -+# Note: this command is experimental and intended for test cases that need -+# control over IOThreads only. -+# -+# Since: 2.12 -+# -+# Example: -+# -+# 1. Move a node into an IOThread -+# -> { "execute": "x-blockdev-set-iothread", -+# "arguments": { "node-name": "disk1", -+# "iothread": "iothread0" } } -+# <- { "return": {} } -+# -+# 2. Move a node into the main loop -+# -> { "execute": "x-blockdev-set-iothread", -+# "arguments": { "node-name": "disk1", -+# "iothread": null } } -+# <- { "return": {} } -+# -+## -+{ 'command': 'x-blockdev-set-iothread', -+ 'data' : { 'node-name': 'str', -+ 'iothread': 'StrOrNull' } } --- -1.8.3.1 - diff --git a/SOURCES/kvm-blockdev-backup-add-bitmap-argument.patch b/SOURCES/kvm-blockdev-backup-add-bitmap-argument.patch new file mode 100644 index 0000000..59abc5b --- /dev/null +++ b/SOURCES/kvm-blockdev-backup-add-bitmap-argument.patch @@ -0,0 +1,97 @@ +From f165f8b7819f9c9aa0358a1e0bc1f48cf4dfa98f Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 14 Sep 2018 04:08:14 +0200 +Subject: [PATCH 07/49] blockdev-backup: add bitmap argument + +RH-Author: John Snow +Message-id: <20180914040814.14950-2-jsnow@redhat.com> +Patchwork-id: 82149 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/1] blockdev-backup: add bitmap argument +Bugzilla: 1628373 +RH-Acked-by: Fam Zheng +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody + +It is only an oversight that we don't allow incremental backup with +blockdev-backup. Add the bitmap argument which enables this. + +Signed-off-by: John Snow +Message-id: 20180830211605.13683-2-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit 4034c1a9fd503f9fa488dc9b851bc4497f374e98) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + blockdev.c | 16 +++++++++++++++- + qapi/block-core.json | 7 ++++++- + 2 files changed, 21 insertions(+), 2 deletions(-) + +diff --git a/blockdev.c b/blockdev.c +index fb355c8..6e8a1e9 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -3701,6 +3701,7 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn, + BlockDriverState *bs; + BlockDriverState *target_bs; + Error *local_err = NULL; ++ BdrvDirtyBitmap *bmap = NULL; + AioContext *aio_context; + BlockJob *job = NULL; + int job_flags = JOB_DEFAULT; +@@ -3751,6 +3752,19 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn, + goto out; + } + } ++ if (backup->has_bitmap) { ++ bmap = bdrv_find_dirty_bitmap(bs, backup->bitmap); ++ if (!bmap) { ++ error_setg(errp, "Bitmap '%s' could not be found", backup->bitmap); ++ goto out; ++ } ++ if (bdrv_dirty_bitmap_qmp_locked(bmap)) { ++ error_setg(errp, ++ "Bitmap '%s' is currently locked and cannot be used for " ++ "backup", backup->bitmap); ++ goto out; ++ } ++ } + if (!backup->auto_finalize) { + job_flags |= JOB_MANUAL_FINALIZE; + } +@@ -3758,7 +3772,7 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn, + job_flags |= JOB_MANUAL_DISMISS; + } + job = backup_job_create(backup->job_id, bs, target_bs, backup->speed, +- backup->sync, NULL, backup->compress, ++ backup->sync, bmap, backup->compress, + backup->on_source_error, backup->on_target_error, + job_flags, NULL, NULL, txn, &local_err); + if (local_err != NULL) { +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 8da07cd..2706012 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -1299,6 +1299,10 @@ + # @speed: the maximum speed, in bytes per second. The default is 0, + # for unlimited. + # ++# @bitmap: the name of dirty bitmap if sync is "incremental". ++# Must be present if sync is "incremental", must NOT be present ++# otherwise. (Since 3.1) ++# + # @compress: true to compress data, if the target format supports it. + # (default: false) (since 2.8) + # +@@ -1331,7 +1335,8 @@ + ## + { 'struct': 'BlockdevBackup', + 'data': { '*job-id': 'str', 'device': 'str', 'target': 'str', +- 'sync': 'MirrorSyncMode', '*speed': 'int', '*compress': 'bool', ++ 'sync': 'MirrorSyncMode', '*speed': 'int', ++ '*bitmap': 'str', '*compress': 'bool', + '*on-source-error': 'BlockdevOnError', + '*on-target-error': 'BlockdevOnError', + '*auto-finalize': 'bool', '*auto-dismiss': 'bool' } } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-blockdev-document-transactional-shortcomings.patch b/SOURCES/kvm-blockdev-document-transactional-shortcomings.patch new file mode 100644 index 0000000..8145b13 --- /dev/null +++ b/SOURCES/kvm-blockdev-document-transactional-shortcomings.patch @@ -0,0 +1,53 @@ +From 3e0ff815da32944228b49c4ad33957c63dfd0f99 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 10 Sep 2018 18:18:03 +0200 +Subject: [PATCH 25/25] blockdev: document transactional shortcomings + +RH-Author: John Snow +Message-id: <20180910181803.11781-26-jsnow@redhat.com> +Patchwork-id: 82087 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 25/25] blockdev: document transactional shortcomings +Bugzilla: 1626061 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Presently only the backup job really guarantees what one would consider +transactional semantics. To guard against someone helpfully adding them +in the future, document that there are shortcomings in the model that +would need to be audited at that time. + +Signed-off-by: John Snow +Message-id: 20180906130225.5118-17-jsnow@redhat.com +Reviewed-by: Jeff Cody +Reviewed-by: Max Reitz +Signed-off-by: Max Reitz +(cherry picked from commit 97169e9959811e92e14c42afa0ec1fdeb09715ea) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + blockdev.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/blockdev.c b/blockdev.c +index 6325471..0eb6bba 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -2333,7 +2333,13 @@ static const BlkActionOps actions[] = { + .instance_size = sizeof(BlockDirtyBitmapState), + .prepare = block_dirty_bitmap_disable_prepare, + .abort = block_dirty_bitmap_disable_abort, +- } ++ }, ++ /* Where are transactions for MIRROR, COMMIT and STREAM? ++ * Although these blockjobs use transaction callbacks like the backup job, ++ * these jobs do not necessarily adhere to transaction semantics. ++ * These jobs may not fully undo all of their actions on abort, nor do they ++ * necessarily work in transactions with more than one job in them. ++ */ + }; + + /** +-- +1.8.3.1 + diff --git a/SOURCES/kvm-blockdev-enable-non-root-nodes-for-backup-source.patch b/SOURCES/kvm-blockdev-enable-non-root-nodes-for-backup-source.patch new file mode 100644 index 0000000..b661e6d --- /dev/null +++ b/SOURCES/kvm-blockdev-enable-non-root-nodes-for-backup-source.patch @@ -0,0 +1,61 @@ +From 305bd87b4d721989679d4c3407e355e032e2c005 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 18 Jul 2018 22:54:46 +0200 +Subject: [PATCH 61/89] blockdev: enable non-root nodes for backup source + +RH-Author: John Snow +Message-id: <20180718225511.14878-11-jsnow@redhat.com> +Patchwork-id: 81395 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 10/35] blockdev: enable non-root nodes for backup source +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Vladimir Sementsov-Ogievskiy + +This is needed to implement the image-fleecing workflow where we +create a temporary node backed by an active node, then start +backupdev-backup sync=none from the active node to the temp node. + +In this case, the active node is now a root node AND a backing node, +so it no longer qualifies as a root node, so we loosen the restriction +on which nodes can be considered as the source for a backup. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: Eric Blake +Signed-off-by: John Snow +Message-Id: <20180702194630.9360-2-jsnow@redhat.com> +Signed-off-by: Eric Blake +(cherry picked from commit 930fe17f9900e9c879834f2d2e5c301992623332) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + blockdev.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/blockdev.c b/blockdev.c +index 9beef10..baa7e18 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -2010,7 +2010,7 @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp) + assert(common->action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP); + backup = common->action->u.blockdev_backup.data; + +- bs = qmp_get_root_bs(backup->device, errp); ++ bs = bdrv_lookup_bs(backup->device, backup->device, errp); + if (!bs) { + return; + } +@@ -3674,7 +3674,7 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn, + backup->compress = false; + } + +- bs = qmp_get_root_bs(backup->device, errp); ++ bs = bdrv_lookup_bs(backup->device, backup->device, errp); + if (!bs) { + return NULL; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-blockdev-hold-AioContext-for-bdrv_unref-in-external_.patch b/SOURCES/kvm-blockdev-hold-AioContext-for-bdrv_unref-in-external_.patch deleted file mode 100644 index 9f8b68b..0000000 --- a/SOURCES/kvm-blockdev-hold-AioContext-for-bdrv_unref-in-external_.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 96ba2c5dcbe1bed81311a8a150712a3bb25b9296 Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Fri, 22 Dec 2017 11:08:49 +0100 -Subject: [PATCH 31/42] blockdev: hold AioContext for bdrv_unref() in - external_snapshot_clean() - -RH-Author: Stefan Hajnoczi -Message-id: <20171222110900.24813-10-stefanha@redhat.com> -Patchwork-id: 78490 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 09/20] blockdev: hold AioContext for bdrv_unref() in external_snapshot_clean() -Bugzilla: 1519721 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -bdrv_unref() requires the AioContext lock because bdrv_flush() uses -BDRV_POLL_WHILE(), which assumes the AioContext is currently held. If -BDRV_POLL_WHILE() runs without AioContext held the -pthread_mutex_unlock() call in aio_context_release() fails. - -This patch moves bdrv_unref() into the AioContext locked region to solve -the following pthread_mutex_unlock() failure: - - #0 0x00007f566181969b in raise () at /lib64/libc.so.6 - #1 0x00007f566181b3b1 in abort () at /lib64/libc.so.6 - #2 0x00005592cd590458 in error_exit (err=, msg=msg@entry=0x5592cdaf6d60 <__func__.23977> "qemu_mutex_unlock") at util/qemu-thread-posix.c:36 - #3 0x00005592cd96e738 in qemu_mutex_unlock (mutex=mutex@entry=0x5592ce9505e0) at util/qemu-thread-posix.c:96 - #4 0x00005592cd969b69 in aio_context_release (ctx=ctx@entry=0x5592ce950580) at util/async.c:507 - #5 0x00005592cd8ead78 in bdrv_flush (bs=bs@entry=0x5592cfa87210) at block/io.c:2478 - #6 0x00005592cd89df30 in bdrv_close (bs=0x5592cfa87210) at block.c:3207 - #7 0x00005592cd89df30 in bdrv_delete (bs=0x5592cfa87210) at block.c:3395 - #8 0x00005592cd89df30 in bdrv_unref (bs=0x5592cfa87210) at block.c:4418 - #9 0x00005592cd6b7f86 in qmp_transaction (dev_list=, has_props=, props=, errp=errp@entry=0x7ffe4a1fc9d8) at blockdev.c:2308 - -Signed-off-by: Stefan Hajnoczi -Reviewed-by: Kevin Wolf -Reviewed-by: Eric Blake -Message-id: 20171206144550.22295-2-stefanha@redhat.com -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit b9464ba19f821ea6b29969104dc48dcdb26243dd) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - blockdev.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/blockdev.c b/blockdev.c -index 6a37934..c6978a5 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -1855,8 +1855,8 @@ static void external_snapshot_clean(BlkActionState *common) - DO_UPCAST(ExternalSnapshotState, common, common); - if (state->aio_context) { - bdrv_drained_end(state->old_bs); -- aio_context_release(state->aio_context); - bdrv_unref(state->new_bs); -+ aio_context_release(state->aio_context); - } - } - --- -1.8.3.1 - diff --git a/SOURCES/kvm-blockjob-Add-block_job_driver.patch b/SOURCES/kvm-blockjob-Add-block_job_driver.patch new file mode 100644 index 0000000..fb1dd60 --- /dev/null +++ b/SOURCES/kvm-blockjob-Add-block_job_driver.patch @@ -0,0 +1,105 @@ +From a80cabf1e33718c739f131c77b63a31d5cf6f5e1 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:47:56 +0200 +Subject: [PATCH 27/89] blockjob: Add block_job_driver() + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-14-kwolf@redhat.com> +Patchwork-id: 81064 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 13/73] blockjob: Add block_job_driver() +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +The backup block job directly accesses the driver field in BlockJob. Add +a wrapper for getting it. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +Reviewed-by: Max Reitz +Reviewed-by: John Snow +(cherry picked from commit bd21935b50d100d8da8c05cd3c2009f0f3432cb4) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/backup.c | 8 +++++--- + blockjob.c | 5 +++++ + include/block/blockjob.h | 7 +++++++ + 3 files changed, 17 insertions(+), 3 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index cfdb6ec..e14d995 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -47,6 +47,8 @@ typedef struct BackupBlockJob { + HBitmap *copy_bitmap; + } BackupBlockJob; + ++static const BlockJobDriver backup_job_driver; ++ + /* See if in-flight requests overlap and wait for them to complete */ + static void coroutine_fn wait_for_overlapping_requests(BackupBlockJob *job, + int64_t start, +@@ -241,7 +243,7 @@ void backup_do_checkpoint(BlockJob *job, Error **errp) + BackupBlockJob *backup_job = container_of(job, BackupBlockJob, common); + int64_t len; + +- assert(job->driver->job_type == BLOCK_JOB_TYPE_BACKUP); ++ assert(block_job_driver(job) == &backup_job_driver); + + if (backup_job->sync_mode != MIRROR_SYNC_MODE_NONE) { + error_setg(errp, "The backup job only supports block checkpoint in" +@@ -259,7 +261,7 @@ void backup_wait_for_overlapping_requests(BlockJob *job, int64_t offset, + BackupBlockJob *backup_job = container_of(job, BackupBlockJob, common); + int64_t start, end; + +- assert(job->driver->job_type == BLOCK_JOB_TYPE_BACKUP); ++ assert(block_job_driver(job) == &backup_job_driver); + + start = QEMU_ALIGN_DOWN(offset, backup_job->cluster_size); + end = QEMU_ALIGN_UP(offset + bytes, backup_job->cluster_size); +@@ -272,7 +274,7 @@ void backup_cow_request_begin(CowRequest *req, BlockJob *job, + BackupBlockJob *backup_job = container_of(job, BackupBlockJob, common); + int64_t start, end; + +- assert(job->driver->job_type == BLOCK_JOB_TYPE_BACKUP); ++ assert(block_job_driver(job) == &backup_job_driver); + + start = QEMU_ALIGN_DOWN(offset, backup_job->cluster_size); + end = QEMU_ALIGN_UP(offset + bytes, backup_job->cluster_size); +diff --git a/blockjob.c b/blockjob.c +index e30f5ec..112672a 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -373,6 +373,11 @@ static bool block_job_started(BlockJob *job) + return job->co; + } + ++const BlockJobDriver *block_job_driver(BlockJob *job) ++{ ++ return job->driver; ++} ++ + /** + * All jobs must allow a pause point before entering their job proper. This + * ensures that jobs can be paused prior to being started, then resumed later. +diff --git a/include/block/blockjob.h b/include/block/blockjob.h +index 82f52f4..0f56f72 100644 +--- a/include/block/blockjob.h ++++ b/include/block/blockjob.h +@@ -452,4 +452,11 @@ void block_job_txn_add_job(BlockJobTxn *txn, BlockJob *job); + */ + bool block_job_is_internal(BlockJob *job); + ++/** ++ * block_job_driver: ++ * ++ * Returns the driver associated with a block job. ++ */ ++const BlockJobDriver *block_job_driver(BlockJob *job); ++ + #endif +-- +1.8.3.1 + diff --git a/SOURCES/kvm-blockjob-Fix-assertion-in-block_job_finalize.patch b/SOURCES/kvm-blockjob-Fix-assertion-in-block_job_finalize.patch new file mode 100644 index 0000000..7f1d57a --- /dev/null +++ b/SOURCES/kvm-blockjob-Fix-assertion-in-block_job_finalize.patch @@ -0,0 +1,52 @@ +From 7c3744d3960176798cde84b989bab4f7955f97c3 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:47:51 +0200 +Subject: [PATCH 22/89] blockjob: Fix assertion in block_job_finalize() + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-9-kwolf@redhat.com> +Patchwork-id: 81060 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 08/73] blockjob: Fix assertion in block_job_finalize() +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +Every job gets a non-NULL job->txn on creation, but it doesn't +necessarily keep it until it is decommissioned: Finalising a job removes +it from its transaction. Therefore, calling 'blockdev-job-finalize' a +second time on an already concluded job causes an assertion failure. + +Remove job->txn from the assertion in block_job_finalize() to fix this. +block_job_do_finalize() still has the same assertion, but if a job is +already removed from its transaction, block_job_apply_verb() will +already error out before we run into that assertion. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +Reviewed-by: Max Reitz +Reviewed-by: John Snow +(cherry picked from commit 37aa19b63c46d933f1e4ea944cfccee54e2caf4a) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + blockjob.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/blockjob.c b/blockjob.c +index 6746cad..0033b96 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -710,7 +710,7 @@ void block_job_complete(BlockJob *job, Error **errp) + + void block_job_finalize(BlockJob *job, Error **errp) + { +- assert(job && job->id && job->txn); ++ assert(job && job->id); + if (block_job_apply_verb(job, BLOCK_JOB_VERB_FINALIZE, errp)) { + return; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-blockjob-Implement-block_job_set_speed-centrally.patch b/SOURCES/kvm-blockjob-Implement-block_job_set_speed-centrally.patch new file mode 100644 index 0000000..72ba875 --- /dev/null +++ b/SOURCES/kvm-blockjob-Implement-block_job_set_speed-centrally.patch @@ -0,0 +1,284 @@ +From f92e2e46e8d14701afb20a12a45423cd06d7f5c6 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:47:54 +0200 +Subject: [PATCH 25/89] blockjob: Implement block_job_set_speed() centrally + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-12-kwolf@redhat.com> +Patchwork-id: 81102 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 11/73] blockjob: Implement block_job_set_speed() centrally +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +All block job drivers support .set_speed and all of them duplicate the +same code to implement it. Move that code to blockjob.c and remove the +now useless callback. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +Reviewed-by: Max Reitz +Reviewed-by: John Snow +(cherry picked from commit 18bb69287ea522ab696e1bea818b93e5eaa85745) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/backup.c | 13 ------------- + block/commit.c | 14 -------------- + block/mirror.c | 26 ++++++-------------------- + block/stream.c | 14 -------------- + blockjob.c | 12 ++++-------- + include/block/blockjob.h | 2 ++ + include/block/blockjob_int.h | 3 --- + 7 files changed, 12 insertions(+), 72 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index 7585c43..8468fd9 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -27,7 +27,6 @@ + #include "qemu/error-report.h" + + #define BACKUP_CLUSTER_SIZE_DEFAULT (1 << 16) +-#define SLICE_TIME 100000000ULL /* ns */ + + typedef struct BackupBlockJob { + BlockJob common; +@@ -190,17 +189,6 @@ static int coroutine_fn backup_before_write_notify( + return backup_do_cow(job, req->offset, req->bytes, NULL, true); + } + +-static void backup_set_speed(BlockJob *job, int64_t speed, Error **errp) +-{ +- BackupBlockJob *s = container_of(job, BackupBlockJob, common); +- +- if (speed < 0) { +- error_setg(errp, QERR_INVALID_PARAMETER, "speed"); +- return; +- } +- ratelimit_set_speed(&s->common.limit, speed, SLICE_TIME); +-} +- + static void backup_cleanup_sync_bitmap(BackupBlockJob *job, int ret) + { + BdrvDirtyBitmap *bm; +@@ -540,7 +528,6 @@ static const BlockJobDriver backup_job_driver = { + .instance_size = sizeof(BackupBlockJob), + .job_type = BLOCK_JOB_TYPE_BACKUP, + .start = backup_run, +- .set_speed = backup_set_speed, + .commit = backup_commit, + .abort = backup_abort, + .clean = backup_clean, +diff --git a/block/commit.c b/block/commit.c +index beec5d0..46cbeae 100644 +--- a/block/commit.c ++++ b/block/commit.c +@@ -31,8 +31,6 @@ enum { + COMMIT_BUFFER_SIZE = 512 * 1024, /* in bytes */ + }; + +-#define SLICE_TIME 100000000ULL /* ns */ +- + typedef struct CommitBlockJob { + BlockJob common; + BlockDriverState *commit_top_bs; +@@ -216,21 +214,9 @@ out: + block_job_defer_to_main_loop(&s->common, commit_complete, data); + } + +-static void commit_set_speed(BlockJob *job, int64_t speed, Error **errp) +-{ +- CommitBlockJob *s = container_of(job, CommitBlockJob, common); +- +- if (speed < 0) { +- error_setg(errp, QERR_INVALID_PARAMETER, "speed"); +- return; +- } +- ratelimit_set_speed(&s->common.limit, speed, SLICE_TIME); +-} +- + static const BlockJobDriver commit_job_driver = { + .instance_size = sizeof(CommitBlockJob), + .job_type = BLOCK_JOB_TYPE_COMMIT, +- .set_speed = commit_set_speed, + .start = commit_run, + }; + +diff --git a/block/mirror.c b/block/mirror.c +index a515ec1..d5e0ff2 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -22,7 +22,6 @@ + #include "qemu/ratelimit.h" + #include "qemu/bitmap.h" + +-#define SLICE_TIME 100000000ULL /* ns */ + #define MAX_IN_FLIGHT 16 + #define MAX_IO_BYTES (1 << 20) /* 1 Mb */ + #define DEFAULT_MIRROR_BUF_SIZE (MAX_IN_FLIGHT * MAX_IO_BYTES) +@@ -596,7 +595,7 @@ static void mirror_throttle(MirrorBlockJob *s) + { + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); + +- if (now - s->last_pause_ns > SLICE_TIME) { ++ if (now - s->last_pause_ns > BLOCK_JOB_SLICE_TIME) { + s->last_pause_ns = now; + block_job_sleep_ns(&s->common, 0); + } else { +@@ -799,11 +798,10 @@ static void coroutine_fn mirror_run(void *opaque) + + /* Note that even when no rate limit is applied we need to yield + * periodically with no pending I/O so that bdrv_drain_all() returns. +- * We do so every SLICE_TIME nanoseconds, or when there is an error, +- * or when the source is clean, whichever comes first. +- */ ++ * We do so every BLKOCK_JOB_SLICE_TIME nanoseconds, or when there is ++ * an error, or when the source is clean, whichever comes first. */ + delta = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - s->last_pause_ns; +- if (delta < SLICE_TIME && ++ if (delta < BLOCK_JOB_SLICE_TIME && + s->common.iostatus == BLOCK_DEVICE_IO_STATUS_OK) { + if (s->in_flight >= MAX_IN_FLIGHT || s->buf_free_count == 0 || + (cnt == 0 && s->in_flight > 0)) { +@@ -869,7 +867,8 @@ static void coroutine_fn mirror_run(void *opaque) + ret = 0; + + if (s->synced && !should_complete) { +- delay_ns = (s->in_flight == 0 && cnt == 0 ? SLICE_TIME : 0); ++ delay_ns = (s->in_flight == 0 && ++ cnt == 0 ? BLOCK_JOB_SLICE_TIME : 0); + } + trace_mirror_before_sleep(s, cnt, s->synced, delay_ns); + block_job_sleep_ns(&s->common, delay_ns); +@@ -908,17 +907,6 @@ immediate_exit: + block_job_defer_to_main_loop(&s->common, mirror_exit, data); + } + +-static void mirror_set_speed(BlockJob *job, int64_t speed, Error **errp) +-{ +- MirrorBlockJob *s = container_of(job, MirrorBlockJob, common); +- +- if (speed < 0) { +- error_setg(errp, QERR_INVALID_PARAMETER, "speed"); +- return; +- } +- ratelimit_set_speed(&s->common.limit, speed, SLICE_TIME); +-} +- + static void mirror_complete(BlockJob *job, Error **errp) + { + MirrorBlockJob *s = container_of(job, MirrorBlockJob, common); +@@ -1003,7 +991,6 @@ static void mirror_drain(BlockJob *job) + static const BlockJobDriver mirror_job_driver = { + .instance_size = sizeof(MirrorBlockJob), + .job_type = BLOCK_JOB_TYPE_MIRROR, +- .set_speed = mirror_set_speed, + .start = mirror_run, + .complete = mirror_complete, + .pause = mirror_pause, +@@ -1014,7 +1001,6 @@ static const BlockJobDriver mirror_job_driver = { + static const BlockJobDriver commit_active_job_driver = { + .instance_size = sizeof(MirrorBlockJob), + .job_type = BLOCK_JOB_TYPE_COMMIT, +- .set_speed = mirror_set_speed, + .start = mirror_run, + .complete = mirror_complete, + .pause = mirror_pause, +diff --git a/block/stream.c b/block/stream.c +index a1d4768..797d7c4 100644 +--- a/block/stream.c ++++ b/block/stream.c +@@ -29,8 +29,6 @@ enum { + STREAM_BUFFER_SIZE = 512 * 1024, /* in bytes */ + }; + +-#define SLICE_TIME 100000000ULL /* ns */ +- + typedef struct StreamBlockJob { + BlockJob common; + BlockDriverState *base; +@@ -210,21 +208,9 @@ out: + block_job_defer_to_main_loop(&s->common, stream_complete, data); + } + +-static void stream_set_speed(BlockJob *job, int64_t speed, Error **errp) +-{ +- StreamBlockJob *s = container_of(job, StreamBlockJob, common); +- +- if (speed < 0) { +- error_setg(errp, QERR_INVALID_PARAMETER, "speed"); +- return; +- } +- ratelimit_set_speed(&s->common.limit, speed, SLICE_TIME); +-} +- + static const BlockJobDriver stream_job_driver = { + .instance_size = sizeof(StreamBlockJob), + .job_type = BLOCK_JOB_TYPE_STREAM, +- .set_speed = stream_set_speed, + .start = stream_run, + }; + +diff --git a/blockjob.c b/blockjob.c +index d0a2ac5..0f7214c 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -667,22 +667,18 @@ static void block_job_completed_txn_success(BlockJob *job) + + void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) + { +- Error *local_err = NULL; + int64_t old_speed = job->speed; + +- if (!job->driver->set_speed) { +- error_setg(errp, QERR_UNSUPPORTED); +- return; +- } + if (block_job_apply_verb(job, BLOCK_JOB_VERB_SET_SPEED, errp)) { + return; + } +- job->driver->set_speed(job, speed, &local_err); +- if (local_err) { +- error_propagate(errp, local_err); ++ if (speed < 0) { ++ error_setg(errp, QERR_INVALID_PARAMETER, "speed"); + return; + } + ++ ratelimit_set_speed(&job->limit, speed, BLOCK_JOB_SLICE_TIME); ++ + job->speed = speed; + if (speed && speed <= old_speed) { + return; +diff --git a/include/block/blockjob.h b/include/block/blockjob.h +index 22bf418..82f52f4 100644 +--- a/include/block/blockjob.h ++++ b/include/block/blockjob.h +@@ -29,6 +29,8 @@ + #include "block/block.h" + #include "qemu/ratelimit.h" + ++#define BLOCK_JOB_SLICE_TIME 100000000ULL /* ns */ ++ + typedef struct BlockJobDriver BlockJobDriver; + typedef struct BlockJobTxn BlockJobTxn; + +diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h +index d5a515d..ad510d5 100644 +--- a/include/block/blockjob_int.h ++++ b/include/block/blockjob_int.h +@@ -41,9 +41,6 @@ struct BlockJobDriver { + /** String describing the operation, part of query-block-jobs QMP API */ + BlockJobType job_type; + +- /** Optional callback for job types that support setting a speed limit */ +- void (*set_speed)(BlockJob *job, int64_t speed, Error **errp); +- + /** Mandatory: Entrypoint for the Coroutine. */ + CoroutineEntry *start; + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-blockjob-Improve-BlockJobInfo.offset-len-documentati.patch b/SOURCES/kvm-blockjob-Improve-BlockJobInfo.offset-len-documentati.patch new file mode 100644 index 0000000..d2c7782 --- /dev/null +++ b/SOURCES/kvm-blockjob-Improve-BlockJobInfo.offset-len-documentati.patch @@ -0,0 +1,60 @@ +From 1dca4e49145a339e84b7cdc2a9b226f0a3afe502 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:47:58 +0200 +Subject: [PATCH 29/89] blockjob: Improve BlockJobInfo.offset/len documentation + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-16-kwolf@redhat.com> +Patchwork-id: 81087 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 15/73] blockjob: Improve BlockJobInfo.offset/len documentation +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +Clarify that len is just an estimation of the end value of offset, and +that offset increases monotonically while len can change arbitrarily. + +While touching the documentation of offset, move it directly after len +to match the order of the declaration below. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +Reviewed-by: John Snow +(cherry picked from commit a81e0a825e3b89039a427bca037112f461b95fec) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + qapi/block-core.json | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/qapi/block-core.json b/qapi/block-core.json +index d24c12b..1f6d4bb 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -1148,7 +1148,12 @@ + # @device: The job identifier. Originally the device name but other + # values are allowed since QEMU 2.7 + # +-# @len: the maximum progress value ++# @len: Estimated @offset value at the completion of the job. This value can ++# arbitrarily change while the job is running, in both directions. ++# ++# @offset: Progress made until now. The unit is arbitrary and the value can ++# only meaningfully be used for the ratio of @offset to @len. The ++# value is monotonically increasing. + # + # @busy: false if the job is known to be in a quiescent state, with + # no pending I/O. Since 1.3. +@@ -1156,8 +1161,6 @@ + # @paused: whether the job is paused or, if @busy is true, will + # pause itself as soon as possible. Since 1.3. + # +-# @offset: the current progress value +-# + # @speed: the rate limit, bytes per second + # + # @io-status: the status of the job (since 1.3) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-blockjob-Introduce-block_job_ratelimit_get_delay.patch b/SOURCES/kvm-blockjob-Introduce-block_job_ratelimit_get_delay.patch new file mode 100644 index 0000000..4a37a04 --- /dev/null +++ b/SOURCES/kvm-blockjob-Introduce-block_job_ratelimit_get_delay.patch @@ -0,0 +1,154 @@ +From 0106ebf221d3cc30580249e7b9b4d90a0ad10c5c Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:47:55 +0200 +Subject: [PATCH 26/89] blockjob: Introduce block_job_ratelimit_get_delay() + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-13-kwolf@redhat.com> +Patchwork-id: 81079 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 12/73] blockjob: Introduce block_job_ratelimit_get_delay() +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This gets us rid of more direct accesses to BlockJob fields from the +job drivers. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +Reviewed-by: Max Reitz +Reviewed-by: John Snow +(cherry picked from commit dee81d5111ff0e24ac63ab0dbbd19e84c2f87904) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/backup.c | 18 +++++++----------- + block/commit.c | 4 ++-- + block/mirror.c | 5 +---- + block/stream.c | 4 ++-- + blockjob.c | 9 +++++++++ + include/block/blockjob_int.h | 8 ++++++++ + 6 files changed, 29 insertions(+), 19 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index 8468fd9..cfdb6ec 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -325,21 +325,17 @@ static void backup_complete(BlockJob *job, void *opaque) + + static bool coroutine_fn yield_and_check(BackupBlockJob *job) + { ++ uint64_t delay_ns; ++ + if (block_job_is_cancelled(&job->common)) { + return true; + } + +- /* we need to yield so that bdrv_drain_all() returns. +- * (without, VM does not reboot) +- */ +- if (job->common.speed) { +- uint64_t delay_ns = ratelimit_calculate_delay(&job->common.limit, +- job->bytes_read); +- job->bytes_read = 0; +- block_job_sleep_ns(&job->common, delay_ns); +- } else { +- block_job_sleep_ns(&job->common, 0); +- } ++ /* We need to yield even for delay_ns = 0 so that bdrv_drain_all() can ++ * return. Without a yield, the VM would not reboot. */ ++ delay_ns = block_job_ratelimit_get_delay(&job->common, job->bytes_read); ++ job->bytes_read = 0; ++ block_job_sleep_ns(&job->common, delay_ns); + + if (block_job_is_cancelled(&job->common)) { + return true; +diff --git a/block/commit.c b/block/commit.c +index 46cbeae..ba5df6a 100644 +--- a/block/commit.c ++++ b/block/commit.c +@@ -197,8 +197,8 @@ static void coroutine_fn commit_run(void *opaque) + /* Publish progress */ + block_job_progress_update(&s->common, n); + +- if (copy && s->common.speed) { +- delay_ns = ratelimit_calculate_delay(&s->common.limit, n); ++ if (copy) { ++ delay_ns = block_job_ratelimit_get_delay(&s->common, n); + } else { + delay_ns = 0; + } +diff --git a/block/mirror.c b/block/mirror.c +index d5e0ff2..a4197bb 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -447,10 +447,7 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s) + assert(io_bytes); + offset += io_bytes; + nb_chunks -= DIV_ROUND_UP(io_bytes, s->granularity); +- if (s->common.speed) { +- delay_ns = ratelimit_calculate_delay(&s->common.limit, +- io_bytes_acct); +- } ++ delay_ns = block_job_ratelimit_get_delay(&s->common, io_bytes_acct); + } + return delay_ns; + } +diff --git a/block/stream.c b/block/stream.c +index 797d7c4..df9660d 100644 +--- a/block/stream.c ++++ b/block/stream.c +@@ -185,8 +185,8 @@ static void coroutine_fn stream_run(void *opaque) + + /* Publish progress */ + block_job_progress_update(&s->common, n); +- if (copy && s->common.speed) { +- delay_ns = ratelimit_calculate_delay(&s->common.limit, n); ++ if (copy) { ++ delay_ns = block_job_ratelimit_get_delay(&s->common, n); + } else { + delay_ns = 0; + } +diff --git a/blockjob.c b/blockjob.c +index 0f7214c..e30f5ec 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -688,6 +688,15 @@ void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) + block_job_enter_cond(job, block_job_timer_pending); + } + ++int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n) ++{ ++ if (!job->speed) { ++ return 0; ++ } ++ ++ return ratelimit_calculate_delay(&job->limit, n); ++} ++ + void block_job_complete(BlockJob *job, Error **errp) + { + /* Should not be reachable via external interface for internal jobs */ +diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h +index ad510d5..62ec964 100644 +--- a/include/block/blockjob_int.h ++++ b/include/block/blockjob_int.h +@@ -166,6 +166,14 @@ void block_job_sleep_ns(BlockJob *job, int64_t ns); + void block_job_yield(BlockJob *job); + + /** ++ * block_job_ratelimit_get_delay: ++ * ++ * Calculate and return delay for the next request in ns. See the documentation ++ * of ratelimit_calculate_delay() for details. ++ */ ++int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n); ++ ++/** + * block_job_early_fail: + * @bs: The block device. + * +-- +1.8.3.1 + diff --git a/SOURCES/kvm-blockjob-Lie-better-in-child_job_drained_poll.patch b/SOURCES/kvm-blockjob-Lie-better-in-child_job_drained_poll.patch new file mode 100644 index 0000000..b7d191f --- /dev/null +++ b/SOURCES/kvm-blockjob-Lie-better-in-child_job_drained_poll.patch @@ -0,0 +1,102 @@ +From a174500971a42552a30d238bf9ec065d27fd4b32 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:36 +0200 +Subject: [PATCH 45/49] blockjob: Lie better in child_job_drained_poll() + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-39-kwolf@redhat.com> +Patchwork-id: 82192 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 38/42] blockjob: Lie better in child_job_drained_poll() +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +Block jobs claim in .drained_poll() that they are in a quiescent state +as soon as job->deferred_to_main_loop is true. This is obviously wrong, +they still have a completion BH to run. We only get away with this +because commit 91af091f923 added an unconditional aio_poll(false) to the +drain functions, but this is bypassing the regular drain mechanisms. + +However, just removing this and telling that the job is still active +doesn't work either: The completion callbacks themselves call drain +functions (directly, or indirectly with bdrv_reopen), so they would +deadlock then. + +As a better lie, tell that the job is active as long as the BH is +pending, but falsely call it quiescent from the point in the BH when the +completion callback is called. At this point, nested drain calls won't +deadlock because they ignore the job, and outer drains will wait for the +job to really reach a quiescent state because the callback is already +running. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + blockjob.c | 2 +- + include/qemu/job.h | 3 +++ + job.c | 11 ++++++++++- + 3 files changed, 14 insertions(+), 2 deletions(-) + +diff --git a/blockjob.c b/blockjob.c +index 8d27e8e..617d86f 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -164,7 +164,7 @@ static bool child_job_drained_poll(BdrvChild *c) + /* An inactive or completed job doesn't have any pending requests. Jobs + * with !job->busy are either already paused or have a pause point after + * being reentered, so no job driver code will run before they pause. */ +- if (!job->busy || job_is_completed(job) || job->deferred_to_main_loop) { ++ if (!job->busy || job_is_completed(job)) { + return false; + } + +diff --git a/include/qemu/job.h b/include/qemu/job.h +index 35ac7a9..d1710f3 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -76,6 +76,9 @@ typedef struct Job { + * Set to false by the job while the coroutine has yielded and may be + * re-entered by job_enter(). There may still be I/O or event loop activity + * pending. Accessed under block_job_mutex (in blockjob.c). ++ * ++ * When the job is deferred to the main loop, busy is true as long as the ++ * bottom half is still pending. + */ + bool busy; + +diff --git a/job.c b/job.c +index 47b5a11..42af9e2 100644 +--- a/job.c ++++ b/job.c +@@ -852,7 +852,16 @@ static void job_exit(void *opaque) + AioContext *ctx = job->aio_context; + + aio_context_acquire(ctx); ++ ++ /* This is a lie, we're not quiescent, but still doing the completion ++ * callbacks. However, completion callbacks tend to involve operations that ++ * drain block nodes, and if .drained_poll still returned true, we would ++ * deadlock. */ ++ job->busy = false; ++ job_event_idle(job); ++ + job_completed(job); ++ + aio_context_release(ctx); + } + +@@ -867,8 +876,8 @@ static void coroutine_fn job_co_entry(void *opaque) + assert(job && job->driver && job->driver->run); + job_pause_point(job); + job->ret = job->driver->run(job, &job->err); +- job_event_idle(job); + job->deferred_to_main_loop = true; ++ job->busy = true; + aio_bh_schedule_oneshot(qemu_get_aio_context(), job_exit, job); + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-blockjob-Make-block_job_pause_all-keep-a-reference-t.patch b/SOURCES/kvm-blockjob-Make-block_job_pause_all-keep-a-reference-t.patch deleted file mode 100644 index a3c9055..0000000 --- a/SOURCES/kvm-blockjob-Make-block_job_pause_all-keep-a-reference-t.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 03560a7d6e57ca2ba3198d5051acfdd1e345f9a4 Mon Sep 17 00:00:00 2001 -From: Jeffrey Cody -Date: Tue, 5 Dec 2017 16:03:17 +0100 -Subject: [PATCH 12/21] blockjob: Make block_job_pause_all() keep a reference - to the jobs - -RH-Author: Jeffrey Cody -Message-id: -Patchwork-id: 78161 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 12/11] blockjob: Make block_job_pause_all() keep a reference to the jobs -Bugzilla: 1506531 -RH-Acked-by: John Snow -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Stefan Hajnoczi - -From: Alberto Garcia - -Starting from commit 40840e419be31e6a32e6ea24511c74b389d5e0e4 we are -pausing all block jobs during bdrv_reopen_multiple() to prevent any of -them from finishing and removing nodes from the graph while they are -being reopened. - -It turns out that pausing a block job doesn't necessarily prevent it -from finishing: a paused block job can still run its exit function -from the main loop and call block_job_completed(). The mirror block -job in particular always goes to the main loop while it is paused (by -virtue of the bdrv_drained_begin() call in mirror_run()). - -Destroying a paused block job during bdrv_reopen_multiple() has two -consequences: - - 1) The references to the nodes involved in the job are released, - possibly destroying some of them. If those nodes were in the - reopen queue this would trigger the problem originally described - in commit 40840e419be, crashing QEMU. - - 2) At the end of bdrv_reopen_multiple(), bdrv_drain_all_end() would - not be doing all necessary bdrv_parent_drained_end() calls. - -I can reproduce problem 1) easily with iotest 030 by increasing -STREAM_BUFFER_SIZE from 512KB to 8MB in block/stream.c, or by tweaking -the iotest like in this example: - - https://lists.gnu.org/archive/html/qemu-block/2017-11/msg00934.html - -This patch keeps an additional reference to all block jobs between -block_job_pause_all() and block_job_resume_all(), guaranteeing that -they are kept alive. - -Signed-off-by: Alberto Garcia -Signed-off-by: Kevin Wolf -(cherry picked from commit 3d5d319e1221082974711af1d09d82f0755c1698) -Signed-off-by: Jeff Cody -Signed-off-by: Miroslav Rezanina ---- - blockjob.c | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - -diff --git a/blockjob.c b/blockjob.c -index 84f526a..63aecce 100644 ---- a/blockjob.c -+++ b/blockjob.c -@@ -730,6 +730,7 @@ void block_job_pause_all(void) - AioContext *aio_context = blk_get_aio_context(job->blk); - - aio_context_acquire(aio_context); -+ block_job_ref(job); - block_job_pause(job); - aio_context_release(aio_context); - } -@@ -808,12 +809,14 @@ void coroutine_fn block_job_pause_point(BlockJob *job) - - void block_job_resume_all(void) - { -- BlockJob *job = NULL; -- while ((job = block_job_next(job))) { -+ BlockJob *job, *next; -+ -+ QLIST_FOREACH_SAFE(job, &block_jobs, job_list, next) { - AioContext *aio_context = blk_get_aio_context(job->blk); - - aio_context_acquire(aio_context); - block_job_resume(job); -+ block_job_unref(job); - aio_context_release(aio_context); - } - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-blockjob-Move-RateLimit-to-BlockJob.patch b/SOURCES/kvm-blockjob-Move-RateLimit-to-BlockJob.patch new file mode 100644 index 0000000..ce1bace --- /dev/null +++ b/SOURCES/kvm-blockjob-Move-RateLimit-to-BlockJob.patch @@ -0,0 +1,179 @@ +From cc5d2ab40aeaca344047ae0b6655a69c67fd7ada Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:47:53 +0200 +Subject: [PATCH 24/89] blockjob: Move RateLimit to BlockJob + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-11-kwolf@redhat.com> +Patchwork-id: 81088 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 10/73] blockjob: Move RateLimit to BlockJob +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +Every block job has a RateLimit, and they all do the exact same thing +with it, so it should be common infrastructure. Move the struct field +for a start. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +Reviewed-by: Max Reitz +Reviewed-by: John Snow +(cherry picked from commit f05fee508f538ca262d2ab19bcd8772196efe848) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/backup.c | 5 ++--- + block/commit.c | 5 ++--- + block/mirror.c | 6 +++--- + block/stream.c | 5 ++--- + include/block/blockjob.h | 4 ++++ + 5 files changed, 13 insertions(+), 12 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index 5d95805..7585c43 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -35,7 +35,6 @@ typedef struct BackupBlockJob { + /* bitmap for sync=incremental */ + BdrvDirtyBitmap *sync_bitmap; + MirrorSyncMode sync_mode; +- RateLimit limit; + BlockdevOnError on_source_error; + BlockdevOnError on_target_error; + CoRwlock flush_rwlock; +@@ -199,7 +198,7 @@ static void backup_set_speed(BlockJob *job, int64_t speed, Error **errp) + error_setg(errp, QERR_INVALID_PARAMETER, "speed"); + return; + } +- ratelimit_set_speed(&s->limit, speed, SLICE_TIME); ++ ratelimit_set_speed(&s->common.limit, speed, SLICE_TIME); + } + + static void backup_cleanup_sync_bitmap(BackupBlockJob *job, int ret) +@@ -346,7 +345,7 @@ static bool coroutine_fn yield_and_check(BackupBlockJob *job) + * (without, VM does not reboot) + */ + if (job->common.speed) { +- uint64_t delay_ns = ratelimit_calculate_delay(&job->limit, ++ uint64_t delay_ns = ratelimit_calculate_delay(&job->common.limit, + job->bytes_read); + job->bytes_read = 0; + block_job_sleep_ns(&job->common, delay_ns); +diff --git a/block/commit.c b/block/commit.c +index 50b191c..beec5d0 100644 +--- a/block/commit.c ++++ b/block/commit.c +@@ -35,7 +35,6 @@ enum { + + typedef struct CommitBlockJob { + BlockJob common; +- RateLimit limit; + BlockDriverState *commit_top_bs; + BlockBackend *top; + BlockBackend *base; +@@ -201,7 +200,7 @@ static void coroutine_fn commit_run(void *opaque) + block_job_progress_update(&s->common, n); + + if (copy && s->common.speed) { +- delay_ns = ratelimit_calculate_delay(&s->limit, n); ++ delay_ns = ratelimit_calculate_delay(&s->common.limit, n); + } else { + delay_ns = 0; + } +@@ -225,7 +224,7 @@ static void commit_set_speed(BlockJob *job, int64_t speed, Error **errp) + error_setg(errp, QERR_INVALID_PARAMETER, "speed"); + return; + } +- ratelimit_set_speed(&s->limit, speed, SLICE_TIME); ++ ratelimit_set_speed(&s->common.limit, speed, SLICE_TIME); + } + + static const BlockJobDriver commit_job_driver = { +diff --git a/block/mirror.c b/block/mirror.c +index ed711b5..a515ec1 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -36,7 +36,6 @@ typedef struct MirrorBuffer { + + typedef struct MirrorBlockJob { + BlockJob common; +- RateLimit limit; + BlockBackend *target; + BlockDriverState *mirror_top_bs; + BlockDriverState *source; +@@ -450,7 +449,8 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s) + offset += io_bytes; + nb_chunks -= DIV_ROUND_UP(io_bytes, s->granularity); + if (s->common.speed) { +- delay_ns = ratelimit_calculate_delay(&s->limit, io_bytes_acct); ++ delay_ns = ratelimit_calculate_delay(&s->common.limit, ++ io_bytes_acct); + } + } + return delay_ns; +@@ -916,7 +916,7 @@ static void mirror_set_speed(BlockJob *job, int64_t speed, Error **errp) + error_setg(errp, QERR_INVALID_PARAMETER, "speed"); + return; + } +- ratelimit_set_speed(&s->limit, speed, SLICE_TIME); ++ ratelimit_set_speed(&s->common.limit, speed, SLICE_TIME); + } + + static void mirror_complete(BlockJob *job, Error **errp) +diff --git a/block/stream.c b/block/stream.c +index 8369852..a1d4768 100644 +--- a/block/stream.c ++++ b/block/stream.c +@@ -33,7 +33,6 @@ enum { + + typedef struct StreamBlockJob { + BlockJob common; +- RateLimit limit; + BlockDriverState *base; + BlockdevOnError on_error; + char *backing_file_str; +@@ -189,7 +188,7 @@ static void coroutine_fn stream_run(void *opaque) + /* Publish progress */ + block_job_progress_update(&s->common, n); + if (copy && s->common.speed) { +- delay_ns = ratelimit_calculate_delay(&s->limit, n); ++ delay_ns = ratelimit_calculate_delay(&s->common.limit, n); + } else { + delay_ns = 0; + } +@@ -219,7 +218,7 @@ static void stream_set_speed(BlockJob *job, int64_t speed, Error **errp) + error_setg(errp, QERR_INVALID_PARAMETER, "speed"); + return; + } +- ratelimit_set_speed(&s->limit, speed, SLICE_TIME); ++ ratelimit_set_speed(&s->common.limit, speed, SLICE_TIME); + } + + static const BlockJobDriver stream_job_driver = { +diff --git a/include/block/blockjob.h b/include/block/blockjob.h +index a2cc522..22bf418 100644 +--- a/include/block/blockjob.h ++++ b/include/block/blockjob.h +@@ -27,6 +27,7 @@ + #define BLOCKJOB_H + + #include "block/block.h" ++#include "qemu/ratelimit.h" + + typedef struct BlockJobDriver BlockJobDriver; + typedef struct BlockJobTxn BlockJobTxn; +@@ -118,6 +119,9 @@ typedef struct BlockJob { + /** Speed that was set with @block_job_set_speed. */ + int64_t speed; + ++ /** Rate limiting data structure for implementing @speed. */ ++ RateLimit limit; ++ + /** The completion function that will be called when the job completes. */ + BlockCompletionFunc *cb; + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-blockjob-Remove-BlockJob.driver.patch b/SOURCES/kvm-blockjob-Remove-BlockJob.driver.patch new file mode 100644 index 0000000..439a4c9 --- /dev/null +++ b/SOURCES/kvm-blockjob-Remove-BlockJob.driver.patch @@ -0,0 +1,96 @@ +From 0991b141d8b65fb00b9261532faeb65a93d4d650 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:34 +0200 +Subject: [PATCH 65/89] blockjob: Remove BlockJob.driver + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-52-kwolf@redhat.com> +Patchwork-id: 81123 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 51/73] blockjob: Remove BlockJob.driver +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +BlockJob.driver is redundant with Job.driver and only used in very few +places any more. Remove it. + +Signed-off-by: Kevin Wolf +(cherry picked from commit 9f6bb4c004a6458227b9eec6aff3f79afe159699) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + blockjob.c | 17 ++++++++++------- + include/block/blockjob.h | 3 --- + 2 files changed, 10 insertions(+), 10 deletions(-) + +diff --git a/blockjob.c b/blockjob.c +index 5c8ff6f..0306533 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -103,10 +103,12 @@ static void block_job_attached_aio_context(AioContext *new_context, + void *opaque) + { + BlockJob *job = opaque; ++ const JobDriver *drv = job->job.driver; ++ BlockJobDriver *bjdrv = container_of(drv, BlockJobDriver, job_driver); + + job->job.aio_context = new_context; +- if (job->driver->attached_aio_context) { +- job->driver->attached_aio_context(job, new_context); ++ if (bjdrv->attached_aio_context) { ++ bjdrv->attached_aio_context(job, new_context); + } + + job_resume(&job->job); +@@ -115,10 +117,12 @@ static void block_job_attached_aio_context(AioContext *new_context, + void block_job_drain(Job *job) + { + BlockJob *bjob = container_of(job, BlockJob, job); ++ const JobDriver *drv = job->driver; ++ BlockJobDriver *bjdrv = container_of(drv, BlockJobDriver, job_driver); + + blk_drain(bjob->blk); +- if (bjob->driver->drain) { +- bjob->driver->drain(bjob); ++ if (bjdrv->drain) { ++ bjdrv->drain(bjob); + } + } + +@@ -201,7 +205,7 @@ bool block_job_is_internal(BlockJob *job) + + const BlockJobDriver *block_job_driver(BlockJob *job) + { +- return job->driver; ++ return container_of(job->job.driver, BlockJobDriver, job_driver); + } + + /* Assumes the job_mutex is held */ +@@ -386,8 +390,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + assert(job->job.driver->user_resume == &block_job_user_resume); + assert(job->job.driver->drain == &block_job_drain); + +- job->driver = driver; +- job->blk = blk; ++ job->blk = blk; + + job->finalize_cancelled_notifier.notify = block_job_event_cancelled; + job->finalize_completed_notifier.notify = block_job_event_completed; +diff --git a/include/block/blockjob.h b/include/block/blockjob.h +index 3021d11..32c00b7 100644 +--- a/include/block/blockjob.h ++++ b/include/block/blockjob.h +@@ -43,9 +43,6 @@ typedef struct BlockJob { + /** Data belonging to the generic Job infrastructure */ + Job job; + +- /** The job type, including the job vtable. */ +- const BlockJobDriver *driver; +- + /** The block device on which the job is operating. */ + BlockBackend *blk; + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-blockjob-Remove-the-job-from-the-list-earlier-in-blo.patch b/SOURCES/kvm-blockjob-Remove-the-job-from-the-list-earlier-in-blo.patch deleted file mode 100644 index 52181fe..0000000 --- a/SOURCES/kvm-blockjob-Remove-the-job-from-the-list-earlier-in-blo.patch +++ /dev/null @@ -1,57 +0,0 @@ -From f64ca42ce16a0df89d4abba838d00ea7bc7e4da9 Mon Sep 17 00:00:00 2001 -From: Jeffrey Cody -Date: Thu, 30 Nov 2017 22:49:11 +0100 -Subject: [PATCH 07/21] blockjob: Remove the job from the list earlier in - block_job_unref() - -RH-Author: Jeffrey Cody -Message-id: <8fc0c61d51c41fdde7d809502e5025371f89c4c7.1511985875.git.jcody@redhat.com> -Patchwork-id: 78045 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 07/11] blockjob: Remove the job from the list earlier in block_job_unref() -Bugzilla: 1506531 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: John Snow - -From: Alberto Garcia - -When destroying a block job in block_job_unref() we should remove it -from the job list before calling block_job_remove_all_bdrv(). - -This is because removing the BDSs can trigger an aio_poll() and wake -up other jobs that might attempt to use the block job list. If that -happens the job we're currently destroying should not be in that list -anymore. - -Signed-off-by: Alberto Garcia -Signed-off-by: Kevin Wolf -(cherry picked from commit 0a3e155f3f5ec9b6f12d00894c7701b3cbb66590) -Signed-off-by: Jeff Cody -Signed-off-by: Miroslav Rezanina ---- - blockjob.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/blockjob.c b/blockjob.c -index c3cf9a2..2509bba 100644 ---- a/blockjob.c -+++ b/blockjob.c -@@ -152,6 +152,7 @@ void block_job_unref(BlockJob *job) - { - if (--job->refcnt == 0) { - BlockDriverState *bs = blk_bs(job->blk); -+ QLIST_REMOVE(job, job_list); - bs->job = NULL; - block_job_remove_all_bdrv(job); - blk_remove_aio_context_notifier(job->blk, -@@ -160,7 +161,6 @@ void block_job_unref(BlockJob *job) - blk_unref(job->blk); - error_free(job->blocker); - g_free(job->id); -- QLIST_REMOVE(job, job_list); - g_free(job); - } - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-blockjob-Split-block_job_event_pending.patch b/SOURCES/kvm-blockjob-Split-block_job_event_pending.patch new file mode 100644 index 0000000..fbf05b1 --- /dev/null +++ b/SOURCES/kvm-blockjob-Split-block_job_event_pending.patch @@ -0,0 +1,92 @@ +From 192def6a1acb30c3ff81e130fa73849e19a9ee87 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:14 +0200 +Subject: [PATCH 45/89] blockjob: Split block_job_event_pending() + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-32-kwolf@redhat.com> +Patchwork-id: 81071 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 31/73] blockjob: Split block_job_event_pending() +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +block_job_event_pending() doesn't only send a QMP event, but it also +transitions to the PENDING state. Split the function so that we get one +part only sending the event (like other block_job_event_* functions) and +another part that does the state transition. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +(cherry picked from commit 5d4f376998bc6b01402b90634385b082b2eb5c5b) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + blockjob.c | 27 ++++++++++++++++++--------- + 1 file changed, 18 insertions(+), 9 deletions(-) + +diff --git a/blockjob.c b/blockjob.c +index d9d8ff7..b4334fb 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -38,7 +38,7 @@ + + static void block_job_event_cancelled(BlockJob *job); + static void block_job_event_completed(BlockJob *job, const char *msg); +-static int block_job_event_pending(BlockJob *job); ++static void block_job_event_pending(BlockJob *job); + + /* Transactional group of block jobs */ + struct BlockJobTxn { +@@ -500,6 +500,15 @@ static void block_job_do_finalize(BlockJob *job) + } + } + ++static int block_job_transition_to_pending(BlockJob *job) ++{ ++ job_state_transition(&job->job, JOB_STATUS_PENDING); ++ if (!job->job.auto_finalize) { ++ block_job_event_pending(job); ++ } ++ return 0; ++} ++ + static void block_job_completed_txn_success(BlockJob *job) + { + BlockJobTxn *txn = job->txn; +@@ -518,7 +527,7 @@ static void block_job_completed_txn_success(BlockJob *job) + assert(other_job->ret == 0); + } + +- block_job_txn_apply(txn, block_job_event_pending, false); ++ block_job_txn_apply(txn, block_job_transition_to_pending, false); + + /* If no jobs need manual finalization, automatically do so */ + if (block_job_txn_apply(txn, block_job_needs_finalize, false) == 0) { +@@ -733,15 +742,15 @@ static void block_job_event_completed(BlockJob *job, const char *msg) + &error_abort); + } + +-static int block_job_event_pending(BlockJob *job) ++static void block_job_event_pending(BlockJob *job) + { +- job_state_transition(&job->job, JOB_STATUS_PENDING); +- if (!job->job.auto_finalize && !block_job_is_internal(job)) { +- qapi_event_send_block_job_pending(job_type(&job->job), +- job->job.id, +- &error_abort); ++ if (block_job_is_internal(job)) { ++ return; + } +- return 0; ++ ++ qapi_event_send_block_job_pending(job_type(&job->job), ++ job->job.id, ++ &error_abort); + } + + /* +-- +1.8.3.1 + diff --git a/SOURCES/kvm-blockjob-Update-block-job-pause-resume-documentation.patch b/SOURCES/kvm-blockjob-Update-block-job-pause-resume-documentation.patch new file mode 100644 index 0000000..d0c0c69 --- /dev/null +++ b/SOURCES/kvm-blockjob-Update-block-job-pause-resume-documentation.patch @@ -0,0 +1,54 @@ +From f00178eea8078521e2d3020df4873d27b16adacc Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:47:57 +0200 +Subject: [PATCH 28/89] blockjob: Update block-job-pause/resume documentation + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-15-kwolf@redhat.com> +Patchwork-id: 81069 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 14/73] blockjob: Update block-job-pause/resume documentation +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +Commit 0ec4dfb8d changed block-job_pause/resume so that they return an +error if they don't do anything because the job is already +paused/running. It forgot to update the documentation, so do that now. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +Reviewed-by: John Snow +(cherry picked from commit cd44d96be90e7767c6fb8f33b90939eb58814956) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + qapi/block-core.json | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 9012d00..d24c12b 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -2338,8 +2338,7 @@ + # + # This command returns immediately after marking the active background block + # operation for pausing. It is an error to call this command if no +-# operation is in progress. Pausing an already paused job has no cumulative +-# effect; a single block-job-resume command will resume the job. ++# operation is in progress or if the job is already paused. + # + # The operation will pause as soon as possible. No event is emitted when + # the operation is actually paused. Cancelling a paused job automatically +@@ -2363,7 +2362,7 @@ + # + # This command returns immediately after resuming a paused background block + # operation. It is an error to call this command if no operation is in +-# progress. Resuming an already running job is not an error. ++# progress or if the job is not paused. + # + # This command also clears the error status of the job. + # +-- +1.8.3.1 + diff --git a/SOURCES/kvm-blockjob-Wake-up-BDS-when-job-becomes-idle.patch b/SOURCES/kvm-blockjob-Wake-up-BDS-when-job-becomes-idle.patch new file mode 100644 index 0000000..32f79f2 --- /dev/null +++ b/SOURCES/kvm-blockjob-Wake-up-BDS-when-job-becomes-idle.patch @@ -0,0 +1,159 @@ +From 29117d8ea323429138020a8de63119f15da01d83 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:25 +0200 +Subject: [PATCH 34/49] blockjob: Wake up BDS when job becomes idle + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-28-kwolf@redhat.com> +Patchwork-id: 82180 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 27/42] blockjob: Wake up BDS when job becomes idle +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +In the context of draining a BDS, the .drained_poll callback of block +jobs is called. If this returns true (i.e. there is still some activity +pending), the drain operation may call aio_poll() with blocking=true to +wait for completion. + +As soon as the pending activity is completed and the job finally arrives +in a quiescent state (i.e. its coroutine either yields with busy=false +or terminates), the block job must notify the aio_poll() loop to wake +up, otherwise we get a deadlock if both are running in different +threads. + +Signed-off-by: Kevin Wolf +Reviewed-by: Fam Zheng +Reviewed-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + blockjob.c | 18 ++++++++++++++++++ + include/block/blockjob.h | 13 +++++++++++++ + include/qemu/job.h | 3 +++ + job.c | 7 +++++++ + 4 files changed, 41 insertions(+) + +diff --git a/blockjob.c b/blockjob.c +index be5903a..8d27e8e 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -221,6 +221,22 @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs, + return 0; + } + ++void block_job_wakeup_all_bdrv(BlockJob *job) ++{ ++ GSList *l; ++ ++ for (l = job->nodes; l; l = l->next) { ++ BdrvChild *c = l->data; ++ bdrv_wakeup(c->bs); ++ } ++} ++ ++static void block_job_on_idle(Notifier *n, void *opaque) ++{ ++ BlockJob *job = opaque; ++ block_job_wakeup_all_bdrv(job); ++} ++ + bool block_job_is_internal(BlockJob *job) + { + return (job->job.id == NULL); +@@ -419,6 +435,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + job->finalize_completed_notifier.notify = block_job_event_completed; + job->pending_notifier.notify = block_job_event_pending; + job->ready_notifier.notify = block_job_event_ready; ++ job->idle_notifier.notify = block_job_on_idle; + + notifier_list_add(&job->job.on_finalize_cancelled, + &job->finalize_cancelled_notifier); +@@ -426,6 +443,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + &job->finalize_completed_notifier); + notifier_list_add(&job->job.on_pending, &job->pending_notifier); + notifier_list_add(&job->job.on_ready, &job->ready_notifier); ++ notifier_list_add(&job->job.on_idle, &job->idle_notifier); + + error_setg(&job->blocker, "block device is in use by block job: %s", + job_type_str(&job->job)); +diff --git a/include/block/blockjob.h b/include/block/blockjob.h +index 32c00b7..2290bbb 100644 +--- a/include/block/blockjob.h ++++ b/include/block/blockjob.h +@@ -70,6 +70,9 @@ typedef struct BlockJob { + /** Called when the job transitions to READY */ + Notifier ready_notifier; + ++ /** Called when the job coroutine yields or terminates */ ++ Notifier idle_notifier; ++ + /** BlockDriverStates that are involved in this block job */ + GSList *nodes; + } BlockJob; +@@ -119,6 +122,16 @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs, + void block_job_remove_all_bdrv(BlockJob *job); + + /** ++ * block_job_wakeup_all_bdrv: ++ * @job: The block job ++ * ++ * Calls bdrv_wakeup() for all BlockDriverStates that have been added to the ++ * job. This function is to be called whenever child_job_drained_poll() would ++ * go from true to false to notify waiting drain requests. ++ */ ++void block_job_wakeup_all_bdrv(BlockJob *job); ++ ++/** + * block_job_set_speed: + * @job: The job to set the speed for. + * @speed: The new value +diff --git a/include/qemu/job.h b/include/qemu/job.h +index fdaa06f..407d549 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -156,6 +156,9 @@ typedef struct Job { + /** Notifiers called when the job transitions to READY */ + NotifierList on_ready; + ++ /** Notifiers called when the job coroutine yields or terminates */ ++ NotifierList on_idle; ++ + /** Element of the list of jobs */ + QLIST_ENTRY(Job) job_list; + +diff --git a/job.c b/job.c +index db53163..5a0ccc7 100644 +--- a/job.c ++++ b/job.c +@@ -397,6 +397,11 @@ static void job_event_ready(Job *job) + notifier_list_notify(&job->on_ready, job); + } + ++static void job_event_idle(Job *job) ++{ ++ notifier_list_notify(&job->on_idle, job); ++} ++ + void job_enter_cond(Job *job, bool(*fn)(Job *job)) + { + if (!job_started(job)) { +@@ -442,6 +447,7 @@ static void coroutine_fn job_do_yield(Job *job, uint64_t ns) + timer_mod(&job->sleep_timer, ns); + } + job->busy = false; ++ job_event_idle(job); + job_unlock(); + qemu_coroutine_yield(); + +@@ -860,6 +866,7 @@ static void coroutine_fn job_co_entry(void *opaque) + assert(job && job->driver && job->driver->run); + job_pause_point(job); + job->ret = job->driver->run(job, &job->err); ++ job_event_idle(job); + job->deferred_to_main_loop = true; + aio_bh_schedule_oneshot(qemu_get_aio_context(), job_exit, job); + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-blockjob-Wrappers-for-progress-counter-access.patch b/SOURCES/kvm-blockjob-Wrappers-for-progress-counter-access.patch new file mode 100644 index 0000000..eead363 --- /dev/null +++ b/SOURCES/kvm-blockjob-Wrappers-for-progress-counter-access.patch @@ -0,0 +1,311 @@ +From c8cf3cfff0a6fd9e059190a97d38b0d1a3223e8e Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:47:52 +0200 +Subject: [PATCH 23/89] blockjob: Wrappers for progress counter access + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-10-kwolf@redhat.com> +Patchwork-id: 81078 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 09/73] blockjob: Wrappers for progress counter access +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +Block job drivers are not expected to mess with the internals of the +BlockJob object, so provide wrapper functions for one of the cases where +they still do it: Updating the progress counter. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +Reviewed-by: Max Reitz +Reviewed-by: John Snow +(cherry picked from commit 05df8a6a2b4e36e8d69de2130e616d5ac28e8837) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/backup.c | 22 +++++++++++++--------- + block/commit.c | 16 ++++++++-------- + block/mirror.c | 11 +++++------ + block/stream.c | 14 ++++++++------ + blockjob.c | 10 ++++++++++ + include/block/blockjob.h | 19 +++++++++++++++++++ + 6 files changed, 63 insertions(+), 29 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index 453cd62..5d95805 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -39,6 +39,7 @@ typedef struct BackupBlockJob { + BlockdevOnError on_source_error; + BlockdevOnError on_target_error; + CoRwlock flush_rwlock; ++ uint64_t len; + uint64_t bytes_read; + int64_t cluster_size; + bool compress; +@@ -118,7 +119,7 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job, + + trace_backup_do_cow_process(job, start); + +- n = MIN(job->cluster_size, job->common.len - start); ++ n = MIN(job->cluster_size, job->len - start); + + if (!bounce_buffer) { + bounce_buffer = blk_blockalign(blk, job->cluster_size); +@@ -159,7 +160,7 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job, + * offset field is an opaque progress value, it is not a disk offset. + */ + job->bytes_read += n; +- job->common.offset += n; ++ block_job_progress_update(&job->common, n); + } + + out: +@@ -261,7 +262,7 @@ void backup_do_checkpoint(BlockJob *job, Error **errp) + return; + } + +- len = DIV_ROUND_UP(backup_job->common.len, backup_job->cluster_size); ++ len = DIV_ROUND_UP(backup_job->len, backup_job->cluster_size); + hbitmap_set(backup_job->copy_bitmap, 0, len); + } + +@@ -420,8 +421,9 @@ static void backup_incremental_init_copy_bitmap(BackupBlockJob *job) + bdrv_set_dirty_iter(dbi, next_cluster * job->cluster_size); + } + +- job->common.offset = job->common.len - +- hbitmap_count(job->copy_bitmap) * job->cluster_size; ++ /* TODO block_job_progress_set_remaining() would make more sense */ ++ block_job_progress_update(&job->common, ++ job->len - hbitmap_count(job->copy_bitmap) * job->cluster_size); + + bdrv_dirty_iter_free(dbi); + } +@@ -437,7 +439,9 @@ static void coroutine_fn backup_run(void *opaque) + QLIST_INIT(&job->inflight_reqs); + qemu_co_rwlock_init(&job->flush_rwlock); + +- nb_clusters = DIV_ROUND_UP(job->common.len, job->cluster_size); ++ nb_clusters = DIV_ROUND_UP(job->len, job->cluster_size); ++ block_job_progress_set_remaining(&job->common, job->len); ++ + job->copy_bitmap = hbitmap_alloc(nb_clusters, 0); + if (job->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) { + backup_incremental_init_copy_bitmap(job); +@@ -461,7 +465,7 @@ static void coroutine_fn backup_run(void *opaque) + ret = backup_run_incremental(job); + } else { + /* Both FULL and TOP SYNC_MODE's require copying.. */ +- for (offset = 0; offset < job->common.len; ++ for (offset = 0; offset < job->len; + offset += job->cluster_size) { + bool error_is_read; + int alloced = 0; +@@ -620,7 +624,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, + goto error; + } + +- /* job->common.len is fixed, so we can't allow resize */ ++ /* job->len is fixed, so we can't allow resize */ + job = block_job_create(job_id, &backup_job_driver, txn, bs, + BLK_PERM_CONSISTENT_READ, + BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | +@@ -676,7 +680,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, + /* Required permissions are already taken with target's blk_new() */ + block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL, + &error_abort); +- job->common.len = len; ++ job->len = len; + + return &job->common; + +diff --git a/block/commit.c b/block/commit.c +index 1432bae..50b191c 100644 +--- a/block/commit.c ++++ b/block/commit.c +@@ -146,21 +146,21 @@ static void coroutine_fn commit_run(void *opaque) + int64_t n = 0; /* bytes */ + void *buf = NULL; + int bytes_written = 0; +- int64_t base_len; ++ int64_t len, base_len; + +- ret = s->common.len = blk_getlength(s->top); +- +- if (s->common.len < 0) { ++ ret = len = blk_getlength(s->top); ++ if (len < 0) { + goto out; + } ++ block_job_progress_set_remaining(&s->common, len); + + ret = base_len = blk_getlength(s->base); + if (base_len < 0) { + goto out; + } + +- if (base_len < s->common.len) { +- ret = blk_truncate(s->base, s->common.len, PREALLOC_MODE_OFF, NULL); ++ if (base_len < len) { ++ ret = blk_truncate(s->base, len, PREALLOC_MODE_OFF, NULL); + if (ret) { + goto out; + } +@@ -168,7 +168,7 @@ static void coroutine_fn commit_run(void *opaque) + + buf = blk_blockalign(s->top, COMMIT_BUFFER_SIZE); + +- for (offset = 0; offset < s->common.len; offset += n) { ++ for (offset = 0; offset < len; offset += n) { + bool copy; + + /* Note that even when no rate limit is applied we need to yield +@@ -198,7 +198,7 @@ static void coroutine_fn commit_run(void *opaque) + } + } + /* Publish progress */ +- s->common.offset += n; ++ block_job_progress_update(&s->common, n); + + if (copy && s->common.speed) { + delay_ns = ratelimit_calculate_delay(&s->limit, n); +diff --git a/block/mirror.c b/block/mirror.c +index 003f957..ed711b5 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -121,7 +121,7 @@ static void mirror_iteration_done(MirrorOp *op, int ret) + bitmap_set(s->cow_bitmap, chunk_num, nb_chunks); + } + if (!s->initial_zeroing_ongoing) { +- s->common.offset += op->bytes; ++ block_job_progress_update(&s->common, op->bytes); + } + } + qemu_iovec_destroy(&op->qiov); +@@ -792,11 +792,10 @@ static void coroutine_fn mirror_run(void *opaque) + block_job_pause_point(&s->common); + + cnt = bdrv_get_dirty_count(s->dirty_bitmap); +- /* s->common.offset contains the number of bytes already processed so +- * far, cnt is the number of dirty bytes remaining and +- * s->bytes_in_flight is the number of bytes currently being +- * processed; together those are the current total operation length */ +- s->common.len = s->common.offset + s->bytes_in_flight + cnt; ++ /* cnt is the number of dirty bytes remaining and s->bytes_in_flight is ++ * the number of bytes currently being processed; together those are ++ * the current remaining operation length */ ++ block_job_progress_set_remaining(&s->common, s->bytes_in_flight + cnt); + + /* Note that even when no rate limit is applied we need to yield + * periodically with no pending I/O so that bdrv_drain_all() returns. +diff --git a/block/stream.c b/block/stream.c +index 1a85708..8369852 100644 +--- a/block/stream.c ++++ b/block/stream.c +@@ -107,6 +107,7 @@ static void coroutine_fn stream_run(void *opaque) + BlockBackend *blk = s->common.blk; + BlockDriverState *bs = blk_bs(blk); + BlockDriverState *base = s->base; ++ int64_t len; + int64_t offset = 0; + uint64_t delay_ns = 0; + int error = 0; +@@ -118,11 +119,12 @@ static void coroutine_fn stream_run(void *opaque) + goto out; + } + +- s->common.len = bdrv_getlength(bs); +- if (s->common.len < 0) { +- ret = s->common.len; ++ len = bdrv_getlength(bs); ++ if (len < 0) { ++ ret = len; + goto out; + } ++ block_job_progress_set_remaining(&s->common, len); + + buf = qemu_blockalign(bs, STREAM_BUFFER_SIZE); + +@@ -135,7 +137,7 @@ static void coroutine_fn stream_run(void *opaque) + bdrv_enable_copy_on_read(bs); + } + +- for ( ; offset < s->common.len; offset += n) { ++ for ( ; offset < len; offset += n) { + bool copy; + + /* Note that even when no rate limit is applied we need to yield +@@ -159,7 +161,7 @@ static void coroutine_fn stream_run(void *opaque) + + /* Finish early if end of backing file has been reached */ + if (ret == 0 && n == 0) { +- n = s->common.len - offset; ++ n = len - offset; + } + + copy = (ret == 1); +@@ -185,7 +187,7 @@ static void coroutine_fn stream_run(void *opaque) + ret = 0; + + /* Publish progress */ +- s->common.offset += n; ++ block_job_progress_update(&s->common, n); + if (copy && s->common.speed) { + delay_ns = ratelimit_calculate_delay(&s->limit, n); + } else { +diff --git a/blockjob.c b/blockjob.c +index 0033b96..d0a2ac5 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -818,6 +818,16 @@ int block_job_complete_sync(BlockJob *job, Error **errp) + return block_job_finish_sync(job, &block_job_complete, errp); + } + ++void block_job_progress_update(BlockJob *job, uint64_t done) ++{ ++ job->offset += done; ++} ++ ++void block_job_progress_set_remaining(BlockJob *job, uint64_t remaining) ++{ ++ job->len = job->offset + remaining; ++} ++ + BlockJobInfo *block_job_query(BlockJob *job, Error **errp) + { + BlockJobInfo *info; +diff --git a/include/block/blockjob.h b/include/block/blockjob.h +index fc645da..a2cc522 100644 +--- a/include/block/blockjob.h ++++ b/include/block/blockjob.h +@@ -278,6 +278,25 @@ void block_job_finalize(BlockJob *job, Error **errp); + void block_job_dismiss(BlockJob **job, Error **errp); + + /** ++ * block_job_progress_update: ++ * @job: The job that has made progress ++ * @done: How much progress the job made ++ * ++ * Updates the progress counter of the job. ++ */ ++void block_job_progress_update(BlockJob *job, uint64_t done); ++ ++/** ++ * block_job_progress_set_remaining: ++ * @job: The job whose expected progress end value is set ++ * @remaining: Expected end value of the progress counter of the job ++ * ++ * Sets the expected end value of the progress counter of a job so that a ++ * completion percentage can be calculated when the progress is updated. ++ */ ++void block_job_progress_set_remaining(BlockJob *job, uint64_t remaining); ++ ++/** + * block_job_query: + * @job: The job to get information about. + * +-- +1.8.3.1 + diff --git a/SOURCES/kvm-blockjob-do-not-allow-coroutine-double-entry-or-entr.patch b/SOURCES/kvm-blockjob-do-not-allow-coroutine-double-entry-or-entr.patch deleted file mode 100644 index dc9b7c8..0000000 --- a/SOURCES/kvm-blockjob-do-not-allow-coroutine-double-entry-or-entr.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 01dd04dfd1421d041da935e7a22987d0883b4353 Mon Sep 17 00:00:00 2001 -From: Jeffrey Cody -Date: Thu, 30 Nov 2017 22:49:07 +0100 -Subject: [PATCH 03/21] blockjob: do not allow coroutine double entry or - entry-after-completion - -RH-Author: Jeffrey Cody -Message-id: <36a71db70d56ebdb223c760e682a146ad91d97ad.1511985875.git.jcody@redhat.com> -Patchwork-id: 78041 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 03/11] blockjob: do not allow coroutine double entry or entry-after-completion -Bugzilla: 1506531 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: John Snow - -When block_job_sleep_ns() is called, the co-routine is scheduled for -future execution. If we allow the job to be re-entered prior to the -scheduled time, we present a race condition in which a coroutine can be -entered recursively, or even entered after the coroutine is deleted. - -The job->busy flag is used by blockjobs when a coroutine is busy -executing. The function 'block_job_enter()' obeys the busy flag, -and will not enter a coroutine if set. If we sleep a job, we need to -leave the busy flag set, so that subsequent calls to block_job_enter() -are prevented. - -This changes the prior behavior of block_job_cancel() being able to -immediately wake up and cancel a job; in practice, this should not be an -issue, as the coroutine sleep times are generally very small, and the -cancel will occur the next time the coroutine wakes up. - -This fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1508708 - -Signed-off-by: Jeff Cody -Reviewed-by: Stefan Hajnoczi -(cherry picked from commit 4afeffc8572f40d8844b946a30c00b10da4442b1) -Signed-off-by: Jeff Cody -Signed-off-by: Miroslav Rezanina ---- - blockjob.c | 7 +++++-- - include/block/blockjob_int.h | 3 ++- - 2 files changed, 7 insertions(+), 3 deletions(-) - -diff --git a/blockjob.c b/blockjob.c -index 70a7818..c3cf9a2 100644 ---- a/blockjob.c -+++ b/blockjob.c -@@ -797,11 +797,14 @@ void block_job_sleep_ns(BlockJob *job, QEMUClockType type, int64_t ns) - return; - } - -- job->busy = false; -+ /* We need to leave job->busy set here, because when we have -+ * put a coroutine to 'sleep', we have scheduled it to run in -+ * the future. We cannot enter that same coroutine again before -+ * it wakes and runs, otherwise we risk double-entry or entry after -+ * completion. */ - if (!block_job_should_pause(job)) { - co_aio_sleep_ns(blk_get_aio_context(job->blk), type, ns); - } -- job->busy = true; - - block_job_pause_point(job); - } -diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h -index f13ad05..43f3be2 100644 ---- a/include/block/blockjob_int.h -+++ b/include/block/blockjob_int.h -@@ -143,7 +143,8 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, - * @ns: How many nanoseconds to stop for. - * - * Put the job to sleep (assuming that it wasn't canceled) for @ns -- * nanoseconds. Canceling the job will interrupt the wait immediately. -+ * nanoseconds. Canceling the job will not interrupt the wait, so the -+ * cancel will not process until the coroutine wakes up. - */ - void block_job_sleep_ns(BlockJob *job, QEMUClockType type, int64_t ns); - --- -1.8.3.1 - diff --git a/SOURCES/kvm-blockjob-do-not-cancel-timer-in-resume.patch b/SOURCES/kvm-blockjob-do-not-cancel-timer-in-resume.patch new file mode 100644 index 0000000..cf8b15c --- /dev/null +++ b/SOURCES/kvm-blockjob-do-not-cancel-timer-in-resume.patch @@ -0,0 +1,165 @@ +From c18e6451e1f5d1c060497f545a624ffdc9733fca Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:47:46 +0200 +Subject: [PATCH 17/89] blockjob: do not cancel timer in resume + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-4-kwolf@redhat.com> +Patchwork-id: 81089 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 03/73] blockjob: do not cancel timer in resume +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +From: Stefan Hajnoczi + +Currently the timer is cancelled and the block job is entered by +block_job_resume(). This behavior causes drain to run extra blockjob +iterations when the job was sleeping due to the ratelimit. + +This patch leaves the job asleep when block_job_resume() is called. +Jobs can still be forcibly woken up using block_job_enter(), which is +used to cancel jobs. + +After this patch drain no longer runs extra blockjob iterations. This +is the expected behavior that qemu-iotests 185 used to rely on. We +temporarily changed the 185 test output to make it pass for the QEMU +2.12 release but now it's time to address this issue. + +Cc: QingFeng Hao +Signed-off-by: Stefan Hajnoczi +Reviewed-by: Eric Blake +Reviewed-by: QingFeng Hao +Message-id: 20180508135436.30140-3-stefanha@redhat.com +Reviewed-by: Jeff Cody +Signed-off-by: Jeff Cody +(cherry picked from commit 4c7e813ce964e230bb55cf4afc862ccb091ca3a3) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + blockjob.c | 22 +++++++++++++++------- + tests/qemu-iotests/185 | 5 +---- + tests/qemu-iotests/185.out | 12 +++++------- + 3 files changed, 21 insertions(+), 18 deletions(-) + +diff --git a/blockjob.c b/blockjob.c +index 27f957e..7064389 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -209,6 +209,18 @@ static void block_job_txn_del_job(BlockJob *job) + } + } + ++/* Assumes the block_job_mutex is held */ ++static bool block_job_timer_pending(BlockJob *job) ++{ ++ return timer_pending(&job->sleep_timer); ++} ++ ++/* Assumes the block_job_mutex is held */ ++static bool block_job_timer_not_pending(BlockJob *job) ++{ ++ return !block_job_timer_pending(job); ++} ++ + static void block_job_pause(BlockJob *job) + { + job->pause_count++; +@@ -221,7 +233,9 @@ static void block_job_resume(BlockJob *job) + if (job->pause_count) { + return; + } +- block_job_enter(job); ++ ++ /* kick only if no timer is pending */ ++ block_job_enter_cond(job, block_job_timer_not_pending); + } + + void block_job_ref(BlockJob *job) +@@ -651,12 +665,6 @@ static void block_job_completed_txn_success(BlockJob *job) + } + } + +-/* Assumes the block_job_mutex is held */ +-static bool block_job_timer_pending(BlockJob *job) +-{ +- return timer_pending(&job->sleep_timer); +-} +- + void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) + { + Error *local_err = NULL; +diff --git a/tests/qemu-iotests/185 b/tests/qemu-iotests/185 +index 975404c..9a2d317 100755 +--- a/tests/qemu-iotests/185 ++++ b/tests/qemu-iotests/185 +@@ -101,14 +101,11 @@ echo + # command to be received (after receiving the command, the rest runs + # synchronously, so jobs can arbitrarily continue or complete). + # +-# Jobs present while QEMU is terminating iterate once more due to +-# bdrv_drain_all(). +-# + # The buffer size for commit and streaming is 512k (waiting for 8 seconds after + # the first request), for active commit and mirror it's large enough to cover + # the full 4M, and for backup it's the qcow2 cluster size, which we know is + # 64k. As all of these are at least as large as the speed, we are sure that the +-# offset advances exactly twice before qemu exits. ++# offset advances exactly once before qemu exits. + + _send_qemu_cmd $h \ + "{ 'execute': 'block-commit', +diff --git a/tests/qemu-iotests/185.out b/tests/qemu-iotests/185.out +index 992162f..57eaf8d 100644 +--- a/tests/qemu-iotests/185.out ++++ b/tests/qemu-iotests/185.out +@@ -20,7 +20,7 @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.q + {"return": {}} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 67108864, "offset": 1048576, "speed": 65536, "type": "commit"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 67108864, "offset": 524288, "speed": 65536, "type": "commit"}} + + === Start active commit job and exit qemu === + +@@ -28,8 +28,7 @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.q + {"return": {}} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "disk", "len": 4194304, "offset": 4194304, "speed": 65536, "type": "commit"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "disk", "len": 4194304, "offset": 4194304, "speed": 65536, "type": "commit"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 4194304, "offset": 4194304, "speed": 65536, "type": "commit"}} + + === Start mirror job and exit qemu === + +@@ -38,8 +37,7 @@ Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 l + {"return": {}} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "disk", "len": 4194304, "offset": 4194304, "speed": 65536, "type": "mirror"}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "disk", "len": 4194304, "offset": 4194304, "speed": 65536, "type": "mirror"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 4194304, "offset": 4194304, "speed": 65536, "type": "mirror"}} + + === Start backup job and exit qemu === + +@@ -48,7 +46,7 @@ Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 l + {"return": {}} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 67108864, "offset": 131072, "speed": 65536, "type": "backup"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 67108864, "offset": 65536, "speed": 65536, "type": "backup"}} + + === Start streaming job and exit qemu === + +@@ -56,6 +54,6 @@ Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 l + {"return": {}} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 67108864, "offset": 1048576, "speed": 65536, "type": "stream"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 67108864, "offset": 524288, "speed": 65536, "type": "stream"}} + No errors were found on the image. + *** done +-- +1.8.3.1 + diff --git a/SOURCES/kvm-blockjob-drop-block_job_pause-resume_all.patch b/SOURCES/kvm-blockjob-drop-block_job_pause-resume_all.patch new file mode 100644 index 0000000..9065eb5 --- /dev/null +++ b/SOURCES/kvm-blockjob-drop-block_job_pause-resume_all.patch @@ -0,0 +1,109 @@ +From 4dc02d3f416a291b48e803600302e69cbb6f92ff Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:47:49 +0200 +Subject: [PATCH 20/89] blockjob: drop block_job_pause/resume_all() + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-7-kwolf@redhat.com> +Patchwork-id: 81068 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 06/73] blockjob: drop block_job_pause/resume_all() +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +From: Stefan Hajnoczi + +Commit 8119334918e86f45877cfc139192d54f2449a239 ("block: Don't +block_job_pause_all() in bdrv_drain_all()") removed the only callers of +block_job_pause/resume_all(). + +Pausing and resuming now happens in child_job_drained_begin/end() so +it's no longer necessary to globally pause/resume jobs. + +Signed-off-by: Stefan Hajnoczi +Reviewed-by: John Snow +Reviewed-by: Alberto Garcia +Message-id: 20180424085240.5798-1-stefanha@redhat.com +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 23d702d898bdd8e6772d83ea9789767ed589e17e) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + blockjob.c | 27 --------------------------- + include/block/blockjob_int.h | 14 -------------- + 2 files changed, 41 deletions(-) + +diff --git a/blockjob.c b/blockjob.c +index 7064389..b39d0f8 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -996,19 +996,6 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + return job; + } + +-void block_job_pause_all(void) +-{ +- BlockJob *job = NULL; +- while ((job = block_job_next(job))) { +- AioContext *aio_context = blk_get_aio_context(job->blk); +- +- aio_context_acquire(aio_context); +- block_job_ref(job); +- block_job_pause(job); +- aio_context_release(aio_context); +- } +-} +- + void block_job_early_fail(BlockJob *job) + { + assert(job->status == BLOCK_JOB_STATUS_CREATED); +@@ -1086,20 +1073,6 @@ void coroutine_fn block_job_pause_point(BlockJob *job) + } + } + +-void block_job_resume_all(void) +-{ +- BlockJob *job, *next; +- +- QLIST_FOREACH_SAFE(job, &block_jobs, job_list, next) { +- AioContext *aio_context = blk_get_aio_context(job->blk); +- +- aio_context_acquire(aio_context); +- block_job_resume(job); +- block_job_unref(job); +- aio_context_release(aio_context); +- } +-} +- + /* + * Conditionally enter a block_job pending a call to fn() while + * under the block_job_lock critical section. +diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h +index 642adce..d5a515d 100644 +--- a/include/block/blockjob_int.h ++++ b/include/block/blockjob_int.h +@@ -169,20 +169,6 @@ void block_job_sleep_ns(BlockJob *job, int64_t ns); + void block_job_yield(BlockJob *job); + + /** +- * block_job_pause_all: +- * +- * Asynchronously pause all jobs. +- */ +-void block_job_pause_all(void); +- +-/** +- * block_job_resume_all: +- * +- * Resume all block jobs. Must be paired with a preceding block_job_pause_all. +- */ +-void block_job_resume_all(void); +- +-/** + * block_job_early_fail: + * @bs: The block device. + * +-- +1.8.3.1 + diff --git a/SOURCES/kvm-blockjob-expose-error-string-via-query.patch b/SOURCES/kvm-blockjob-expose-error-string-via-query.patch new file mode 100644 index 0000000..23d006c --- /dev/null +++ b/SOURCES/kvm-blockjob-expose-error-string-via-query.patch @@ -0,0 +1,80 @@ +From 08fa409a1ec90e383103a12f3d06205ef5941062 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:47:50 +0200 +Subject: [PATCH 21/89] blockjob: expose error string via query + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-8-kwolf@redhat.com> +Patchwork-id: 81059 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 07/73] blockjob: expose error string via query +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +From: John Snow + +When we've reached the concluded state, we need to expose the error +state if applicable. Add the new field. + +This should be sufficient for determining if a job completed +successfully or not after concluding; if we want to discriminate +based on how it failed more mechanically, we can always add an +explicit return code enumeration later. + +I didn't bother to make it only show up if we are in the concluded +state; I don't think it's necessary. + +Cc: qemu-stable@nongnu.org +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Alberto Garcia +Signed-off-by: Kevin Wolf +(cherry picked from commit ab9ba614556ac5b0f8d96b99e0dba19f1e28d6c2) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + blockjob.c | 2 ++ + qapi/block-core.json | 6 +++++- + 2 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/blockjob.c b/blockjob.c +index b39d0f8..6746cad 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -839,6 +839,8 @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp) + info->status = job->status; + info->auto_finalize = job->auto_finalize; + info->auto_dismiss = job->auto_dismiss; ++ info->has_error = job->ret != 0; ++ info->error = job->ret ? g_strdup(strerror(-job->ret)) : NULL; + return info; + } + +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 5aac0c7..9012d00 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -1172,6 +1172,9 @@ + # @auto-dismiss: Job will dismiss itself when CONCLUDED, moving to the NULL + # state and disappearing from the query list. (since 2.12) + # ++# @error: Error information if the job did not complete successfully. ++# Not set if the job completed successfully. (since 2.12.1) ++# + # Since: 1.1 + ## + { 'struct': 'BlockJobInfo', +@@ -1179,7 +1182,8 @@ + 'offset': 'int', 'busy': 'bool', 'paused': 'bool', 'speed': 'int', + 'io-status': 'BlockDeviceIoStatus', 'ready': 'bool', + 'status': 'BlockJobStatus', +- 'auto-finalize': 'bool', 'auto-dismiss': 'bool' } } ++ 'auto-finalize': 'bool', 'auto-dismiss': 'bool', ++ '*error': 'str' } } + + ## + # @query-block-jobs: +-- +1.8.3.1 + diff --git a/SOURCES/kvm-blockjob-introduce-block_job_do_yield.patch b/SOURCES/kvm-blockjob-introduce-block_job_do_yield.patch deleted file mode 100644 index f9b7b1e..0000000 --- a/SOURCES/kvm-blockjob-introduce-block_job_do_yield.patch +++ /dev/null @@ -1,95 +0,0 @@ -From dace2b99ec7489bdabb4beeb429ec44427805d90 Mon Sep 17 00:00:00 2001 -From: Jeffrey Cody -Date: Thu, 30 Nov 2017 22:49:14 +0100 -Subject: [PATCH 10/21] blockjob: introduce block_job_do_yield - -RH-Author: Jeffrey Cody -Message-id: <331a28f9c09b1ce40dd95f7b21ded200ab46713d.1511985875.git.jcody@redhat.com> -Patchwork-id: 78046 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 10/11] blockjob: introduce block_job_do_yield -Bugzilla: 1506531 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: John Snow - -From: Paolo Bonzini - -Hide the clearing of job->busy in a single function, and set it -in block_job_enter. This lets block_job_do_yield verify that -qemu_coroutine_enter is not used while job->busy = false. - -Signed-off-by: Paolo Bonzini -Tested-By: Jeff Cody -Reviewed-by: Fam Zheng -Reviewed-by: Jeff Cody -Reviewed-by: Stefan Hajnoczi -Signed-off-by: Kevin Wolf -(cherry picked from commit 356f59b8757f47c0aca3e2e4e51d6010f64cade1) -Signed-off-by: Jeff Cody -Signed-off-by: Miroslav Rezanina ---- - blockjob.c | 24 ++++++++++++++++-------- - 1 file changed, 16 insertions(+), 8 deletions(-) - -diff --git a/blockjob.c b/blockjob.c -index 4d78046..e960b3e 100644 ---- a/blockjob.c -+++ b/blockjob.c -@@ -729,6 +729,15 @@ static bool block_job_should_pause(BlockJob *job) - return job->pause_count > 0; - } - -+static void block_job_do_yield(BlockJob *job) -+{ -+ job->busy = false; -+ qemu_coroutine_yield(); -+ -+ /* Set by block_job_enter before re-entering the coroutine. */ -+ assert(job->busy); -+} -+ - void coroutine_fn block_job_pause_point(BlockJob *job) - { - assert(job && block_job_started(job)); -@@ -746,9 +755,7 @@ void coroutine_fn block_job_pause_point(BlockJob *job) - - if (block_job_should_pause(job) && !block_job_is_cancelled(job)) { - job->paused = true; -- job->busy = false; -- qemu_coroutine_yield(); /* wait for block_job_resume() */ -- job->busy = true; -+ block_job_do_yield(job); - job->paused = false; - } - -@@ -778,9 +785,12 @@ void block_job_enter(BlockJob *job) - return; - } - -- if (!job->busy) { -- bdrv_coroutine_enter(blk_bs(job->blk), job->co); -+ if (job->busy) { -+ return; - } -+ -+ job->busy = true; -+ aio_co_wake(job->co); - } - - bool block_job_is_cancelled(BlockJob *job) -@@ -819,11 +829,9 @@ void block_job_yield(BlockJob *job) - return; - } - -- job->busy = false; - if (!block_job_should_pause(job)) { -- qemu_coroutine_yield(); -+ block_job_do_yield(job); - } -- job->busy = true; - - block_job_pause_point(job); - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-blockjob-reimplement-block_job_sleep_ns-to-allow-can.patch b/SOURCES/kvm-blockjob-reimplement-block_job_sleep_ns-to-allow-can.patch deleted file mode 100644 index acddfff..0000000 --- a/SOURCES/kvm-blockjob-reimplement-block_job_sleep_ns-to-allow-can.patch +++ /dev/null @@ -1,230 +0,0 @@ -From b3526a8557aac40fa4f4520518a1193cc92598e6 Mon Sep 17 00:00:00 2001 -From: Jeffrey Cody -Date: Thu, 30 Nov 2017 22:49:15 +0100 -Subject: [PATCH 11/21] blockjob: reimplement block_job_sleep_ns to allow - cancellation - -RH-Author: Jeffrey Cody -Message-id: <51b0c9ece9db7a164c4e7ccc90a7d51f786ceaa2.1511985875.git.jcody@redhat.com> -Patchwork-id: 78049 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 11/11] blockjob: reimplement block_job_sleep_ns to allow cancellation -Bugzilla: 1506531 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: John Snow - -From: Paolo Bonzini - -This reverts the effects of commit 4afeffc857 ("blockjob: do not allow -coroutine double entry or entry-after-completion", 2017-11-21) - -This fixed the symptom of a bug rather than the root cause. Canceling the -wait on a sleeping blockjob coroutine is generally fine, we just need to -make it work correctly across AioContexts. To do so, use a QEMUTimer -that calls block_job_enter. Use a mutex to ensure that block_job_enter -synchronizes correctly with block_job_sleep_ns. - -Signed-off-by: Paolo Bonzini -Tested-By: Jeff Cody -Reviewed-by: Fam Zheng -Reviewed-by: Stefan Hajnoczi -Reviewed-by: Jeff Cody -Signed-off-by: Kevin Wolf -(cherry picked from commit fc24908e7d232b79c2a6f0363f52bda18dedb57b) -Signed-off-by: Jeff Cody -Signed-off-by: Miroslav Rezanina ---- - blockjob.c | 63 ++++++++++++++++++++++++++++++++++++-------- - include/block/blockjob.h | 8 +++++- - include/block/blockjob_int.h | 4 +-- - 3 files changed, 61 insertions(+), 14 deletions(-) - -diff --git a/blockjob.c b/blockjob.c -index e960b3e..84f526a 100644 ---- a/blockjob.c -+++ b/blockjob.c -@@ -37,6 +37,26 @@ - #include "qemu/timer.h" - #include "qapi-event.h" - -+/* Right now, this mutex is only needed to synchronize accesses to job->busy -+ * and job->sleep_timer, such as concurrent calls to block_job_do_yield and -+ * block_job_enter. */ -+static QemuMutex block_job_mutex; -+ -+static void block_job_lock(void) -+{ -+ qemu_mutex_lock(&block_job_mutex); -+} -+ -+static void block_job_unlock(void) -+{ -+ qemu_mutex_unlock(&block_job_mutex); -+} -+ -+static void __attribute__((__constructor__)) block_job_init(void) -+{ -+ qemu_mutex_init(&block_job_mutex); -+} -+ - static void block_job_event_cancelled(BlockJob *job); - static void block_job_event_completed(BlockJob *job, const char *msg); - -@@ -161,6 +181,7 @@ void block_job_unref(BlockJob *job) - blk_unref(job->blk); - error_free(job->blocker); - g_free(job->id); -+ assert(!timer_pending(&job->sleep_timer)); - g_free(job); - } - } -@@ -287,6 +308,13 @@ static void coroutine_fn block_job_co_entry(void *opaque) - job->driver->start(job); - } - -+static void block_job_sleep_timer_cb(void *opaque) -+{ -+ BlockJob *job = opaque; -+ -+ block_job_enter(job); -+} -+ - void block_job_start(BlockJob *job) - { - assert(job && !block_job_started(job) && job->paused && -@@ -556,7 +584,7 @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp) - info->type = g_strdup(BlockJobType_lookup[job->driver->job_type]); - info->device = g_strdup(job->id); - info->len = job->len; -- info->busy = job->busy; -+ info->busy = atomic_read(&job->busy); - info->paused = job->pause_count > 0; - info->offset = job->offset; - info->speed = job->speed; -@@ -664,6 +692,9 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, - job->paused = true; - job->pause_count = 1; - job->refcnt = 1; -+ aio_timer_init(qemu_get_aio_context(), &job->sleep_timer, -+ QEMU_CLOCK_REALTIME, SCALE_NS, -+ block_job_sleep_timer_cb, job); - - error_setg(&job->blocker, "block device is in use by block job: %s", - BlockJobType_lookup[driver->job_type]); -@@ -729,9 +760,20 @@ static bool block_job_should_pause(BlockJob *job) - return job->pause_count > 0; - } - --static void block_job_do_yield(BlockJob *job) -+/* Yield, and schedule a timer to reenter the coroutine after @ns nanoseconds. -+ * Reentering the job coroutine with block_job_enter() before the timer has -+ * expired is allowed and cancels the timer. -+ * -+ * If @ns is (uint64_t) -1, no timer is scheduled and block_job_enter() must be -+ * called explicitly. */ -+static void block_job_do_yield(BlockJob *job, uint64_t ns) - { -+ block_job_lock(); -+ if (ns != -1) { -+ timer_mod(&job->sleep_timer, ns); -+ } - job->busy = false; -+ block_job_unlock(); - qemu_coroutine_yield(); - - /* Set by block_job_enter before re-entering the coroutine. */ -@@ -755,7 +797,7 @@ void coroutine_fn block_job_pause_point(BlockJob *job) - - if (block_job_should_pause(job) && !block_job_is_cancelled(job)) { - job->paused = true; -- block_job_do_yield(job); -+ block_job_do_yield(job, -1); - job->paused = false; - } - -@@ -785,11 +827,16 @@ void block_job_enter(BlockJob *job) - return; - } - -+ block_job_lock(); - if (job->busy) { -+ block_job_unlock(); - return; - } - -+ assert(!job->deferred_to_main_loop); -+ timer_del(&job->sleep_timer); - job->busy = true; -+ block_job_unlock(); - aio_co_wake(job->co); - } - -@@ -807,14 +854,8 @@ void block_job_sleep_ns(BlockJob *job, int64_t ns) - return; - } - -- /* We need to leave job->busy set here, because when we have -- * put a coroutine to 'sleep', we have scheduled it to run in -- * the future. We cannot enter that same coroutine again before -- * it wakes and runs, otherwise we risk double-entry or entry after -- * completion. */ - if (!block_job_should_pause(job)) { -- co_aio_sleep_ns(blk_get_aio_context(job->blk), -- QEMU_CLOCK_REALTIME, ns); -+ block_job_do_yield(job, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + ns); - } - - block_job_pause_point(job); -@@ -830,7 +871,7 @@ void block_job_yield(BlockJob *job) - } - - if (!block_job_should_pause(job)) { -- block_job_do_yield(job); -+ block_job_do_yield(job, -1); - } - - block_job_pause_point(job); -diff --git a/include/block/blockjob.h b/include/block/blockjob.h -index 67c0968..00403d9 100644 ---- a/include/block/blockjob.h -+++ b/include/block/blockjob.h -@@ -77,7 +77,7 @@ typedef struct BlockJob { - /** - * Set to false by the job while the coroutine has yielded and may be - * re-entered by block_job_enter(). There may still be I/O or event loop -- * activity pending. -+ * activity pending. Accessed under block_job_mutex (in blockjob.c). - */ - bool busy; - -@@ -135,6 +135,12 @@ typedef struct BlockJob { - */ - int ret; - -+ /** -+ * Timer that is used by @block_job_sleep_ns. Accessed under -+ * block_job_mutex (in blockjob.c). -+ */ -+ QEMUTimer sleep_timer; -+ - /** Non-NULL if this job is part of a transaction */ - BlockJobTxn *txn; - QLIST_ENTRY(BlockJob) txn_list; -diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h -index f7ab183..c9b23b0 100644 ---- a/include/block/blockjob_int.h -+++ b/include/block/blockjob_int.h -@@ -142,8 +142,8 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, - * @ns: How many nanoseconds to stop for. - * - * Put the job to sleep (assuming that it wasn't canceled) for @ns -- * %QEMU_CLOCK_REALTIME nanoseconds. Canceling the job will not interrupt -- * the wait, so the cancel will not process until the coroutine wakes up. -+ * %QEMU_CLOCK_REALTIME nanoseconds. Canceling the job will immediately -+ * interrupt the wait. - */ - void block_job_sleep_ns(BlockJob *job, int64_t ns); - --- -1.8.3.1 - diff --git a/SOURCES/kvm-blockjob-remove-clock-argument-from-block_job_sleep_.patch b/SOURCES/kvm-blockjob-remove-clock-argument-from-block_job_sleep_.patch deleted file mode 100644 index 3685bfc..0000000 --- a/SOURCES/kvm-blockjob-remove-clock-argument-from-block_job_sleep_.patch +++ /dev/null @@ -1,172 +0,0 @@ -From e514856415406ee30a9199843895057faa7e7152 Mon Sep 17 00:00:00 2001 -From: Jeffrey Cody -Date: Thu, 30 Nov 2017 22:49:13 +0100 -Subject: [PATCH 09/21] blockjob: remove clock argument from block_job_sleep_ns - -RH-Author: Jeffrey Cody -Message-id: <2f57c3ce7143bdde2d8c485e3b1eda19898547dd.1511985875.git.jcody@redhat.com> -Patchwork-id: 78048 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 09/11] blockjob: remove clock argument from block_job_sleep_ns -Bugzilla: 1506531 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: John Snow - -From: Paolo Bonzini - -All callers are using QEMU_CLOCK_REALTIME, and it will not be possible to -support more than one clock when block_job_sleep_ns switches to a single -timer stored in the BlockJob struct. - -Signed-off-by: Paolo Bonzini -Reviewed-by: Alberto Garcia -Tested-By: Jeff Cody -Reviewed-by: Fam Zheng -Reviewed-by: Jeff Cody -Reviewed-by: Stefan Hajnoczi -Signed-off-by: Kevin Wolf -(cherry picked from commit 5bf1d5a73a4a6d0e2d692bd02b6d7f3eedeed3b7) -Signed-off-by: Jeff Cody -Signed-off-by: Miroslav Rezanina ---- - block/backup.c | 4 ++-- - block/commit.c | 2 +- - block/mirror.c | 6 +++--- - block/stream.c | 2 +- - blockjob.c | 5 +++-- - include/block/blockjob_int.h | 7 +++---- - tests/test-blockjob-txn.c | 2 +- - 7 files changed, 14 insertions(+), 14 deletions(-) - -diff --git a/block/backup.c b/block/backup.c -index 504a089..ac6dc89 100644 ---- a/block/backup.c -+++ b/block/backup.c -@@ -346,9 +346,9 @@ static bool coroutine_fn yield_and_check(BackupBlockJob *job) - uint64_t delay_ns = ratelimit_calculate_delay(&job->limit, - job->bytes_read); - job->bytes_read = 0; -- block_job_sleep_ns(&job->common, QEMU_CLOCK_REALTIME, delay_ns); -+ block_job_sleep_ns(&job->common, delay_ns); - } else { -- block_job_sleep_ns(&job->common, QEMU_CLOCK_REALTIME, 0); -+ block_job_sleep_ns(&job->common, 0); - } - - if (block_job_is_cancelled(&job->common)) { -diff --git a/block/commit.c b/block/commit.c -index 834084b..9dbad9c 100644 ---- a/block/commit.c -+++ b/block/commit.c -@@ -179,7 +179,7 @@ static void coroutine_fn commit_run(void *opaque) - /* Note that even when no rate limit is applied we need to yield - * with no pending I/O here so that bdrv_drain_all() returns. - */ -- block_job_sleep_ns(&s->common, QEMU_CLOCK_REALTIME, delay_ns); -+ block_job_sleep_ns(&s->common, delay_ns); - if (block_job_is_cancelled(&s->common)) { - break; - } -diff --git a/block/mirror.c b/block/mirror.c -index 17278db..b88014e 100644 ---- a/block/mirror.c -+++ b/block/mirror.c -@@ -608,7 +608,7 @@ static void mirror_throttle(MirrorBlockJob *s) - - if (now - s->last_pause_ns > SLICE_TIME) { - s->last_pause_ns = now; -- block_job_sleep_ns(&s->common, QEMU_CLOCK_REALTIME, 0); -+ block_job_sleep_ns(&s->common, 0); - } else { - block_job_pause_point(&s->common); - } -@@ -891,13 +891,13 @@ static void coroutine_fn mirror_run(void *opaque) - trace_mirror_before_sleep(s, cnt * BDRV_SECTOR_SIZE, - s->synced, delay_ns); - if (!s->synced) { -- block_job_sleep_ns(&s->common, QEMU_CLOCK_REALTIME, delay_ns); -+ block_job_sleep_ns(&s->common, delay_ns); - if (block_job_is_cancelled(&s->common)) { - break; - } - } else if (!should_complete) { - delay_ns = (s->in_flight == 0 && cnt == 0 ? SLICE_TIME : 0); -- block_job_sleep_ns(&s->common, QEMU_CLOCK_REALTIME, delay_ns); -+ block_job_sleep_ns(&s->common, delay_ns); - } - s->last_pause_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); - } -diff --git a/block/stream.c b/block/stream.c -index e6f7234..499cdac 100644 ---- a/block/stream.c -+++ b/block/stream.c -@@ -141,7 +141,7 @@ static void coroutine_fn stream_run(void *opaque) - /* Note that even when no rate limit is applied we need to yield - * with no pending I/O here so that bdrv_drain_all() returns. - */ -- block_job_sleep_ns(&s->common, QEMU_CLOCK_REALTIME, delay_ns); -+ block_job_sleep_ns(&s->common, delay_ns); - if (block_job_is_cancelled(&s->common)) { - break; - } -diff --git a/blockjob.c b/blockjob.c -index 2509bba..4d78046 100644 ---- a/blockjob.c -+++ b/blockjob.c -@@ -788,7 +788,7 @@ bool block_job_is_cancelled(BlockJob *job) - return job->cancelled; - } - --void block_job_sleep_ns(BlockJob *job, QEMUClockType type, int64_t ns) -+void block_job_sleep_ns(BlockJob *job, int64_t ns) - { - assert(job->busy); - -@@ -803,7 +803,8 @@ void block_job_sleep_ns(BlockJob *job, QEMUClockType type, int64_t ns) - * it wakes and runs, otherwise we risk double-entry or entry after - * completion. */ - if (!block_job_should_pause(job)) { -- co_aio_sleep_ns(blk_get_aio_context(job->blk), type, ns); -+ co_aio_sleep_ns(blk_get_aio_context(job->blk), -+ QEMU_CLOCK_REALTIME, ns); - } - - block_job_pause_point(job); -diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h -index 43f3be2..f7ab183 100644 ---- a/include/block/blockjob_int.h -+++ b/include/block/blockjob_int.h -@@ -139,14 +139,13 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, - /** - * block_job_sleep_ns: - * @job: The job that calls the function. -- * @clock: The clock to sleep on. - * @ns: How many nanoseconds to stop for. - * - * Put the job to sleep (assuming that it wasn't canceled) for @ns -- * nanoseconds. Canceling the job will not interrupt the wait, so the -- * cancel will not process until the coroutine wakes up. -+ * %QEMU_CLOCK_REALTIME nanoseconds. Canceling the job will not interrupt -+ * the wait, so the cancel will not process until the coroutine wakes up. - */ --void block_job_sleep_ns(BlockJob *job, QEMUClockType type, int64_t ns); -+void block_job_sleep_ns(BlockJob *job, int64_t ns); - - /** - * block_job_yield: -diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c -index c77343f..3591c96 100644 ---- a/tests/test-blockjob-txn.c -+++ b/tests/test-blockjob-txn.c -@@ -44,7 +44,7 @@ static void coroutine_fn test_block_job_run(void *opaque) - - while (s->iterations--) { - if (s->use_timer) { -- block_job_sleep_ns(job, QEMU_CLOCK_REALTIME, 0); -+ block_job_sleep_ns(job, 0); - } else { - block_job_yield(job); - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-build-sys-restrict-vmcoreinfo-to-fw_cfg-dma-capable-.patch b/SOURCES/kvm-build-sys-restrict-vmcoreinfo-to-fw_cfg-dma-capable-.patch deleted file mode 100644 index f1b0df3..0000000 --- a/SOURCES/kvm-build-sys-restrict-vmcoreinfo-to-fw_cfg-dma-capable-.patch +++ /dev/null @@ -1,84 +0,0 @@ -From bc725b358214c32163d60898e26b24b3ba84a3ca Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Mon, 27 Nov 2017 22:51:11 +0100 -Subject: [PATCH 13/21] build-sys: restrict vmcoreinfo to fw_cfg+dma capable - targets -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Marc-André Lureau -Message-id: <20171127225111.24518-10-marcandre.lureau@redhat.com> -Patchwork-id: 77926 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 9/9] build-sys: restrict vmcoreinfo to fw_cfg+dma capable targets -Bugzilla: 1398633 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Andrew Jones -RH-Acked-by: Miroslav Rezanina - -vmcoreinfo is built for all targets. However, it requires fw_cfg with -DMA operations support (write operation). Restrict vmcoreinfo exposure -to architectures that are supporting FW_CFG_DMA, that is arm-virt and -x86 only atm. - -Signed-off-by: Marc-André Lureau -Reviewed-by: Thomas Huth -Reviewed-by: Daniel Henrique Barboza -Tested-by: Daniel Henrique Barboza -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin - -(cherry picked from commit f865da7c369fa00b2ccaf6bce158ad2701b2a27c) -Signed-off-by: Marc-André Lureau -Signed-off-by: Miroslav Rezanina ---- - default-configs/arm-softmmu.mak | 2 ++ - default-configs/i386-softmmu.mak | 1 + - default-configs/x86_64-softmmu.mak | 1 + - hw/misc/Makefile.objs | 2 +- - 4 files changed, 5 insertions(+), 1 deletion(-) - -diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak -index 05aaf8f..bbdcc81 100644 ---- a/default-configs/arm-softmmu.mak -+++ b/default-configs/arm-softmmu.mak -@@ -128,3 +128,5 @@ CONFIG_ACPI=y - CONFIG_SMBIOS=y - CONFIG_ASPEED_SOC=y - CONFIG_GPIO_KEY=y -+ -+CONFIG_FW_CFG_DMA=y -diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak -index d2ab2f6..f7c0b33 100644 ---- a/default-configs/i386-softmmu.mak -+++ b/default-configs/i386-softmmu.mak -@@ -59,3 +59,4 @@ CONFIG_SMBIOS=y - CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM) - CONFIG_PXB=y - CONFIG_ACPI_VMGENID=y -+CONFIG_FW_CFG_DMA=y -diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak -index d6d10aa..611fa6f 100644 ---- a/default-configs/x86_64-softmmu.mak -+++ b/default-configs/x86_64-softmmu.mak -@@ -61,3 +61,4 @@ CONFIG_SMBIOS=y - #CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM) - CONFIG_PXB=y - CONFIG_ACPI_VMGENID=y -+CONFIG_FW_CFG_DMA=y -diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs -index b4cbebf..255a35a 100644 ---- a/hw/misc/Makefile.objs -+++ b/hw/misc/Makefile.objs -@@ -9,7 +9,7 @@ common-obj-$(CONFIG_PCI_TESTDEV) += pci-testdev.o - common-obj-$(CONFIG_EDU) += edu.o - - #common-obj-y += unimp.o --common-obj-y += vmcoreinfo.o -+common-obj-$(CONFIG_FW_CFG_DMA) += vmcoreinfo.o - - obj-$(CONFIG_VMPORT) += vmport.o - --- -1.8.3.1 - diff --git a/SOURCES/kvm-ccid-card-passthru-fix-regression-in-realize.patch b/SOURCES/kvm-ccid-card-passthru-fix-regression-in-realize.patch new file mode 100644 index 0000000..73e4a39 --- /dev/null +++ b/SOURCES/kvm-ccid-card-passthru-fix-regression-in-realize.patch @@ -0,0 +1,51 @@ +From a0251ae2c973f3a5a103e7601fabed65cc24c1b0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Mon, 11 Jun 2018 17:13:26 +0200 +Subject: [PATCH 2/9] ccid-card-passthru: fix regression in realize() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20180611171326.5043-1-marcandre.lureau@redhat.com> +Patchwork-id: 80632 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH] ccid-card-passthru: fix regression in realize() +Bugzilla: 1584984 +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Markus Armbruster +RH-Acked-by: Thomas Huth + +Since cc847bfd16d894fd8c1a2ce25f31772f6cdbbc74, CCID card-passthru +fails to intialize, because it changed a debug line to an error, +probably by mistake. Change it back to a DPRINTF debug. + +(solves Boxes creating VM with smartcard passthru failing to start) + +Signed-off-by: Marc-André Lureau +Reviewed-by: Philippe Mathieu-Daudé +Message-id: 20180515153039.27514-1-marcandre.lureau@redhat.com +Signed-off-by: Gerd Hoffmann + +(cherry picked from commit e58d64a16abc2304c4dcb644411eb9580bf63b1e) +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + hw/usb/ccid-card-passthru.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c +index b7dd360..668a22d 100644 +--- a/hw/usb/ccid-card-passthru.c ++++ b/hw/usb/ccid-card-passthru.c +@@ -345,7 +345,7 @@ static void passthru_realize(CCIDCardState *base, Error **errp) + card->vscard_in_pos = 0; + card->vscard_in_hdr = 0; + if (qemu_chr_fe_backend_connected(&card->cs)) { +- error_setg(errp, "ccid-card-passthru: initing chardev"); ++ DPRINTF(card, D_INFO, "ccid-card-passthru: initing chardev"); + qemu_chr_fe_set_handlers(&card->cs, + ccid_card_vscard_can_read, + ccid_card_vscard_read, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-check-block-qdict-Cover-flattening-of-empty-lists-an.patch b/SOURCES/kvm-check-block-qdict-Cover-flattening-of-empty-lists-an.patch new file mode 100644 index 0000000..0190a2b --- /dev/null +++ b/SOURCES/kvm-check-block-qdict-Cover-flattening-of-empty-lists-an.patch @@ -0,0 +1,76 @@ +From b90ea90ed89d27cadc704b664e6ca26ea32fa95d Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Mon, 18 Jun 2018 08:43:27 +0200 +Subject: [PATCH 20/54] check-block-qdict: Cover flattening of empty lists and + dictionaries + +RH-Author: Markus Armbruster +Message-id: <20180618084330.30009-21-armbru@redhat.com> +Patchwork-id: 80734 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 20/23] check-block-qdict: Cover flattening of empty lists and dictionaries +Bugzilla: 1557995 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Signed-off-by: Markus Armbruster +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit bef96b1549907b005ce1fa1456d2a0910d2a1aa5) +Signed-off-by: Miroslav Rezanina +--- + tests/check-block-qdict.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/tests/check-block-qdict.c b/tests/check-block-qdict.c +index 29f58a2..2da16f0 100644 +--- a/tests/check-block-qdict.c ++++ b/tests/check-block-qdict.c +@@ -41,6 +41,8 @@ static void qdict_flatten_test(void) + QList *e = qlist_new(); + QDict *e_1_2 = qdict_new(); + QDict *f = qdict_new(); ++ QList *y = qlist_new(); ++ QDict *z = qdict_new(); + QDict *root = qdict_new(); + + /* +@@ -62,7 +64,9 @@ static void qdict_flatten_test(void) + * "c": 2, + * "d": 3, + * }, +- * "g": 4 ++ * "g": 4, ++ * "y": [{}], ++ * "z": {"a": []} + * } + * + * to +@@ -77,6 +81,8 @@ static void qdict_flatten_test(void) + * "f.d": 3, + * "g": 4 + * } ++ * ++ * Note that "y" and "z" get eaten. + */ + + qdict_put_int(e_1_2, "a", 0); +@@ -91,9 +97,15 @@ static void qdict_flatten_test(void) + qdict_put_int(f, "c", 2); + qdict_put_int(f, "d", 3); + ++ qlist_append(y, qdict_new()); ++ ++ qdict_put(z, "a", qlist_new()); ++ + qdict_put(root, "e", e); + qdict_put(root, "f", f); + qdict_put_int(root, "g", 4); ++ qdict_put(root, "y", y); ++ qdict_put(root, "z", z); + + qdict_flatten(root); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-check-block-qdict-Rename-qdict_flatten-s-variables-f.patch b/SOURCES/kvm-check-block-qdict-Rename-qdict_flatten-s-variables-f.patch new file mode 100644 index 0000000..aa90a2e --- /dev/null +++ b/SOURCES/kvm-check-block-qdict-Rename-qdict_flatten-s-variables-f.patch @@ -0,0 +1,108 @@ +From 34251ed7b01f81a0e62fa56548db657a5c238125 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Mon, 18 Jun 2018 08:43:26 +0200 +Subject: [PATCH 19/54] check-block-qdict: Rename qdict_flatten()'s variables + for clarity + +RH-Author: Markus Armbruster +Message-id: <20180618084330.30009-20-armbru@redhat.com> +Patchwork-id: 80721 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 19/23] check-block-qdict: Rename qdict_flatten()'s variables for clarity +Bugzilla: 1557995 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Signed-off-by: Markus Armbruster +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit cddec036830ada5d5d45023bcfba09015b8ab394) +Signed-off-by: Miroslav Rezanina +--- + tests/check-block-qdict.c | 57 ++++++++++++++++++++++++----------------------- + 1 file changed, 29 insertions(+), 28 deletions(-) + +diff --git a/tests/check-block-qdict.c b/tests/check-block-qdict.c +index 5b9f4d5..29f58a2 100644 +--- a/tests/check-block-qdict.c ++++ b/tests/check-block-qdict.c +@@ -37,11 +37,11 @@ static void qdict_defaults_test(void) + + static void qdict_flatten_test(void) + { +- QList *list1 = qlist_new(); +- QList *list2 = qlist_new(); +- QDict *dict1 = qdict_new(); +- QDict *dict2 = qdict_new(); +- QDict *dict3 = qdict_new(); ++ QList *e_1 = qlist_new(); ++ QList *e = qlist_new(); ++ QDict *e_1_2 = qdict_new(); ++ QDict *f = qdict_new(); ++ QDict *root = qdict_new(); + + /* + * Test the flattening of +@@ -79,35 +79,36 @@ static void qdict_flatten_test(void) + * } + */ + +- qdict_put_int(dict1, "a", 0); +- qdict_put_int(dict1, "b", 1); ++ qdict_put_int(e_1_2, "a", 0); ++ qdict_put_int(e_1_2, "b", 1); + +- qlist_append_int(list1, 23); +- qlist_append_int(list1, 66); +- qlist_append(list1, dict1); +- qlist_append_int(list2, 42); +- qlist_append(list2, list1); ++ qlist_append_int(e_1, 23); ++ qlist_append_int(e_1, 66); ++ qlist_append(e_1, e_1_2); ++ qlist_append_int(e, 42); ++ qlist_append(e, e_1); + +- qdict_put_int(dict2, "c", 2); +- qdict_put_int(dict2, "d", 3); +- qdict_put(dict3, "e", list2); +- qdict_put(dict3, "f", dict2); +- qdict_put_int(dict3, "g", 4); ++ qdict_put_int(f, "c", 2); ++ qdict_put_int(f, "d", 3); + +- qdict_flatten(dict3); ++ qdict_put(root, "e", e); ++ qdict_put(root, "f", f); ++ qdict_put_int(root, "g", 4); + +- g_assert(qdict_get_int(dict3, "e.0") == 42); +- g_assert(qdict_get_int(dict3, "e.1.0") == 23); +- g_assert(qdict_get_int(dict3, "e.1.1") == 66); +- g_assert(qdict_get_int(dict3, "e.1.2.a") == 0); +- g_assert(qdict_get_int(dict3, "e.1.2.b") == 1); +- g_assert(qdict_get_int(dict3, "f.c") == 2); +- g_assert(qdict_get_int(dict3, "f.d") == 3); +- g_assert(qdict_get_int(dict3, "g") == 4); ++ qdict_flatten(root); + +- g_assert(qdict_size(dict3) == 8); ++ g_assert(qdict_get_int(root, "e.0") == 42); ++ g_assert(qdict_get_int(root, "e.1.0") == 23); ++ g_assert(qdict_get_int(root, "e.1.1") == 66); ++ g_assert(qdict_get_int(root, "e.1.2.a") == 0); ++ g_assert(qdict_get_int(root, "e.1.2.b") == 1); ++ g_assert(qdict_get_int(root, "f.c") == 2); ++ g_assert(qdict_get_int(root, "f.d") == 3); ++ g_assert(qdict_get_int(root, "g") == 4); + +- qobject_unref(dict3); ++ g_assert(qdict_size(root) == 8); ++ ++ qobject_unref(root); + } + + static void qdict_array_split_test(void) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-cirrus-fix-oob-access-in-mode4and5-write-functions.patch b/SOURCES/kvm-cirrus-fix-oob-access-in-mode4and5-write-functions.patch deleted file mode 100644 index 96add77..0000000 --- a/SOURCES/kvm-cirrus-fix-oob-access-in-mode4and5-write-functions.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 63d5677cbe031c52b37af8d123c27fdcb0f73af3 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Fri, 20 Oct 2017 07:19:25 +0200 -Subject: [PATCH 03/19] cirrus: fix oob access in mode4and5 write functions - -RH-Author: Gerd Hoffmann -Message-id: <20171020071925.9483-5-kraxel@redhat.com> -Patchwork-id: 77392 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 4/4] cirrus: fix oob access in mode4and5 write functions -Bugzilla: 1501301 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Laurent Vivier - -Move dst calculation into the loop, so we apply the mask on each -interation and will not overflow vga memory. - -Cc: Prasad J Pandit -Reported-by: Niu Guoxiang -Signed-off-by: Gerd Hoffmann -Message-id: 20171011084314.21752-1-kraxel@redhat.com -(cherry picked from commit eb38e1bc3740725ca29a535351de94107ec58d51) -Signed-off-by: Miroslav Rezanina ---- - hw/display/cirrus_vga.c | 6 ++---- - 1 file changed, 2 insertions(+), 4 deletions(-) - -diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c -index 15322b5..e53c6f2 100644 ---- a/hw/display/cirrus_vga.c -+++ b/hw/display/cirrus_vga.c -@@ -2038,15 +2038,14 @@ static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s, - unsigned val = mem_value; - uint8_t *dst; - -- dst = s->vga.vram_ptr + (offset &= s->cirrus_addr_mask); - for (x = 0; x < 8; x++) { -+ dst = s->vga.vram_ptr + ((offset + x) & s->cirrus_addr_mask); - if (val & 0x80) { - *dst = s->cirrus_shadow_gr1; - } else if (mode == 5) { - *dst = s->cirrus_shadow_gr0; - } - val <<= 1; -- dst++; - } - memory_region_set_dirty(&s->vga.vram, offset, 8); - } -@@ -2060,8 +2059,8 @@ static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s, - unsigned val = mem_value; - uint8_t *dst; - -- dst = s->vga.vram_ptr + (offset &= s->cirrus_addr_mask); - for (x = 0; x < 8; x++) { -+ dst = s->vga.vram_ptr + ((offset + 2 * x) & s->cirrus_addr_mask & ~1); - if (val & 0x80) { - *dst = s->cirrus_shadow_gr1; - *(dst + 1) = s->vga.gr[0x11]; -@@ -2070,7 +2069,6 @@ static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s, - *(dst + 1) = s->vga.gr[0x10]; - } - val <<= 1; -- dst += 2; - } - memory_region_set_dirty(&s->vga.vram, offset, 16); - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-commit-Add-top-node-base-node-options.patch b/SOURCES/kvm-commit-Add-top-node-base-node-options.patch new file mode 100644 index 0000000..347b256 --- /dev/null +++ b/SOURCES/kvm-commit-Add-top-node-base-node-options.patch @@ -0,0 +1,138 @@ +From 1ac2f161e5585d1ed71b79e8279c9d78b2efe35e Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Mon, 17 Sep 2018 07:48:43 +0200 +Subject: [PATCH 01/49] commit: Add top-node/base-node options + +RH-Author: Kevin Wolf +Message-id: <20180911130704.6641-2-kwolf@redhat.com> +Patchwork-id: 82114 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 1/2] commit: Add top-node/base-node options +Bugzilla: 1624012 +RH-Acked-by: Max Reitz +RH-Acked-by: John Snow +RH-Acked-by: Fam Zheng + +The block-commit QMP command required specifying the top and base nodes +of the commit jobs using the file name of that node. While this works +in simple cases (local files with absolute paths), the file names +generated for more complicated setups can be hard to predict. + +The block-commit command has more problems than just this, so we want to +replace it altogether in the long run, but libvirt needs a reliable way +to address nodes now. So we don't want to wait for a new, cleaner +command, but just add the minimal thing needed right now. + +This adds two new options top-node and base-node to the command, which +allow specifying node names instead. They are mutually exclusive with +the old options. + +Signed-off-by: Kevin Wolf +--- + blockdev.c | 32 ++++++++++++++++++++++++++++++-- + qapi/block-core.json | 24 ++++++++++++++++++------ + 2 files changed, 48 insertions(+), 8 deletions(-) + +diff --git a/blockdev.c b/blockdev.c +index 0eb6bba..fb355c8 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -3371,7 +3371,9 @@ out: + } + + void qmp_block_commit(bool has_job_id, const char *job_id, const char *device, ++ bool has_base_node, const char *base_node, + bool has_base, const char *base, ++ bool has_top_node, const char *top_node, + bool has_top, const char *top, + bool has_backing_file, const char *backing_file, + bool has_speed, int64_t speed, +@@ -3432,7 +3434,20 @@ void qmp_block_commit(bool has_job_id, const char *job_id, const char *device, + /* default top_bs is the active layer */ + top_bs = bs; + +- if (has_top && top) { ++ if (has_top_node && has_top) { ++ error_setg(errp, "'top-node' and 'top' are mutually exclusive"); ++ goto out; ++ } else if (has_top_node) { ++ top_bs = bdrv_lookup_bs(NULL, top_node, errp); ++ if (top_bs == NULL) { ++ goto out; ++ } ++ if (!bdrv_chain_contains(bs, top_bs)) { ++ error_setg(errp, "'%s' is not in this backing file chain", ++ top_node); ++ goto out; ++ } ++ } else if (has_top && top) { + if (strcmp(bs->filename, top) != 0) { + top_bs = bdrv_find_backing_image(bs, top); + } +@@ -3445,7 +3460,20 @@ void qmp_block_commit(bool has_job_id, const char *job_id, const char *device, + + assert(bdrv_get_aio_context(top_bs) == aio_context); + +- if (has_base && base) { ++ if (has_base_node && has_base) { ++ error_setg(errp, "'base-node' and 'base' are mutually exclusive"); ++ goto out; ++ } else if (has_base_node) { ++ base_bs = bdrv_lookup_bs(NULL, base_node, errp); ++ if (base_bs == NULL) { ++ goto out; ++ } ++ if (!bdrv_chain_contains(top_bs, base_bs)) { ++ error_setg(errp, "'%s' is not in this backing file chain", ++ base_node); ++ goto out; ++ } ++ } else if (has_base && base) { + base_bs = bdrv_find_backing_image(top_bs, base); + } else { + base_bs = bdrv_find_base(top_bs); +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 56937db..8da07cd 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -1440,12 +1440,23 @@ + # + # @device: the device name or node-name of a root node + # +-# @base: The file name of the backing image to write data into. +-# If not specified, this is the deepest backing image. ++# @base-node: The node name of the backing image to write data into. ++# If not specified, this is the deepest backing image. ++# (since: 3.1) + # +-# @top: The file name of the backing image within the image chain, +-# which contains the topmost data to be committed down. If +-# not specified, this is the active layer. ++# @base: Same as @base-node, except that it is a file name rather than a node ++# name. This must be the exact filename string that was used to open the ++# node; other strings, even if addressing the same file, are not ++# accepted (deprecated, use @base-node instead) ++# ++# @top-node: The node name of the backing image within the image chain ++# which contains the topmost data to be committed down. If ++# not specified, this is the active layer. (since: 3.1) ++# ++# @top: Same as @top-node, except that it is a file name rather than a node ++# name. This must be the exact filename string that was used to open the ++# node; other strings, even if addressing the same file, are not ++# accepted (deprecated, use @base-node instead) + # + # @backing-file: The backing file string to write into the overlay + # image of 'top'. If 'top' is the active layer, +@@ -1514,7 +1525,8 @@ + # + ## + { 'command': 'block-commit', +- 'data': { '*job-id': 'str', 'device': 'str', '*base': 'str', '*top': 'str', ++ 'data': { '*job-id': 'str', 'device': 'str', '*base-node': 'str', ++ '*base': 'str', '*top-node': 'str', '*top': 'str', + '*backing-file': 'str', '*speed': 'int', + '*filter-node-name': 'str', + '*auto-finalize': 'bool', '*auto-dismiss': 'bool' } } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-configure-Allow-enable-seccomp-on-s390x-too.patch b/SOURCES/kvm-configure-Allow-enable-seccomp-on-s390x-too.patch deleted file mode 100644 index ec26e33..0000000 --- a/SOURCES/kvm-configure-Allow-enable-seccomp-on-s390x-too.patch +++ /dev/null @@ -1,46 +0,0 @@ -From eb80abd49652e09d10b44da5a75c753e76ef5beb Mon Sep 17 00:00:00 2001 -From: Thomas Huth -Date: Mon, 2 Oct 2017 07:04:17 +0200 -Subject: [PATCH 02/34] configure: Allow --enable-seccomp on s390x, too - -RH-Author: Thomas Huth -Message-id: <1506927858-5400-2-git-send-email-thuth@redhat.com> -Patchwork-id: 76788 -O-Subject: [RHEL-7.5 qemu-kvm-ma PATCH 1/2] configure: Allow --enable-seccomp on s390x, too -Bugzilla: 1491647 -RH-Acked-by: Eduardo Otubo -RH-Acked-by: Markus Armbruster -RH-Acked-by: Stefan Hajnoczi - -libseccomp supports s390x since version 2.3.0, and I was able to start -a VM with "-sandbox on" without any obvious problems by using this patch, -so it should be safe to allow --enable-seccomp on s390x nowadays, too. - -Signed-off-by: Thomas Huth -Message-Id: <1505385363-27717-1-git-send-email-thuth@redhat.com> -Acked-by: Christian Borntraeger -Acked-by: Eduardo Otubo -Acked-by: Halil Pasic -Signed-off-by: Cornelia Huck -(cherry picked from commit 3aa35fcffcf0fe22ac48d4277ed6057ae3e57ce0) -Signed-off-by: Miroslav Rezanina ---- - configure | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/configure b/configure -index 355c364..5cb65d0 100755 ---- a/configure -+++ b/configure -@@ -2050,7 +2050,7 @@ if test "$seccomp" != "no" ; then - arm|aarch64) - libseccomp_minver="2.2.3" - ;; -- ppc|ppc64) -+ ppc|ppc64|s390x) - libseccomp_minver="2.3.0" - ;; - *) --- -1.8.3.1 - diff --git a/SOURCES/kvm-configure-add-libpmem-support.patch b/SOURCES/kvm-configure-add-libpmem-support.patch new file mode 100644 index 0000000..57bd26c --- /dev/null +++ b/SOURCES/kvm-configure-add-libpmem-support.patch @@ -0,0 +1,130 @@ +From 17e8fa1ceb357d0008f651cd88a72f2630b24fc5 Mon Sep 17 00:00:00 2001 +From: "plai@redhat.com" +Date: Fri, 31 Aug 2018 16:25:55 +0200 +Subject: [PATCH 13/29] configure: add libpmem support + +RH-Author: plai@redhat.com +Message-id: <1535732759-22481-6-git-send-email-plai@redhat.com> +Patchwork-id: 82010 +O-Subject: [RHEL7.6 PATCH BZ 1539280 5/9] configure: add libpmem support +Bugzilla: 1539280 +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Pankaj Gupta +RH-Acked-by: Miroslav Rezanina + +From: Junyan He + +Add a pair of configure options --{enable,disable}-libpmem to control +whether QEMU is compiled with PMDK libpmem [1]. + +QEMU may write to the host persistent memory (e.g. in vNVDIMM label +emulation and live migration), so it must take the proper operations +to ensure the persistence of its own writes. Depending on the CPU +models and available instructions, the optimal operation can vary [2]. +PMDK libpmem have already implemented those operations on multiple CPU +models (x86 and ARM) and the logic to select the optimal ones, so QEMU +can just use libpmem rather than re-implement them. + +Libpem is a part of PMDK project(formerly known as NMVL). +The project's home page is: http://pmem.io/pmdk/ +And the project's repository is: https://github.com/pmem/pmdk/ + +For more information about libpmem APIs, you can refer to the comments +in source code of: pmdk/src/libpmem/pmem.c, begin at line 33. + +Signed-off-by: Junyan He +Signed-off-by: Haozhong Zhang +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Igor Mammedov +Reviewed-by: Richard Henderson +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 17824406fa55b303379f2e4af715c1e876c3535f) +Signed-off-by: Paul Lai + +Resolved Conflicts: + configure + +Signed-off-by: Miroslav Rezanina +--- + configure | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/configure b/configure +index a869f19..f9c8365 100755 +--- a/configure ++++ b/configure +@@ -454,6 +454,7 @@ vxhs="" + libxml2="" + vtd="yes" + rhel_target="rhv" ++libpmem="" + + supported_cpu="no" + supported_os="no" +@@ -1387,6 +1388,10 @@ for opt do + ;; + --rhel-target=*) rhel_target="$optarg" + ;; ++ --enable-libpmem) libpmem=yes ++ ;; ++ --disable-libpmem) libpmem=no ++ ;; + *) + echo "ERROR: unknown option $opt" + echo "Try '$0 --help' for more information" +@@ -1648,6 +1653,7 @@ disabled with --disable-FEATURE, default is enabled if available: + crypto-afalg Linux AF_ALG crypto backend driver + vhost-user vhost-user support + capstone capstone disassembler support ++ libpmem libpmem support + + NOTE: The object files are built at the place where configure is launched + EOF +@@ -5410,6 +5416,24 @@ EOF + fi + + ########################################## ++# check for libpmem ++ ++if test "$libpmem" != "no"; then ++ if $pkg_config --exists "libpmem"; then ++ libpmem="yes" ++ libpmem_libs=$($pkg_config --libs libpmem) ++ libpmem_cflags=$($pkg_config --cflags libpmem) ++ libs_softmmu="$libs_softmmu $libpmem_libs" ++ QEMU_CFLAGS="$QEMU_CFLAGS $libpmem_cflags" ++ else ++ if test "$libpmem" = "yes" ; then ++ feature_not_found "libpmem" "Install nvml or pmdk" ++ fi ++ libpmem="no" ++ fi ++fi ++ ++########################################## + # End of CC checks + # After here, no more $cc or $ld runs + +@@ -5873,6 +5897,7 @@ echo "VxHS block device $vxhs" + echo "capstone $capstone" + echo "VT-d emulation $vtd" + echo "RHEL target $rhel_target" ++echo "libpmem support $libpmem" + + if test "$sdl_too_old" = "yes"; then + echo "-> Your SDL version is too old - please upgrade to have SDL support" +@@ -6632,6 +6657,10 @@ if test "$rhel_target" = "rhv" ; then + echo "CONFIG_RHV=y" >> $config_host_mak + fi + ++if test "$libpmem" = "yes" ; then ++ echo "CONFIG_LIBPMEM=y" >> $config_host_mak ++fi ++ + if test "$tcg_interpreter" = "yes"; then + QEMU_INCLUDES="-iquote \$(SRC_PATH)/tcg/tci $QEMU_INCLUDES" + elif test "$ARCH" = "sparc64" ; then +-- +1.8.3.1 + diff --git a/SOURCES/kvm-configure-enable-s390-pgste-linker-option.patch b/SOURCES/kvm-configure-enable-s390-pgste-linker-option.patch deleted file mode 100644 index ee67ad0..0000000 --- a/SOURCES/kvm-configure-enable-s390-pgste-linker-option.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 487aafe7bfede37118f4664b473b9a3960a5b89d Mon Sep 17 00:00:00 2001 -From: Cornelia Huck -Date: Fri, 13 Oct 2017 14:13:00 +0200 -Subject: [PATCH 19/69] configure: enable --s390-pgste linker option - -RH-Author: Cornelia Huck -Message-id: <20171013141301.23131-2-cohuck@redhat.com> -Patchwork-id: 77285 -O-Subject: [RHV7.5 qemu-kvm-ma PATCH v3 1/2] configure: enable --s390-pgste linker option -Bugzilla: 1485399 -RH-Acked-by: Thomas Huth -RH-Acked-by: David Hildenbrand -RH-Acked-by: Jens Freimann - -From: Christian Borntraeger - -KVM guests on s390 need a different page table layout than normal -processes (2kb page table + 2kb page status extensions vs 2kb page table -only). As of today this has to be enabled via the vm.allocate_pgste -sysctl. - -Newer kernels (>= 4.12) on s390 check for an S390_PGSTE program header -and enable the pgste page table extensions in that case. This makes the -vm.allocate_pgste sysctl unnecessary. We enable this program header for -the s390 system emulation (qemu-system-s390x) if we build on s390 -- for s390 system emulation -- the linker supports --s390-pgste (binutils >= 2.29) -- KVM is enabled - -This will allow distributions to disable the global vm.allocate_pgste -sysctl, which will improve the page table allocation for non KVM -processes as only 2kb chunks are necessary. - -Cc: Christian Ehrhardt -Cc: Alexander Graf -Cc: Dan Horak -Cc: David Hildenbrand -Signed-off-by: Christian Borntraeger -Acked-by: Janosch Frank -Reviewed-by: Thomas Huth -Message-Id: <1503483383-199649-1-git-send-email-borntraeger@de.ibm.com> -Reviewed-by: David Hildenbrand -Signed-off-by: Cornelia Huck -(cherry picked from commit e9a3591fa09f273592451f8b9f83692bcbedb60c) -Signed-off-by: Miroslav Rezanina ---- - configure | 21 ++++++++++++++++++++- - 1 file changed, 20 insertions(+), 1 deletion(-) - -diff --git a/configure b/configure -index 0da6821..644e52d 100755 ---- a/configure -+++ b/configure -@@ -240,6 +240,11 @@ supported_target() { - return 1 - } - -+ -+ld_has() { -+ $ld --help 2>/dev/null | grep ".$1" >/dev/null 2>&1 -+} -+ - # default parameters - source_path=$(dirname "$0") - cpu="" -@@ -5033,7 +5038,7 @@ fi - # Use ASLR, no-SEH and DEP if available - if test "$mingw32" = "yes" ; then - for flag in --dynamicbase --no-seh --nxcompat; do -- if $ld --help 2>/dev/null | grep ".$flag" >/dev/null 2>/dev/null ; then -+ if ld_has $flag ; then - LDFLAGS="-Wl,$flag $LDFLAGS" - fi - done -@@ -6520,6 +6525,20 @@ if test "$target_linux_user" = "yes" -o "$target_bsd_user" = "yes" ; then - ldflags="$ldflags $textseg_ldflags" - fi - -+# Newer kernels on s390 check for an S390_PGSTE program header and -+# enable the pgste page table extensions in that case. This makes -+# the vm.allocate_pgste sysctl unnecessary. We enable this program -+# header if -+# - we build on s390x -+# - we build the system emulation for s390x (qemu-system-s390x) -+# - KVM is enabled -+# - the linker supports --s390-pgste -+if test "$TARGET_ARCH" = "s390x" -a "$target_softmmu" = "yes" -a "$ARCH" = "s390x" -a "$kvm" = "yes"; then -+ if ld_has --s390-pgste ; then -+ ldflags="-Wl,--s390-pgste $ldflags" -+ fi -+fi -+ - echo "LDFLAGS+=$ldflags" >> $config_target_mak - echo "QEMU_CFLAGS+=$cflags" >> $config_target_mak - --- -1.8.3.1 - diff --git a/SOURCES/kvm-console-fix-dpy_gfx_replace_surface-assert.patch b/SOURCES/kvm-console-fix-dpy_gfx_replace_surface-assert.patch deleted file mode 100644 index 1f57eb3..0000000 --- a/SOURCES/kvm-console-fix-dpy_gfx_replace_surface-assert.patch +++ /dev/null @@ -1,47 +0,0 @@ -From d8e09c7193591639d22c197bf265080cb22c2404 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Fri, 12 Jan 2018 11:30:11 +0100 -Subject: [PATCH 01/20] console: fix dpy_gfx_replace_surface assert -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Gerd Hoffmann -Message-id: <20180112113011.21952-2-kraxel@redhat.com> -Patchwork-id: 78565 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 1/1] console: fix dpy_gfx_replace_surface assert -Bugzilla: 1505696 -RH-Acked-by: John Snow -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Laszlo Ersek - -virtio-gpu can trigger the assert added by commit "6905b93447 console: -add same surface replace pre-condition" in multihead setups (where -surface can be NULL for secondary displays). Allow surface being NULL. - -Fixes: 6905b93447a42e606dfd126b90f75f4cd3c6fe94 -Signed-off-by: Gerd Hoffmann -Reviewed-by: Marc-André Lureau -Message-id: 20170906142109.2685-1-kraxel@redhat.com -(cherry picked from commit 1540008629bbb6a9c0826582d94ecf7a559f784c) -Signed-off-by: Miroslav Rezanina ---- - ui/console.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ui/console.c b/ui/console.c -index 6967fd4..e92e9e0 100644 ---- a/ui/console.c -+++ b/ui/console.c -@@ -1565,7 +1565,7 @@ void dpy_gfx_replace_surface(QemuConsole *con, - DisplaySurface *old_surface = con->surface; - DisplayChangeListener *dcl; - -- assert(old_surface != surface); -+ assert(old_surface != surface || surface == NULL); - - con->surface = surface; - QLIST_FOREACH(dcl, &s->listeners, next) { --- -1.8.3.1 - diff --git a/SOURCES/kvm-coroutine-abort-if-we-try-to-schedule-or-enter-a-pen.patch b/SOURCES/kvm-coroutine-abort-if-we-try-to-schedule-or-enter-a-pen.patch deleted file mode 100644 index c319edc..0000000 --- a/SOURCES/kvm-coroutine-abort-if-we-try-to-schedule-or-enter-a-pen.patch +++ /dev/null @@ -1,175 +0,0 @@ -From ab88ad152dbdf6e906da07e2c165f01985edfe13 Mon Sep 17 00:00:00 2001 -From: Jeffrey Cody -Date: Thu, 30 Nov 2017 22:49:08 +0100 -Subject: [PATCH 04/21] coroutine: abort if we try to schedule or enter a - pending coroutine - -RH-Author: Jeffrey Cody -Message-id: <27811c58f7dd73e9d8b6f51aff42a7de9bae37fc.1511985875.git.jcody@redhat.com> -Patchwork-id: 78044 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 04/11] coroutine: abort if we try to schedule or enter a pending coroutine -Bugzilla: 1506531 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: John Snow - -The previous patch fixed a race condition, in which there were -coroutines being executing doubly, or after coroutine deletion. - -We can detect common scenarios when this happens, and print an error -message and abort before we corrupt memory / data, or segfault. - -This patch will abort if an attempt to enter a coroutine is made while -it is currently pending execution, either in a specific AioContext bh, -or pending execution via a timer. It will also abort if a coroutine -is scheduled, before a prior scheduled run has occurred. - -We cannot rely on the existing co->caller check for recursive re-entry -to catch this, as the coroutine may run and exit with -COROUTINE_TERMINATE before the scheduled coroutine executes. - -(This is the scenario that was occurring and fixed in the previous -patch). - -This patch also re-orders the Coroutine struct elements in an attempt to -optimize caching. - -Signed-off-by: Jeff Cody -Reviewed-by: Stefan Hajnoczi -(cherry picked from commit 6133b39f3c36623425a6ede9e89d93175fde15cd) -Signed-off-by: Jeff Cody -Signed-off-by: Miroslav Rezanina ---- - include/qemu/coroutine_int.h | 13 ++++++++++--- - util/async.c | 13 +++++++++++++ - util/qemu-coroutine-sleep.c | 12 ++++++++++++ - util/qemu-coroutine.c | 14 ++++++++++++++ - 4 files changed, 49 insertions(+), 3 deletions(-) - -diff --git a/include/qemu/coroutine_int.h b/include/qemu/coroutine_int.h -index cb98892..59e8406 100644 ---- a/include/qemu/coroutine_int.h -+++ b/include/qemu/coroutine_int.h -@@ -46,14 +46,21 @@ struct Coroutine { - - size_t locks_held; - -+ /* Only used when the coroutine has yielded. */ -+ AioContext *ctx; -+ -+ /* Used to catch and abort on illegal co-routine entry. -+ * Will contain the name of the function that had first -+ * scheduled the coroutine. */ -+ const char *scheduled; -+ -+ QSIMPLEQ_ENTRY(Coroutine) co_queue_next; -+ - /* Coroutines that should be woken up when we yield or terminate. - * Only used when the coroutine is running. - */ - QSIMPLEQ_HEAD(, Coroutine) co_queue_wakeup; - -- /* Only used when the coroutine has yielded. */ -- AioContext *ctx; -- QSIMPLEQ_ENTRY(Coroutine) co_queue_next; - QSLIST_ENTRY(Coroutine) co_scheduled_next; - }; - -diff --git a/util/async.c b/util/async.c -index 0e1bd87..4dd9d95 100644 ---- a/util/async.c -+++ b/util/async.c -@@ -388,6 +388,9 @@ static void co_schedule_bh_cb(void *opaque) - QSLIST_REMOVE_HEAD(&straight, co_scheduled_next); - trace_aio_co_schedule_bh_cb(ctx, co); - aio_context_acquire(ctx); -+ -+ /* Protected by write barrier in qemu_aio_coroutine_enter */ -+ atomic_set(&co->scheduled, NULL); - qemu_coroutine_enter(co); - aio_context_release(ctx); - } -@@ -438,6 +441,16 @@ fail: - void aio_co_schedule(AioContext *ctx, Coroutine *co) - { - trace_aio_co_schedule(ctx, co); -+ const char *scheduled = atomic_cmpxchg(&co->scheduled, NULL, -+ __func__); -+ -+ if (scheduled) { -+ fprintf(stderr, -+ "%s: Co-routine was already scheduled in '%s'\n", -+ __func__, scheduled); -+ abort(); -+ } -+ - QSLIST_INSERT_HEAD_ATOMIC(&ctx->scheduled_coroutines, - co, co_scheduled_next); - qemu_bh_schedule(ctx->co_schedule_bh); -diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c -index 9c56550..254349c 100644 ---- a/util/qemu-coroutine-sleep.c -+++ b/util/qemu-coroutine-sleep.c -@@ -13,6 +13,7 @@ - - #include "qemu/osdep.h" - #include "qemu/coroutine.h" -+#include "qemu/coroutine_int.h" - #include "qemu/timer.h" - #include "block/aio.h" - -@@ -25,6 +26,8 @@ static void co_sleep_cb(void *opaque) - { - CoSleepCB *sleep_cb = opaque; - -+ /* Write of schedule protected by barrier write in aio_co_schedule */ -+ atomic_set(&sleep_cb->co->scheduled, NULL); - aio_co_wake(sleep_cb->co); - } - -@@ -34,6 +37,15 @@ void coroutine_fn co_aio_sleep_ns(AioContext *ctx, QEMUClockType type, - CoSleepCB sleep_cb = { - .co = qemu_coroutine_self(), - }; -+ -+ const char *scheduled = atomic_cmpxchg(&sleep_cb.co->scheduled, NULL, -+ __func__); -+ if (scheduled) { -+ fprintf(stderr, -+ "%s: Co-routine was already scheduled in '%s'\n", -+ __func__, scheduled); -+ abort(); -+ } - sleep_cb.ts = aio_timer_new(ctx, type, SCALE_NS, co_sleep_cb, &sleep_cb); - timer_mod(sleep_cb.ts, qemu_clock_get_ns(type) + ns); - qemu_coroutine_yield(); -diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c -index d6095c1..9eff7fd 100644 ---- a/util/qemu-coroutine.c -+++ b/util/qemu-coroutine.c -@@ -107,8 +107,22 @@ void qemu_aio_coroutine_enter(AioContext *ctx, Coroutine *co) - Coroutine *self = qemu_coroutine_self(); - CoroutineAction ret; - -+ /* Cannot rely on the read barrier for co in aio_co_wake(), as there are -+ * callers outside of aio_co_wake() */ -+ const char *scheduled = atomic_mb_read(&co->scheduled); -+ - trace_qemu_aio_coroutine_enter(ctx, self, co, co->entry_arg); - -+ /* if the Coroutine has already been scheduled, entering it again will -+ * cause us to enter it twice, potentially even after the coroutine has -+ * been deleted */ -+ if (scheduled) { -+ fprintf(stderr, -+ "%s: Co-routine was already scheduled in '%s'\n", -+ __func__, scheduled); -+ abort(); -+ } -+ - if (co->caller) { - fprintf(stderr, "Co-routine re-entered recursively\n"); - abort(); --- -1.8.3.1 - diff --git a/SOURCES/kvm-cpus-Fix-event-order-on-resume-of-stopped-guest.patch b/SOURCES/kvm-cpus-Fix-event-order-on-resume-of-stopped-guest.patch new file mode 100644 index 0000000..b9d8fae --- /dev/null +++ b/SOURCES/kvm-cpus-Fix-event-order-on-resume-of-stopped-guest.patch @@ -0,0 +1,149 @@ +From f94e1c832c510a3ca1b8bf0d383e7be2dce4909c Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Wed, 9 May 2018 14:42:21 +0200 +Subject: [PATCH 13/13] cpus: Fix event order on resume of stopped guest + +RH-Author: Markus Armbruster +Message-id: <20180509144221.14799-2-armbru@redhat.com> +Patchwork-id: 80191 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/1] cpus: Fix event order on resume of stopped guest +Bugzilla: 1566153 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Igor Mammedov + +When resume of a stopped guest immediately runs into block device +errors, the BLOCK_IO_ERROR event is sent before the RESUME event. + +Reproducer: + +1. Create a scratch image + $ dd if=/dev/zero of=scratch.img bs=1M count=100 + + Size doesn't actually matter. + +2. Prepare blkdebug configuration: + + $ cat >blkdebug.conf < ' + + Issue QMP command 'qmp_capabilities': + QMP> { "execute": "qmp_capabilities" } + +5. Boot the guest. + +6. In the guest, write to the scratch disk, e.g. like this: + + # dd if=/dev/zero of=/dev/vdb count=1 + + Do double-check the device specified with of= is actually the + scratch device! + +7. Issue QMP command 'cont': + QMP> { "execute": "cont" } + +After step 6, I get a BLOCK_IO_ERROR event followed by a STOP event. Good. + +After step 7, I get BLOCK_IO_ERROR, then RESUME, then STOP. Not so +good; I'd expect RESUME, then BLOCK_IO_ERROR, then STOP. + +The funny event order confuses libvirt: virsh -r domstate DOMAIN +--reason reports "paused (unknown)" rather than "paused (I/O error)". + +The culprit is vm_prepare_start(). + + /* Ensure that a STOP/RESUME pair of events is emitted if a + * vmstop request was pending. The BLOCK_IO_ERROR event, for + * example, according to documentation is always followed by + * the STOP event. + */ + if (runstate_is_running()) { + qapi_event_send_stop(&error_abort); + res = -1; + } else { + replay_enable_events(); + cpu_enable_ticks(); + runstate_set(RUN_STATE_RUNNING); + vm_state_notify(1, RUN_STATE_RUNNING); + } + + /* We are sending this now, but the CPUs will be resumed shortly later */ + qapi_event_send_resume(&error_abort); + return res; + +When resuming a stopped guest, we take the else branch before we get +to sending RESUME. vm_state_notify() runs virtio_vmstate_change(), +among other things. This restarts I/O, triggering the BLOCK_IO_ERROR +event. + +Reshuffle vm_prepare_start() to send the RESUME event earlier. + +Fixes RHBZ 1566153. + +Cc: Paolo Bonzini +Signed-off-by: Markus Armbruster +Message-Id: <20180423084518.2426-1-armbru@redhat.com> +Signed-off-by: Paolo Bonzini +(cherry picked from commit f056158d694d2adc63ff120ca71c73ae8b14426c) +Signed-off-by: Miroslav Rezanina +--- + cpus.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/cpus.c b/cpus.c +index 38eba8b..398392b 100644 +--- a/cpus.c ++++ b/cpus.c +@@ -2043,7 +2043,6 @@ int vm_stop(RunState state) + int vm_prepare_start(void) + { + RunState requested; +- int res = 0; + + qemu_vmstop_requested(&requested); + if (runstate_is_running() && requested == RUN_STATE__MAX) { +@@ -2057,17 +2056,18 @@ int vm_prepare_start(void) + */ + if (runstate_is_running()) { + qapi_event_send_stop(&error_abort); +- res = -1; +- } else { +- replay_enable_events(); +- cpu_enable_ticks(); +- runstate_set(RUN_STATE_RUNNING); +- vm_state_notify(1, RUN_STATE_RUNNING); ++ qapi_event_send_resume(&error_abort); ++ return -1; + } + + /* We are sending this now, but the CPUs will be resumed shortly later */ + qapi_event_send_resume(&error_abort); +- return res; ++ ++ replay_enable_events(); ++ cpu_enable_ticks(); ++ runstate_set(RUN_STATE_RUNNING); ++ vm_state_notify(1, RUN_STATE_RUNNING); ++ return 0; + } + + void vm_start(void) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-dirty-bitmap-fix-double-lock-on-bitmap-enabling.patch b/SOURCES/kvm-dirty-bitmap-fix-double-lock-on-bitmap-enabling.patch new file mode 100644 index 0000000..8823cde --- /dev/null +++ b/SOURCES/kvm-dirty-bitmap-fix-double-lock-on-bitmap-enabling.patch @@ -0,0 +1,74 @@ +From a37c990a113d5e205d928e629c96d3a82c00d920 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 18 Jul 2018 22:54:43 +0200 +Subject: [PATCH 58/89] dirty-bitmap: fix double lock on bitmap enabling + +RH-Author: John Snow +Message-id: <20180718225511.14878-8-jsnow@redhat.com> +Patchwork-id: 81403 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 07/35] dirty-bitmap: fix double lock on bitmap enabling +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Vladimir Sementsov-Ogievskiy + +Bitmap lock/unlock were added to bdrv_enable_dirty_bitmap in +8b1402ce80d, but some places were not updated correspondingly, which +leads to trying to take this lock twice, which is dead-lock. Fix this. + +Actually, iotest 199 (about dirty bitmap postcopy migration) is broken +now, and this fixes it. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-id: 20180625165745.25259-3-vsementsov@virtuozzo.com +Signed-off-by: John Snow +(cherry picked from commit 58f72b965e9e1820d246329461216c4d13140122) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 3 ++- + migration/block-dirty-bitmap.c | 4 ++-- + 2 files changed, 4 insertions(+), 3 deletions(-) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index 4d6ae8b..f580c1a 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -259,8 +259,9 @@ void bdrv_enable_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap) + /* Called with BQL taken. */ + void bdrv_dirty_bitmap_enable_successor(BdrvDirtyBitmap *bitmap) + { ++ assert(bitmap->mutex == bitmap->successor->mutex); + qemu_mutex_lock(bitmap->mutex); +- bdrv_enable_dirty_bitmap(bitmap->successor); ++ bdrv_enable_dirty_bitmap_locked(bitmap->successor); + qemu_mutex_unlock(bitmap->mutex); + } + +diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c +index 2c541c9..fefbc6a 100644 +--- a/migration/block-dirty-bitmap.c ++++ b/migration/block-dirty-bitmap.c +@@ -511,7 +511,7 @@ void dirty_bitmap_mig_before_vm_start(void) + DirtyBitmapLoadBitmapState *b = item->data; + + if (b->migrated) { +- bdrv_enable_dirty_bitmap(b->bitmap); ++ bdrv_enable_dirty_bitmap_locked(b->bitmap); + } else { + bdrv_dirty_bitmap_enable_successor(b->bitmap); + } +@@ -547,7 +547,7 @@ static void dirty_bitmap_load_complete(QEMUFile *f, DirtyBitmapLoadState *s) + if (enabled_bitmaps == NULL) { + /* in postcopy */ + bdrv_reclaim_dirty_bitmap_locked(s->bs, s->bitmap, &error_abort); +- bdrv_enable_dirty_bitmap(s->bitmap); ++ bdrv_enable_dirty_bitmap_locked(s->bitmap); + } else { + /* target not started, successor must be empty */ + int64_t count = bdrv_get_dirty_count(s->bitmap); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-docs-Add-image-locking-subsection.patch b/SOURCES/kvm-docs-Add-image-locking-subsection.patch deleted file mode 100644 index d3bca6e..0000000 --- a/SOURCES/kvm-docs-Add-image-locking-subsection.patch +++ /dev/null @@ -1,89 +0,0 @@ -From c83bac681bd10d576c3af9a45b49065aa6b7330e Mon Sep 17 00:00:00 2001 -From: Fam Zheng -Date: Thu, 30 Nov 2017 09:25:42 +0100 -Subject: [PATCH 05/36] docs: Add image locking subsection - -RH-Author: Fam Zheng -Message-id: <20171130092544.19231-4-famz@redhat.com> -Patchwork-id: 78016 -O-Subject: [RHV7.5 qemu-kvm-ma PATCH 3/5] docs: Add image locking subsection -Bugzilla: 1494210 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Jeffrey Cody -RH-Acked-by: John Snow - -This documents the image locking feature and explains when and how -related options can be used. - -Signed-off-by: Fam Zheng -Signed-off-by: Kevin Wolf -(cherry picked from commit b1d1cb272882dd6868740155120f6aeb260a204c) -Signed-off-by: Fam Zheng -Signed-off-by: Miroslav Rezanina ---- - docs/qemu-block-drivers.texi | 36 ++++++++++++++++++++++++++++++++++++ - qemu-doc.texi | 1 + - 2 files changed, 37 insertions(+) - -diff --git a/docs/qemu-block-drivers.texi b/docs/qemu-block-drivers.texi -index d3b8f3b..aa64e60 100644 ---- a/docs/qemu-block-drivers.texi -+++ b/docs/qemu-block-drivers.texi -@@ -785,6 +785,42 @@ warning: ssh server @code{ssh.example.com:22} does not support fsync - With sufficiently new versions of libssh2 and OpenSSH, @code{fsync} is - supported. - -+@node disk_image_locking -+@subsection Disk image file locking -+ -+By default, QEMU tries to protect image files from unexpected concurrent -+access, as long as it's supported by the block protocol driver and host -+operating system. If multiple QEMU processes (including QEMU emulators and -+utilities) try to open the same image with conflicting accessing modes, all but -+the first one will get an error. -+ -+This feature is currently supported by the file protocol on Linux with the Open -+File Descriptor (OFD) locking API, and can be configured to fall back to POSIX -+locking if the POSIX host doesn't support Linux OFD locking. -+ -+To explicitly enable image locking, specify "locking=on" in the file protocol -+driver options. If OFD locking is not possible, a warning will be printed and -+the POSIX locking API will be used. In this case there is a risk that the lock -+will get silently lost when doing hot plugging and block jobs, due to the -+shortcomings of the POSIX locking API. -+ -+QEMU transparently handles lock handover during shared storage migration. For -+shared virtual disk images between multiple VMs, the "share-rw" device option -+should be used. -+ -+Alternatively, locking can be fully disabled by "locking=off" block device -+option. In the command line, the option is usually in the form of -+"file.locking=off" as the protocol driver is normally placed as a "file" child -+under a format driver. For example: -+ -+@code{-blockdev driver=qcow2,file.filename=/path/to/image,file.locking=off,file.driver=file} -+ -+To check if image locking is active, check the output of the "lslocks" command -+on host and see if there are locks held by the QEMU process on the image file. -+More than one byte could be locked by the QEMU instance, each byte of which -+reflects a particular permission that is acquired or protected by the running -+block driver. -+ - @c man end - - @ignore -diff --git a/qemu-doc.texi b/qemu-doc.texi -index b0db386..6af38de 100644 ---- a/qemu-doc.texi -+++ b/qemu-doc.texi -@@ -405,6 +405,7 @@ encrypted disk images. - * disk_images_iscsi:: iSCSI LUNs - * disk_images_gluster:: GlusterFS disk images - * disk_images_ssh:: Secure Shell (ssh) disk images -+* disk_image_locking:: Disk image file locking - @end menu - - @node disk_images_quickstart --- -1.8.3.1 - diff --git a/SOURCES/kvm-docs-add-qemu-block-drivers-7-man-page.patch b/SOURCES/kvm-docs-add-qemu-block-drivers-7-man-page.patch deleted file mode 100644 index f38bd83..0000000 --- a/SOURCES/kvm-docs-add-qemu-block-drivers-7-man-page.patch +++ /dev/null @@ -1,1693 +0,0 @@ -From 8a61770b2643a2af889205cc643d62d0ea3121f5 Mon Sep 17 00:00:00 2001 -From: Fam Zheng -Date: Thu, 30 Nov 2017 09:25:41 +0100 -Subject: [PATCH 04/36] docs: add qemu-block-drivers(7) man page - -RH-Author: Fam Zheng -Message-id: <20171130092544.19231-3-famz@redhat.com> -Patchwork-id: 78014 -O-Subject: [RHV7.5 qemu-kvm-ma PATCH 2/5] docs: add qemu-block-drivers(7) man page -Bugzilla: 1494210 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Jeffrey Cody -RH-Acked-by: John Snow - -From: Stefan Hajnoczi - -Block driver documentation is available in qemu-doc.html. It would be -convenient to have documentation for formats, protocols, and filter -drivers in a man page. - -Extract the relevant part of qemu-doc.html into a new file called -docs/qemu-block-drivers.texi. This file can also be built as a -stand-alone document (man, html, etc). - -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Kevin Wolf -(cherry picked from commit 78aa8aa019b999ec07b62b322c1280a8250e44ac) -Signed-off-by: Fam Zheng -Signed-off-by: Miroslav Rezanina - -Conflicts: - Makefile -Context different because we have reverted 60b412dd18362bd in downstream -(as e0425f69f13). - qemu-doc.texi -We do s/qemu-system-i386/qemu-kvm/ everywhere in downstream docs. ---- - Makefile | 6 +- - docs/qemu-block-drivers.texi | 804 +++++++++++++++++++++++++++++++++++++++++++ - qemu-doc.texi | 781 +---------------------------------------- - 3 files changed, 810 insertions(+), 781 deletions(-) - create mode 100644 docs/qemu-block-drivers.texi - -diff --git a/Makefile b/Makefile -index 312ed5e..1a773a8 100644 ---- a/Makefile -+++ b/Makefile -@@ -209,6 +209,7 @@ ifdef BUILD_DOCS - DOCS=qemu-doc.html qemu-doc.txt qemu.1 qemu-img.1 qemu-nbd.8 qemu-ga.8 - DOCS+=docs/interop/qemu-qmp-ref.html docs/interop/qemu-qmp-ref.txt docs/interop/qemu-qmp-ref.7 - DOCS+=docs/interop/qemu-ga-ref.html docs/interop/qemu-ga-ref.txt docs/interop/qemu-ga-ref.7 -+DOCS+=docs/qemu-block-drivers.7 - ifdef CONFIG_LINUX - DOCS+=kvm_stat.1 - endif -@@ -531,6 +532,7 @@ distclean: clean - rm -f docs/interop/qemu-qmp-ref.txt docs/interop/qemu-ga-ref.txt - rm -f docs/interop/qemu-qmp-ref.pdf docs/interop/qemu-ga-ref.pdf - rm -f docs/interop/qemu-qmp-ref.html docs/interop/qemu-ga-ref.html -+ rm -f docs/qemu-block-drivers.7 - for d in $(TARGET_DIRS); do \ - rm -rf $$d || exit 1 ; \ - done -@@ -576,6 +578,7 @@ ifdef CONFIG_POSIX - $(INSTALL_DATA) qemu.1 "$(DESTDIR)$(mandir)/man1/qemu-kvm.1" - $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man7" - $(INSTALL_DATA) docs/interop/qemu-qmp-ref.7 "$(DESTDIR)$(mandir)/man7" -+ $(INSTALL_DATA) docs/qemu-block-drivers.7 "$(DESTDIR)$(mandir)/man7" - ifneq ($(TOOLS),) - $(INSTALL_DATA) qemu-img.1 "$(DESTDIR)$(mandir)/man1" - $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man8" -@@ -725,6 +728,7 @@ qemu-img.1: qemu-img.texi qemu-option-trace.texi qemu-img-cmds.texi - fsdev/virtfs-proxy-helper.1: fsdev/virtfs-proxy-helper.texi - qemu-nbd.8: qemu-nbd.texi qemu-option-trace.texi - qemu-ga.8: qemu-ga.texi -+docs/qemu-block-drivers.7: docs/qemu-block-drivers.texi - - html: qemu-doc.html docs/interop/qemu-qmp-ref.html docs/interop/qemu-ga-ref.html - info: qemu-doc.info docs/interop/qemu-qmp-ref.info docs/interop/qemu-ga-ref.info -@@ -739,7 +743,7 @@ kvm_stat.1: scripts/kvm/kvm_stat.texi - qemu-doc.html qemu-doc.info qemu-doc.pdf qemu-doc.txt: \ - qemu-img.texi qemu-nbd.texi qemu-options.texi qemu-option-trace.texi \ - qemu-monitor.texi qemu-img-cmds.texi qemu-ga.texi \ -- qemu-monitor-info.texi -+ qemu-monitor-info.texi docs/qemu-block-drivers.texi - - docs/interop/qemu-ga-ref.dvi docs/interop/qemu-ga-ref.html \ - docs/interop/qemu-ga-ref.info docs/interop/qemu-ga-ref.pdf \ -diff --git a/docs/qemu-block-drivers.texi b/docs/qemu-block-drivers.texi -new file mode 100644 -index 0000000..d3b8f3b ---- /dev/null -+++ b/docs/qemu-block-drivers.texi -@@ -0,0 +1,804 @@ -+@c man begin SYNOPSIS -+QEMU block driver reference manual -+@c man end -+ -+@c man begin DESCRIPTION -+ -+@node disk_images_formats -+@subsection Disk image file formats -+ -+QEMU supports many image file formats that can be used with VMs as well as with -+any of the tools (like @code{qemu-img}). This includes the preferred formats -+raw and qcow2 as well as formats that are supported for compatibility with -+older QEMU versions or other hypervisors. -+ -+Depending on the image format, different options can be passed to -+@code{qemu-img create} and @code{qemu-img convert} using the @code{-o} option. -+This section describes each format and the options that are supported for it. -+ -+@table @option -+@item raw -+ -+Raw disk image format. This format has the advantage of -+being simple and easily exportable to all other emulators. If your -+file system supports @emph{holes} (for example in ext2 or ext3 on -+Linux or NTFS on Windows), then only the written sectors will reserve -+space. Use @code{qemu-img info} to know the real size used by the -+image or @code{ls -ls} on Unix/Linux. -+ -+Supported options: -+@table @code -+@item preallocation -+Preallocation mode (allowed values: @code{off}, @code{falloc}, @code{full}). -+@code{falloc} mode preallocates space for image by calling posix_fallocate(). -+@code{full} mode preallocates space for image by writing zeros to underlying -+storage. -+@end table -+ -+@item qcow2 -+QEMU image format, the most versatile format. Use it to have smaller -+images (useful if your filesystem does not supports holes, for example -+on Windows), zlib based compression and support of multiple VM -+snapshots. -+ -+Supported options: -+@table @code -+@item compat -+Determines the qcow2 version to use. @code{compat=0.10} uses the -+traditional image format that can be read by any QEMU since 0.10. -+@code{compat=1.1} enables image format extensions that only QEMU 1.1 and -+newer understand (this is the default). Amongst others, this includes -+zero clusters, which allow efficient copy-on-read for sparse images. -+ -+@item backing_file -+File name of a base image (see @option{create} subcommand) -+@item backing_fmt -+Image format of the base image -+@item encryption -+This option is deprecated and equivalent to @code{encrypt.format=aes} -+ -+@item encrypt.format -+ -+If this is set to @code{luks}, it requests that the qcow2 payload (not -+qcow2 header) be encrypted using the LUKS format. The passphrase to -+use to unlock the LUKS key slot is given by the @code{encrypt.key-secret} -+parameter. LUKS encryption parameters can be tuned with the other -+@code{encrypt.*} parameters. -+ -+If this is set to @code{aes}, the image is encrypted with 128-bit AES-CBC. -+The encryption key is given by the @code{encrypt.key-secret} parameter. -+This encryption format is considered to be flawed by modern cryptography -+standards, suffering from a number of design problems: -+ -+@itemize @minus -+@item The AES-CBC cipher is used with predictable initialization vectors based -+on the sector number. This makes it vulnerable to chosen plaintext attacks -+which can reveal the existence of encrypted data. -+@item The user passphrase is directly used as the encryption key. A poorly -+chosen or short passphrase will compromise the security of the encryption. -+@item In the event of the passphrase being compromised there is no way to -+change the passphrase to protect data in any qcow images. The files must -+be cloned, using a different encryption passphrase in the new file. The -+original file must then be securely erased using a program like shred, -+though even this is ineffective with many modern storage technologies. -+@end itemize -+ -+The use of this is no longer supported in system emulators. Support only -+remains in the command line utilities, for the purposes of data liberation -+and interoperability with old versions of QEMU. The @code{luks} format -+should be used instead. -+ -+@item encrypt.key-secret -+ -+Provides the ID of a @code{secret} object that contains the passphrase -+(@code{encrypt.format=luks}) or encryption key (@code{encrypt.format=aes}). -+ -+@item encrypt.cipher-alg -+ -+Name of the cipher algorithm and key length. Currently defaults -+to @code{aes-256}. Only used when @code{encrypt.format=luks}. -+ -+@item encrypt.cipher-mode -+ -+Name of the encryption mode to use. Currently defaults to @code{xts}. -+Only used when @code{encrypt.format=luks}. -+ -+@item encrypt.ivgen-alg -+ -+Name of the initialization vector generator algorithm. Currently defaults -+to @code{plain64}. Only used when @code{encrypt.format=luks}. -+ -+@item encrypt.ivgen-hash-alg -+ -+Name of the hash algorithm to use with the initialization vector generator -+(if required). Defaults to @code{sha256}. Only used when @code{encrypt.format=luks}. -+ -+@item encrypt.hash-alg -+ -+Name of the hash algorithm to use for PBKDF algorithm -+Defaults to @code{sha256}. Only used when @code{encrypt.format=luks}. -+ -+@item encrypt.iter-time -+ -+Amount of time, in milliseconds, to use for PBKDF algorithm per key slot. -+Defaults to @code{2000}. Only used when @code{encrypt.format=luks}. -+ -+@item cluster_size -+Changes the qcow2 cluster size (must be between 512 and 2M). Smaller cluster -+sizes can improve the image file size whereas larger cluster sizes generally -+provide better performance. -+ -+@item preallocation -+Preallocation mode (allowed values: @code{off}, @code{metadata}, @code{falloc}, -+@code{full}). An image with preallocated metadata is initially larger but can -+improve performance when the image needs to grow. @code{falloc} and @code{full} -+preallocations are like the same options of @code{raw} format, but sets up -+metadata also. -+ -+@item lazy_refcounts -+If this option is set to @code{on}, reference count updates are postponed with -+the goal of avoiding metadata I/O and improving performance. This is -+particularly interesting with @option{cache=writethrough} which doesn't batch -+metadata updates. The tradeoff is that after a host crash, the reference count -+tables must be rebuilt, i.e. on the next open an (automatic) @code{qemu-img -+check -r all} is required, which may take some time. -+ -+This option can only be enabled if @code{compat=1.1} is specified. -+ -+@item nocow -+If this option is set to @code{on}, it will turn off COW of the file. It's only -+valid on btrfs, no effect on other file systems. -+ -+Btrfs has low performance when hosting a VM image file, even more when the guest -+on the VM also using btrfs as file system. Turning off COW is a way to mitigate -+this bad performance. Generally there are two ways to turn off COW on btrfs: -+a) Disable it by mounting with nodatacow, then all newly created files will be -+NOCOW. b) For an empty file, add the NOCOW file attribute. That's what this option -+does. -+ -+Note: this option is only valid to new or empty files. If there is an existing -+file which is COW and has data blocks already, it couldn't be changed to NOCOW -+by setting @code{nocow=on}. One can issue @code{lsattr filename} to check if -+the NOCOW flag is set or not (Capital 'C' is NOCOW flag). -+ -+@end table -+ -+@item qed -+Old QEMU image format with support for backing files and compact image files -+(when your filesystem or transport medium does not support holes). -+ -+When converting QED images to qcow2, you might want to consider using the -+@code{lazy_refcounts=on} option to get a more QED-like behaviour. -+ -+Supported options: -+@table @code -+@item backing_file -+File name of a base image (see @option{create} subcommand). -+@item backing_fmt -+Image file format of backing file (optional). Useful if the format cannot be -+autodetected because it has no header, like some vhd/vpc files. -+@item cluster_size -+Changes the cluster size (must be power-of-2 between 4K and 64K). Smaller -+cluster sizes can improve the image file size whereas larger cluster sizes -+generally provide better performance. -+@item table_size -+Changes the number of clusters per L1/L2 table (must be power-of-2 between 1 -+and 16). There is normally no need to change this value but this option can be -+used for performance benchmarking. -+@end table -+ -+@item qcow -+Old QEMU image format with support for backing files, compact image files, -+encryption and compression. -+ -+Supported options: -+@table @code -+@item backing_file -+File name of a base image (see @option{create} subcommand) -+@item encryption -+This option is deprecated and equivalent to @code{encrypt.format=aes} -+ -+@item encrypt.format -+If this is set to @code{aes}, the image is encrypted with 128-bit AES-CBC. -+The encryption key is given by the @code{encrypt.key-secret} parameter. -+This encryption format is considered to be flawed by modern cryptography -+standards, suffering from a number of design problems enumerated previously -+against the @code{qcow2} image format. -+ -+The use of this is no longer supported in system emulators. Support only -+remains in the command line utilities, for the purposes of data liberation -+and interoperability with old versions of QEMU. -+ -+Users requiring native encryption should use the @code{qcow2} format -+instead with @code{encrypt.format=luks}. -+ -+@item encrypt.key-secret -+ -+Provides the ID of a @code{secret} object that contains the encryption -+key (@code{encrypt.format=aes}). -+ -+@end table -+ -+@item luks -+ -+LUKS v1 encryption format, compatible with Linux dm-crypt/cryptsetup -+ -+Supported options: -+@table @code -+ -+@item key-secret -+ -+Provides the ID of a @code{secret} object that contains the passphrase. -+ -+@item cipher-alg -+ -+Name of the cipher algorithm and key length. Currently defaults -+to @code{aes-256}. -+ -+@item cipher-mode -+ -+Name of the encryption mode to use. Currently defaults to @code{xts}. -+ -+@item ivgen-alg -+ -+Name of the initialization vector generator algorithm. Currently defaults -+to @code{plain64}. -+ -+@item ivgen-hash-alg -+ -+Name of the hash algorithm to use with the initialization vector generator -+(if required). Defaults to @code{sha256}. -+ -+@item hash-alg -+ -+Name of the hash algorithm to use for PBKDF algorithm -+Defaults to @code{sha256}. -+ -+@item iter-time -+ -+Amount of time, in milliseconds, to use for PBKDF algorithm per key slot. -+Defaults to @code{2000}. -+ -+@end table -+ -+@item vdi -+VirtualBox 1.1 compatible image format. -+Supported options: -+@table @code -+@item static -+If this option is set to @code{on}, the image is created with metadata -+preallocation. -+@end table -+ -+@item vmdk -+VMware 3 and 4 compatible image format. -+ -+Supported options: -+@table @code -+@item backing_file -+File name of a base image (see @option{create} subcommand). -+@item compat6 -+Create a VMDK version 6 image (instead of version 4) -+@item hwversion -+Specify vmdk virtual hardware version. Compat6 flag cannot be enabled -+if hwversion is specified. -+@item subformat -+Specifies which VMDK subformat to use. Valid options are -+@code{monolithicSparse} (default), -+@code{monolithicFlat}, -+@code{twoGbMaxExtentSparse}, -+@code{twoGbMaxExtentFlat} and -+@code{streamOptimized}. -+@end table -+ -+@item vpc -+VirtualPC compatible image format (VHD). -+Supported options: -+@table @code -+@item subformat -+Specifies which VHD subformat to use. Valid options are -+@code{dynamic} (default) and @code{fixed}. -+@end table -+ -+@item VHDX -+Hyper-V compatible image format (VHDX). -+Supported options: -+@table @code -+@item subformat -+Specifies which VHDX subformat to use. Valid options are -+@code{dynamic} (default) and @code{fixed}. -+@item block_state_zero -+Force use of payload blocks of type 'ZERO'. Can be set to @code{on} (default) -+or @code{off}. When set to @code{off}, new blocks will be created as -+@code{PAYLOAD_BLOCK_NOT_PRESENT}, which means parsers are free to return -+arbitrary data for those blocks. Do not set to @code{off} when using -+@code{qemu-img convert} with @code{subformat=dynamic}. -+@item block_size -+Block size; min 1 MB, max 256 MB. 0 means auto-calculate based on image size. -+@item log_size -+Log size; min 1 MB. -+@end table -+@end table -+ -+@subsubsection Read-only formats -+More disk image file formats are supported in a read-only mode. -+@table @option -+@item bochs -+Bochs images of @code{growing} type. -+@item cloop -+Linux Compressed Loop image, useful only to reuse directly compressed -+CD-ROM images present for example in the Knoppix CD-ROMs. -+@item dmg -+Apple disk image. -+@item parallels -+Parallels disk image format. -+@end table -+ -+ -+@node host_drives -+@subsection Using host drives -+ -+In addition to disk image files, QEMU can directly access host -+devices. We describe here the usage for QEMU version >= 0.8.3. -+ -+@subsubsection Linux -+ -+On Linux, you can directly use the host device filename instead of a -+disk image filename provided you have enough privileges to access -+it. For example, use @file{/dev/cdrom} to access to the CDROM. -+ -+@table @code -+@item CD -+You can specify a CDROM device even if no CDROM is loaded. QEMU has -+specific code to detect CDROM insertion or removal. CDROM ejection by -+the guest OS is supported. Currently only data CDs are supported. -+@item Floppy -+You can specify a floppy device even if no floppy is loaded. Floppy -+removal is currently not detected accurately (if you change floppy -+without doing floppy access while the floppy is not loaded, the guest -+OS will think that the same floppy is loaded). -+Use of the host's floppy device is deprecated, and support for it will -+be removed in a future release. -+@item Hard disks -+Hard disks can be used. Normally you must specify the whole disk -+(@file{/dev/hdb} instead of @file{/dev/hdb1}) so that the guest OS can -+see it as a partitioned disk. WARNING: unless you know what you do, it -+is better to only make READ-ONLY accesses to the hard disk otherwise -+you may corrupt your host data (use the @option{-snapshot} command -+line option or modify the device permissions accordingly). -+@end table -+ -+@subsubsection Windows -+ -+@table @code -+@item CD -+The preferred syntax is the drive letter (e.g. @file{d:}). The -+alternate syntax @file{\\.\d:} is supported. @file{/dev/cdrom} is -+supported as an alias to the first CDROM drive. -+ -+Currently there is no specific code to handle removable media, so it -+is better to use the @code{change} or @code{eject} monitor commands to -+change or eject media. -+@item Hard disks -+Hard disks can be used with the syntax: @file{\\.\PhysicalDrive@var{N}} -+where @var{N} is the drive number (0 is the first hard disk). -+ -+WARNING: unless you know what you do, it is better to only make -+READ-ONLY accesses to the hard disk otherwise you may corrupt your -+host data (use the @option{-snapshot} command line so that the -+modifications are written in a temporary file). -+@end table -+ -+ -+@subsubsection Mac OS X -+ -+@file{/dev/cdrom} is an alias to the first CDROM. -+ -+Currently there is no specific code to handle removable media, so it -+is better to use the @code{change} or @code{eject} monitor commands to -+change or eject media. -+ -+@node disk_images_fat_images -+@subsection Virtual FAT disk images -+ -+QEMU can automatically create a virtual FAT disk image from a -+directory tree. In order to use it, just type: -+ -+@example -+qemu-kvm linux.img -hdb fat:/my_directory -+@end example -+ -+Then you access access to all the files in the @file{/my_directory} -+directory without having to copy them in a disk image or to export -+them via SAMBA or NFS. The default access is @emph{read-only}. -+ -+Floppies can be emulated with the @code{:floppy:} option: -+ -+@example -+qemu-kvm linux.img -fda fat:floppy:/my_directory -+@end example -+ -+A read/write support is available for testing (beta stage) with the -+@code{:rw:} option: -+ -+@example -+qemu-kvm linux.img -fda fat:floppy:rw:/my_directory -+@end example -+ -+What you should @emph{never} do: -+@itemize -+@item use non-ASCII filenames ; -+@item use "-snapshot" together with ":rw:" ; -+@item expect it to work when loadvm'ing ; -+@item write to the FAT directory on the host system while accessing it with the guest system. -+@end itemize -+ -+@node disk_images_nbd -+@subsection NBD access -+ -+QEMU can access directly to block device exported using the Network Block Device -+protocol. -+ -+@example -+qemu-kvm linux.img -hdb nbd://my_nbd_server.mydomain.org:1024/ -+@end example -+ -+If the NBD server is located on the same host, you can use an unix socket instead -+of an inet socket: -+ -+@example -+qemu-kvm linux.img -hdb nbd+unix://?socket=/tmp/my_socket -+@end example -+ -+In this case, the block device must be exported using qemu-nbd: -+ -+@example -+qemu-nbd --socket=/tmp/my_socket my_disk.qcow2 -+@end example -+ -+The use of qemu-nbd allows sharing of a disk between several guests: -+@example -+qemu-nbd --socket=/tmp/my_socket --share=2 my_disk.qcow2 -+@end example -+ -+@noindent -+and then you can use it with two guests: -+@example -+qemu-kvm linux1.img -hdb nbd+unix://?socket=/tmp/my_socket -+qemu-kvm linux2.img -hdb nbd+unix://?socket=/tmp/my_socket -+@end example -+ -+If the nbd-server uses named exports (supported since NBD 2.9.18, or with QEMU's -+own embedded NBD server), you must specify an export name in the URI: -+@example -+qemu-kvm -cdrom nbd://localhost/debian-500-ppc-netinst -+qemu-kvm -cdrom nbd://localhost/openSUSE-11.1-ppc-netinst -+@end example -+ -+The URI syntax for NBD is supported since QEMU 1.3. An alternative syntax is -+also available. Here are some example of the older syntax: -+@example -+qemu-kvm linux.img -hdb nbd:my_nbd_server.mydomain.org:1024 -+qemu-kvm linux2.img -hdb nbd:unix:/tmp/my_socket -+qemu-kvm -cdrom nbd:localhost:10809:exportname=debian-500-ppc-netinst -+@end example -+ -+@node disk_images_sheepdog -+@subsection Sheepdog disk images -+ -+Sheepdog is a distributed storage system for QEMU. It provides highly -+available block level storage volumes that can be attached to -+QEMU-based virtual machines. -+ -+You can create a Sheepdog disk image with the command: -+@example -+qemu-img create sheepdog:///@var{image} @var{size} -+@end example -+where @var{image} is the Sheepdog image name and @var{size} is its -+size. -+ -+To import the existing @var{filename} to Sheepdog, you can use a -+convert command. -+@example -+qemu-img convert @var{filename} sheepdog:///@var{image} -+@end example -+ -+You can boot from the Sheepdog disk image with the command: -+@example -+qemu-kvm sheepdog:///@var{image} -+@end example -+ -+You can also create a snapshot of the Sheepdog image like qcow2. -+@example -+qemu-img snapshot -c @var{tag} sheepdog:///@var{image} -+@end example -+where @var{tag} is a tag name of the newly created snapshot. -+ -+To boot from the Sheepdog snapshot, specify the tag name of the -+snapshot. -+@example -+qemu-kvm sheepdog:///@var{image}#@var{tag} -+@end example -+ -+You can create a cloned image from the existing snapshot. -+@example -+qemu-img create -b sheepdog:///@var{base}#@var{tag} sheepdog:///@var{image} -+@end example -+where @var{base} is a image name of the source snapshot and @var{tag} -+is its tag name. -+ -+You can use an unix socket instead of an inet socket: -+ -+@example -+qemu-kvm sheepdog+unix:///@var{image}?socket=@var{path} -+@end example -+ -+If the Sheepdog daemon doesn't run on the local host, you need to -+specify one of the Sheepdog servers to connect to. -+@example -+qemu-img create sheepdog://@var{hostname}:@var{port}/@var{image} @var{size} -+qemu-kvm sheepdog://@var{hostname}:@var{port}/@var{image} -+@end example -+ -+@node disk_images_iscsi -+@subsection iSCSI LUNs -+ -+iSCSI is a popular protocol used to access SCSI devices across a computer -+network. -+ -+There are two different ways iSCSI devices can be used by QEMU. -+ -+The first method is to mount the iSCSI LUN on the host, and make it appear as -+any other ordinary SCSI device on the host and then to access this device as a -+/dev/sd device from QEMU. How to do this differs between host OSes. -+ -+The second method involves using the iSCSI initiator that is built into -+QEMU. This provides a mechanism that works the same way regardless of which -+host OS you are running QEMU on. This section will describe this second method -+of using iSCSI together with QEMU. -+ -+In QEMU, iSCSI devices are described using special iSCSI URLs -+ -+@example -+URL syntax: -+iscsi://[[%]@@][:]// -+@end example -+ -+Username and password are optional and only used if your target is set up -+using CHAP authentication for access control. -+Alternatively the username and password can also be set via environment -+variables to have these not show up in the process list -+ -+@example -+export LIBISCSI_CHAP_USERNAME= -+export LIBISCSI_CHAP_PASSWORD= -+iscsi://// -+@end example -+ -+Various session related parameters can be set via special options, either -+in a configuration file provided via '-readconfig' or directly on the -+command line. -+ -+If the initiator-name is not specified qemu will use a default name -+of 'iqn.2008-11.org.linux-kvm[:'] where is the UUID of the -+virtual machine. If the UUID is not specified qemu will use -+'iqn.2008-11.org.linux-kvm[:'] where is the name of the -+virtual machine. -+ -+@example -+Setting a specific initiator name to use when logging in to the target -+-iscsi initiator-name=iqn.qemu.test:my-initiator -+@end example -+ -+@example -+Controlling which type of header digest to negotiate with the target -+-iscsi header-digest=CRC32C|CRC32C-NONE|NONE-CRC32C|NONE -+@end example -+ -+These can also be set via a configuration file -+@example -+[iscsi] -+ user = "CHAP username" -+ password = "CHAP password" -+ initiator-name = "iqn.qemu.test:my-initiator" -+ # header digest is one of CRC32C|CRC32C-NONE|NONE-CRC32C|NONE -+ header-digest = "CRC32C" -+@end example -+ -+ -+Setting the target name allows different options for different targets -+@example -+[iscsi "iqn.target.name"] -+ user = "CHAP username" -+ password = "CHAP password" -+ initiator-name = "iqn.qemu.test:my-initiator" -+ # header digest is one of CRC32C|CRC32C-NONE|NONE-CRC32C|NONE -+ header-digest = "CRC32C" -+@end example -+ -+ -+Howto use a configuration file to set iSCSI configuration options: -+@example -+cat >iscsi.conf <= 0.8.3. -- --@subsubsection Linux -- --On Linux, you can directly use the host device filename instead of a --disk image filename provided you have enough privileges to access --it. For example, use @file{/dev/cdrom} to access to the CDROM. -- --@table @code --@item CD --You can specify a CDROM device even if no CDROM is loaded. QEMU has --specific code to detect CDROM insertion or removal. CDROM ejection by --the guest OS is supported. Currently only data CDs are supported. --@item Floppy --You can specify a floppy device even if no floppy is loaded. Floppy --removal is currently not detected accurately (if you change floppy --without doing floppy access while the floppy is not loaded, the guest --OS will think that the same floppy is loaded). --Use of the host's floppy device is deprecated, and support for it will --be removed in a future release. --@item Hard disks --Hard disks can be used. Normally you must specify the whole disk --(@file{/dev/hdb} instead of @file{/dev/hdb1}) so that the guest OS can --see it as a partitioned disk. WARNING: unless you know what you do, it --is better to only make READ-ONLY accesses to the hard disk otherwise --you may corrupt your host data (use the @option{-snapshot} command --line option or modify the device permissions accordingly). --@end table -- --@subsubsection Windows -- --@table @code --@item CD --The preferred syntax is the drive letter (e.g. @file{d:}). The --alternate syntax @file{\\.\d:} is supported. @file{/dev/cdrom} is --supported as an alias to the first CDROM drive. -- --Currently there is no specific code to handle removable media, so it --is better to use the @code{change} or @code{eject} monitor commands to --change or eject media. --@item Hard disks --Hard disks can be used with the syntax: @file{\\.\PhysicalDrive@var{N}} --where @var{N} is the drive number (0 is the first hard disk). -- --WARNING: unless you know what you do, it is better to only make --READ-ONLY accesses to the hard disk otherwise you may corrupt your --host data (use the @option{-snapshot} command line so that the --modifications are written in a temporary file). --@end table -- -- --@subsubsection Mac OS X -- --@file{/dev/cdrom} is an alias to the first CDROM. -- --Currently there is no specific code to handle removable media, so it --is better to use the @code{change} or @code{eject} monitor commands to --change or eject media. -- --@node disk_images_fat_images --@subsection Virtual FAT disk images -- --QEMU can automatically create a virtual FAT disk image from a --directory tree. In order to use it, just type: -- --@example --qemu-kvm linux.img -hdb fat:/my_directory --@end example -- --Then you access access to all the files in the @file{/my_directory} --directory without having to copy them in a disk image or to export --them via SAMBA or NFS. The default access is @emph{read-only}. -- --Floppies can be emulated with the @code{:floppy:} option: -- --@example --qemu-kvm linux.img -fda fat:floppy:/my_directory --@end example -- --A read/write support is available for testing (beta stage) with the --@code{:rw:} option: -- --@example --qemu-kvm linux.img -fda fat:floppy:rw:/my_directory --@end example -- --What you should @emph{never} do: --@itemize --@item use non-ASCII filenames ; --@item use "-snapshot" together with ":rw:" ; --@item expect it to work when loadvm'ing ; --@item write to the FAT directory on the host system while accessing it with the guest system. --@end itemize -- --@node disk_images_nbd --@subsection NBD access -- --QEMU can access directly to block device exported using the Network Block Device --protocol. -- --@example --qemu-kvm linux.img -hdb nbd://my_nbd_server.mydomain.org:1024/ --@end example -- --If the NBD server is located on the same host, you can use an unix socket instead --of an inet socket: -- --@example --qemu-kvm linux.img -hdb nbd+unix://?socket=/tmp/my_socket --@end example -- --In this case, the block device must be exported using qemu-nbd: -- --@example --qemu-nbd --socket=/tmp/my_socket my_disk.qcow2 --@end example -- --The use of qemu-nbd allows sharing of a disk between several guests: --@example --qemu-nbd --socket=/tmp/my_socket --share=2 my_disk.qcow2 --@end example -- --@noindent --and then you can use it with two guests: --@example --qemu-kvm linux1.img -hdb nbd+unix://?socket=/tmp/my_socket --qemu-kvm linux2.img -hdb nbd+unix://?socket=/tmp/my_socket --@end example -- --If the nbd-server uses named exports (supported since NBD 2.9.18, or with QEMU's --own embedded NBD server), you must specify an export name in the URI: --@example --qemu-kvm -cdrom nbd://localhost/debian-500-ppc-netinst --qemu-kvm -cdrom nbd://localhost/openSUSE-11.1-ppc-netinst --@end example -- --The URI syntax for NBD is supported since QEMU 1.3. An alternative syntax is --also available. Here are some example of the older syntax: --@example --qemu-kvm linux.img -hdb nbd:my_nbd_server.mydomain.org:1024 --qemu-kvm linux2.img -hdb nbd:unix:/tmp/my_socket --qemu-kvm -cdrom nbd:localhost:10809:exportname=debian-500-ppc-netinst --@end example -- --@node disk_images_sheepdog --@subsection Sheepdog disk images -- --Sheepdog is a distributed storage system for QEMU. It provides highly --available block level storage volumes that can be attached to --QEMU-based virtual machines. -- --You can create a Sheepdog disk image with the command: --@example --qemu-img create sheepdog:///@var{image} @var{size} --@end example --where @var{image} is the Sheepdog image name and @var{size} is its --size. -- --To import the existing @var{filename} to Sheepdog, you can use a --convert command. --@example --qemu-img convert @var{filename} sheepdog:///@var{image} --@end example -- --You can boot from the Sheepdog disk image with the command: --@example --qemu-kvm sheepdog:///@var{image} --@end example -- --You can also create a snapshot of the Sheepdog image like qcow2. --@example --qemu-img snapshot -c @var{tag} sheepdog:///@var{image} --@end example --where @var{tag} is a tag name of the newly created snapshot. -- --To boot from the Sheepdog snapshot, specify the tag name of the --snapshot. --@example --qemu-kvm sheepdog:///@var{image}#@var{tag} --@end example -- --You can create a cloned image from the existing snapshot. --@example --qemu-img create -b sheepdog:///@var{base}#@var{tag} sheepdog:///@var{image} --@end example --where @var{base} is a image name of the source snapshot and @var{tag} --is its tag name. -- --You can use an unix socket instead of an inet socket: -- --@example --qemu-kvm sheepdog+unix:///@var{image}?socket=@var{path} --@end example -- --If the Sheepdog daemon doesn't run on the local host, you need to --specify one of the Sheepdog servers to connect to. --@example --qemu-img create sheepdog://@var{hostname}:@var{port}/@var{image} @var{size} --qemu-kvm sheepdog://@var{hostname}:@var{port}/@var{image} --@end example -- --@node disk_images_iscsi --@subsection iSCSI LUNs -- --iSCSI is a popular protocol used to access SCSI devices across a computer --network. -- --There are two different ways iSCSI devices can be used by QEMU. -- --The first method is to mount the iSCSI LUN on the host, and make it appear as --any other ordinary SCSI device on the host and then to access this device as a --/dev/sd device from QEMU. How to do this differs between host OSes. -- --The second method involves using the iSCSI initiator that is built into --QEMU. This provides a mechanism that works the same way regardless of which --host OS you are running QEMU on. This section will describe this second method --of using iSCSI together with QEMU. -- --In QEMU, iSCSI devices are described using special iSCSI URLs -- --@example --URL syntax: --iscsi://[[%]@@][:]// --@end example -- --Username and password are optional and only used if your target is set up --using CHAP authentication for access control. --Alternatively the username and password can also be set via environment --variables to have these not show up in the process list -- --@example --export LIBISCSI_CHAP_USERNAME= --export LIBISCSI_CHAP_PASSWORD= --iscsi://// --@end example -- --Various session related parameters can be set via special options, either --in a configuration file provided via '-readconfig' or directly on the --command line. -- --If the initiator-name is not specified qemu-kvm will use a default name --of 'iqn.2008-11.org.linux-kvm[:'] where is the UUID of the --virtual machine. If the UUID is not specified qemu will use --'iqn.2008-11.org.linux-kvm[:'] where is the name of the --virtual machine. -- --@example --Setting a specific initiator name to use when logging in to the target ---iscsi initiator-name=iqn.qemu.test:my-initiator --@end example -- --@example --Controlling which type of header digest to negotiate with the target ---iscsi header-digest=CRC32C|CRC32C-NONE|NONE-CRC32C|NONE --@end example -- --These can also be set via a configuration file --@example --[iscsi] -- user = "CHAP username" -- password = "CHAP password" -- initiator-name = "iqn.qemu.test:my-initiator" -- # header digest is one of CRC32C|CRC32C-NONE|NONE-CRC32C|NONE -- header-digest = "CRC32C" --@end example -- -- --Setting the target name allows different options for different targets --@example --[iscsi "iqn.target.name"] -- user = "CHAP username" -- password = "CHAP password" -- initiator-name = "iqn.qemu.test:my-initiator" -- # header digest is one of CRC32C|CRC32C-NONE|NONE-CRC32C|NONE -- header-digest = "CRC32C" --@end example -- -- --Howto use a configuration file to set iSCSI configuration options: --@example --cat >iscsi.conf < +Date: Wed, 18 Jul 2018 22:55:05 +0200 +Subject: [PATCH 80/89] docs/interop: add nbd.txt + +RH-Author: John Snow +Message-id: <20180718225511.14878-30-jsnow@redhat.com> +Patchwork-id: 81416 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 29/35] docs/interop: add nbd.txt +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Vladimir Sementsov-Ogievskiy + +Describe new metadata namespace: "qemu". + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20180609151758.17343-7-vsementsov@virtuozzo.com> +Reviewed-by: Eric Blake +[eblake: grammar tweaks] +Signed-off-by: Eric Blake +(cherry picked from commit 3229a835a3c574a8ebc605e007785c4e01c61623) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + MAINTAINERS | 1 + + docs/interop/nbd.txt | 38 ++++++++++++++++++++++++++++++++++++++ + 2 files changed, 39 insertions(+) + create mode 100644 docs/interop/nbd.txt + +diff --git a/MAINTAINERS b/MAINTAINERS +index a783c92..53d5216 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -1927,6 +1927,7 @@ F: nbd/ + F: include/block/nbd* + F: qemu-nbd.* + F: blockdev-nbd.c ++F: docs/interop/nbd.txt + T: git git://repo.or.cz/qemu/ericb.git nbd + + NFS +diff --git a/docs/interop/nbd.txt b/docs/interop/nbd.txt +new file mode 100644 +index 0000000..77b5f45 +--- /dev/null ++++ b/docs/interop/nbd.txt +@@ -0,0 +1,38 @@ ++Qemu supports the NBD protocol, and has an internal NBD client (see ++block/nbd.c), an internal NBD server (see blockdev-nbd.c), and an ++external NBD server tool (see qemu-nbd.c). The common code is placed ++in nbd/*. ++ ++The NBD protocol is specified here: ++https://github.com/NetworkBlockDevice/nbd/blob/master/doc/proto.md ++ ++The following paragraphs describe some specific properties of NBD ++protocol realization in Qemu. ++ ++= Metadata namespaces = ++ ++Qemu supports the "base:allocation" metadata context as defined in the ++NBD protocol specification, and also defines an additional metadata ++namespace "qemu". ++ ++ ++== "qemu" namespace == ++ ++The "qemu" namespace currently contains only one type of context, ++related to exposing the contents of a dirty bitmap alongside the ++associated disk contents. That context has the following form: ++ ++ qemu:dirty-bitmap: ++ ++Each dirty-bitmap metadata context defines only one flag for extents ++in reply for NBD_CMD_BLOCK_STATUS: ++ ++ bit 0: NBD_STATE_DIRTY, means that the extent is "dirty" ++ ++For NBD_OPT_LIST_META_CONTEXT the following queries are supported ++in addition to "qemu:dirty-bitmap:": ++ ++* "qemu:" - returns list of all available metadata contexts in the ++ namespace. ++* "qemu:dirty-bitmap:" - returns list of all available dirty-bitmap ++ metadata contexts. +-- +1.8.3.1 + diff --git a/SOURCES/kvm-dump-add-guest-ELF-note.patch b/SOURCES/kvm-dump-add-guest-ELF-note.patch deleted file mode 100644 index 514604a..0000000 --- a/SOURCES/kvm-dump-add-guest-ELF-note.patch +++ /dev/null @@ -1,223 +0,0 @@ -From 93d31dbfbf412b8a80d364aac0ff6f5f319e831c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Mon, 27 Nov 2017 22:51:06 +0100 -Subject: [PATCH 08/21] dump: add guest ELF note -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Marc-André Lureau -Message-id: <20171127225111.24518-5-marcandre.lureau@redhat.com> -Patchwork-id: 77925 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 4/9] dump: add guest ELF note -Bugzilla: 1398633 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Andrew Jones -RH-Acked-by: Miroslav Rezanina - -Read the guest ELF PT_NOTE from guest memory when fw_cfg -etc/vmcoreinfo entry provides the location, and write it as an -additional note in the dump. - -Signed-off-by: Marc-André Lureau -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin - -(cherry picked from commit 903ef7349699dcd932b5981b85c1f1ebe4a4bf2a) -Signed-off-by: Marc-André Lureau -Signed-off-by: Miroslav Rezanina ---- - dump.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++ - include/sysemu/dump.h | 2 + - 2 files changed, 109 insertions(+) - -diff --git a/dump.c b/dump.c -index 99117ba..a4f175d 100644 ---- a/dump.c -+++ b/dump.c -@@ -26,6 +26,8 @@ - #include "qapi/qmp/qerror.h" - #include "qmp-commands.h" - #include "qapi-event.h" -+#include "qemu/error-report.h" -+#include "hw/misc/vmcoreinfo.h" - - #include - #ifdef CONFIG_LZO -@@ -38,6 +40,13 @@ - #define ELF_MACHINE_UNAME "Unknown" - #endif - -+#define MAX_GUEST_NOTE_SIZE (1 << 20) /* 1MB should be enough */ -+ -+#define ELF_NOTE_SIZE(hdr_size, name_size, desc_size) \ -+ ((DIV_ROUND_UP((hdr_size), 4) + \ -+ DIV_ROUND_UP((name_size), 4) + \ -+ DIV_ROUND_UP((desc_size), 4)) * 4) -+ - uint16_t cpu_to_dump16(DumpState *s, uint16_t val) - { - if (s->dump_info.d_endian == ELFDATA2LSB) { -@@ -76,6 +85,8 @@ static int dump_cleanup(DumpState *s) - guest_phys_blocks_free(&s->guest_phys_blocks); - memory_mapping_list_free(&s->list); - close(s->fd); -+ g_free(s->guest_note); -+ s->guest_note = NULL; - if (s->resume) { - if (s->detached) { - qemu_mutex_lock_iothread(); -@@ -235,6 +246,19 @@ static inline int cpu_index(CPUState *cpu) - return cpu->cpu_index + 1; - } - -+static void write_guest_note(WriteCoreDumpFunction f, DumpState *s, -+ Error **errp) -+{ -+ int ret; -+ -+ if (s->guest_note) { -+ ret = f(s->guest_note, s->guest_note_size, s); -+ if (ret < 0) { -+ error_setg(errp, "dump: failed to write guest note"); -+ } -+ } -+} -+ - static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s, - Error **errp) - { -@@ -258,6 +282,8 @@ static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s, - return; - } - } -+ -+ write_guest_note(f, s, errp); - } - - static void write_elf32_note(DumpState *s, Error **errp) -@@ -303,6 +329,8 @@ static void write_elf32_notes(WriteCoreDumpFunction f, DumpState *s, - return; - } - } -+ -+ write_guest_note(f, s, errp); - } - - static void write_elf_section(DumpState *s, int type, Error **errp) -@@ -714,6 +742,44 @@ static int buf_write_note(const void *buf, size_t size, void *opaque) - return 0; - } - -+/* -+ * This function retrieves various sizes from an elf header. -+ * -+ * @note has to be a valid ELF note. The return sizes are unmodified -+ * (not padded or rounded up to be multiple of 4). -+ */ -+static void get_note_sizes(DumpState *s, const void *note, -+ uint64_t *note_head_size, -+ uint64_t *name_size, -+ uint64_t *desc_size) -+{ -+ uint64_t note_head_sz; -+ uint64_t name_sz; -+ uint64_t desc_sz; -+ -+ if (s->dump_info.d_class == ELFCLASS64) { -+ const Elf64_Nhdr *hdr = note; -+ note_head_sz = sizeof(Elf64_Nhdr); -+ name_sz = tswap64(hdr->n_namesz); -+ desc_sz = tswap64(hdr->n_descsz); -+ } else { -+ const Elf32_Nhdr *hdr = note; -+ note_head_sz = sizeof(Elf32_Nhdr); -+ name_sz = tswap32(hdr->n_namesz); -+ desc_sz = tswap32(hdr->n_descsz); -+ } -+ -+ if (note_head_size) { -+ *note_head_size = note_head_sz; -+ } -+ if (name_size) { -+ *name_size = name_sz; -+ } -+ if (desc_size) { -+ *desc_size = desc_sz; -+ } -+} -+ - /* write common header, sub header and elf note to vmcore */ - static void create_header32(DumpState *s, Error **errp) - { -@@ -1492,6 +1558,7 @@ static void dump_init(DumpState *s, int fd, bool has_format, - DumpGuestMemoryFormat format, bool paging, bool has_filter, - int64_t begin, int64_t length, Error **errp) - { -+ VMCoreInfoState *vmci = vmcoreinfo_find(); - CPUState *cpu; - int nr_cpus; - Error *err = NULL; -@@ -1569,6 +1636,46 @@ static void dump_init(DumpState *s, int fd, bool has_format, - goto cleanup; - } - -+ /* -+ * The goal of this block is to copy the guest note out of -+ * the guest. Failure to do so is not fatal for dumping. -+ */ -+ if (vmci) { -+ uint64_t addr, note_head_size, name_size, desc_size; -+ uint32_t size; -+ uint16_t format; -+ -+ note_head_size = s->dump_info.d_class == ELFCLASS32 ? -+ sizeof(Elf32_Nhdr) : sizeof(Elf64_Nhdr); -+ -+ format = le16_to_cpu(vmci->vmcoreinfo.guest_format); -+ size = le32_to_cpu(vmci->vmcoreinfo.size); -+ addr = le64_to_cpu(vmci->vmcoreinfo.paddr); -+ if (!vmci->has_vmcoreinfo) { -+ warn_report("guest note is not present"); -+ } else if (size < note_head_size || size > MAX_GUEST_NOTE_SIZE) { -+ warn_report("guest note size is invalid: %" PRIu32, size); -+ } else if (format != VMCOREINFO_FORMAT_ELF) { -+ warn_report("guest note format is unsupported: %" PRIu16, format); -+ } else { -+ s->guest_note = g_malloc(size + 1); /* +1 for adding \0 */ -+ cpu_physical_memory_read(addr, s->guest_note, size); -+ -+ get_note_sizes(s, s->guest_note, NULL, &name_size, &desc_size); -+ s->guest_note_size = ELF_NOTE_SIZE(note_head_size, name_size, -+ desc_size); -+ if (name_size > MAX_GUEST_NOTE_SIZE || -+ desc_size > MAX_GUEST_NOTE_SIZE || -+ s->guest_note_size > size) { -+ warn_report("Invalid guest note header"); -+ g_free(s->guest_note); -+ s->guest_note = NULL; -+ } else { -+ s->note_size += s->guest_note_size; -+ } -+ } -+ } -+ - /* get memory mapping */ - if (paging) { - qemu_get_guest_memory_mapping(&s->list, &s->guest_phys_blocks, &err); -diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h -index 2672a15..df43bd0 100644 ---- a/include/sysemu/dump.h -+++ b/include/sysemu/dump.h -@@ -192,6 +192,8 @@ typedef struct DumpState { - * this could be used to calculate - * how much work we have - * finished. */ -+ uint8_t *guest_note; /* ELF note content */ -+ size_t guest_note_size; - } DumpState; - - uint16_t cpu_to_dump16(DumpState *s, uint16_t val); --- -1.8.3.1 - diff --git a/SOURCES/kvm-dump-guest-memory.py-fix-No-symbol-vmcoreinfo_find.patch b/SOURCES/kvm-dump-guest-memory.py-fix-No-symbol-vmcoreinfo_find.patch deleted file mode 100644 index 4e2986e..0000000 --- a/SOURCES/kvm-dump-guest-memory.py-fix-No-symbol-vmcoreinfo_find.patch +++ /dev/null @@ -1,65 +0,0 @@ -From af7952afccf368763122322931a603bfd4443471 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Tue, 5 Dec 2017 14:29:30 +0100 -Subject: [PATCH 18/21] dump-guest-memory.py: fix No symbol "vmcoreinfo_find" -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Marc-André Lureau -Message-id: <20171205142930.5499-1-marcandre.lureau@redhat.com> -Patchwork-id: 78143 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH] dump-guest-memory.py: fix No symbol "vmcoreinfo_find" -Bugzilla: 1398633 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Michael S. Tsirkin -RH-Acked-by: Laurent Vivier - -When qemu is compiled without debug, the dump gdb python script can fail with: - -Error occurred in Python command: No symbol "vmcoreinfo_find" in current context. - -Because vmcoreinfo_find() is inlined and not exported. - -Use the underlying object_resolve_path_type() to get the instance instead. - -Signed-off-by: Marc-André Lureau -Reviewed-by: Laszlo Ersek -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin - -(cherry picked from commit d36d0a9d152316a41e02c2613a71f5859f407da1) -Signed-off-by: Marc-André Lureau -Signed-off-by: Miroslav Rezanina ---- - scripts/dump-guest-memory.py | 12 +++++++----- - 1 file changed, 7 insertions(+), 5 deletions(-) - -diff --git a/scripts/dump-guest-memory.py b/scripts/dump-guest-memory.py -index 69dd5ef..1af26c1 100644 ---- a/scripts/dump-guest-memory.py -+++ b/scripts/dump-guest-memory.py -@@ -546,13 +546,15 @@ shape and this command should mostly work.""" - return None - - def add_vmcoreinfo(self): -- if not gdb.parse_and_eval("vmcoreinfo_find()") \ -- or not gdb.parse_and_eval("vmcoreinfo_find()->has_vmcoreinfo"): -+ vmci = '(VMCoreInfoState *)' + \ -+ 'object_resolve_path_type("", "vmcoreinfo", 0)' -+ if not gdb.parse_and_eval("%s" % vmci) \ -+ or not gdb.parse_and_eval("(%s)->has_vmcoreinfo" % vmci): - return - -- fmt = gdb.parse_and_eval("vmcoreinfo_find()->vmcoreinfo.guest_format") -- addr = gdb.parse_and_eval("vmcoreinfo_find()->vmcoreinfo.paddr") -- size = gdb.parse_and_eval("vmcoreinfo_find()->vmcoreinfo.size") -+ fmt = gdb.parse_and_eval("(%s)->vmcoreinfo.guest_format" % vmci) -+ addr = gdb.parse_and_eval("(%s)->vmcoreinfo.paddr" % vmci) -+ size = gdb.parse_and_eval("(%s)->vmcoreinfo.size" % vmci) - - fmt = le16_to_cpu(fmt) - addr = le64_to_cpu(addr) --- -1.8.3.1 - diff --git a/SOURCES/kvm-dump-guest-memory.py-fix-You-can-t-do-that-without-a.patch b/SOURCES/kvm-dump-guest-memory.py-fix-You-can-t-do-that-without-a.patch deleted file mode 100644 index 6a5dbab..0000000 --- a/SOURCES/kvm-dump-guest-memory.py-fix-You-can-t-do-that-without-a.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 6a2b7d555d46c05b0ca334f8fd6511e134e3220c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Tue, 9 Jan 2018 12:52:04 +0100 -Subject: [PATCH 04/12] dump-guest-memory.py: fix "You can't do that without a - process to debug" -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Marc-André Lureau -Message-id: <20180109125204.4313-1-marcandre.lureau@redhat.com> -Patchwork-id: 78534 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH] dump-guest-memory.py: fix "You can't do that without a process to debug" -Bugzilla: 1398633 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: John Snow -RH-Acked-by: Miroslav Rezanina - -If the script is run with a core (no running process), it produces an -error: - -(gdb) dump-guest-memory /tmp/vmcore X86_64 -guest RAM blocks: -target_start target_end host_addr message count ----------------- ---------------- ---------------- ------- ----- -0000000000000000 00000000000a0000 00007f7935800000 added 1 -00000000000a0000 00000000000b0000 00007f7934200000 added 2 -00000000000c0000 00000000000ca000 00007f79358c0000 added 3 -00000000000ca000 00000000000cd000 00007f79358ca000 joined 3 -00000000000cd000 00000000000e8000 00007f79358cd000 joined 3 -00000000000e8000 00000000000f0000 00007f79358e8000 joined 3 -00000000000f0000 0000000000100000 00007f79358f0000 joined 3 -0000000000100000 0000000080000000 00007f7935900000 joined 3 -00000000fd000000 00000000fe000000 00007f7934200000 added 4 -00000000fffc0000 0000000100000000 00007f7935600000 added 5 -Python Exception You can't do that without a process to debug.: -Error occurred in Python command: You can't do that without a process -to debug. - -Replace the object_resolve_path_type() function call with a local -volatile variable. - -Signed-off-by: Marc-André Lureau -Reviewed-by: Laszlo Ersek - -(cherry picked from commit c3b1642b9b6b3ba4314d6be3be509d396372cfd5) - -Signed-off-by: Marc-André Lureau -Signed-off-by: Miroslav Rezanina ---- - hw/misc/vmcoreinfo.c | 3 +++ - scripts/dump-guest-memory.py | 3 +-- - 2 files changed, 4 insertions(+), 2 deletions(-) - -diff --git a/hw/misc/vmcoreinfo.c b/hw/misc/vmcoreinfo.c -index 31db57a..a280552 100644 ---- a/hw/misc/vmcoreinfo.c -+++ b/hw/misc/vmcoreinfo.c -@@ -35,6 +35,8 @@ static void vmcoreinfo_realize(DeviceState *dev, Error **errp) - { - VMCoreInfoState *s = VMCOREINFO(dev); - FWCfgState *fw_cfg = fw_cfg_find(); -+ /* for gdb script dump-guest-memory.py */ -+ static VMCoreInfoState * volatile vmcoreinfo_state G_GNUC_UNUSED; - - /* Given that this function is executing, there is at least one VMCOREINFO - * device. Check if there are several. -@@ -56,6 +58,7 @@ static void vmcoreinfo_realize(DeviceState *dev, Error **errp) - &s->vmcoreinfo, sizeof(s->vmcoreinfo), false); - - qemu_register_reset(vmcoreinfo_reset, dev); -+ vmcoreinfo_state = s; - } - - static const VMStateDescription vmstate_vmcoreinfo = { -diff --git a/scripts/dump-guest-memory.py b/scripts/dump-guest-memory.py -index 1af26c1..09bec92 100644 ---- a/scripts/dump-guest-memory.py -+++ b/scripts/dump-guest-memory.py -@@ -546,8 +546,7 @@ shape and this command should mostly work.""" - return None - - def add_vmcoreinfo(self): -- vmci = '(VMCoreInfoState *)' + \ -- 'object_resolve_path_type("", "vmcoreinfo", 0)' -+ vmci = 'vmcoreinfo_realize::vmcoreinfo_state' - if not gdb.parse_and_eval("%s" % vmci) \ - or not gdb.parse_and_eval("(%s)->has_vmcoreinfo" % vmci): - return --- -1.8.3.1 - diff --git a/SOURCES/kvm-dump-guest-memory.py-fix-python-2-support.patch b/SOURCES/kvm-dump-guest-memory.py-fix-python-2-support.patch deleted file mode 100644 index b764e55..0000000 --- a/SOURCES/kvm-dump-guest-memory.py-fix-python-2-support.patch +++ /dev/null @@ -1,58 +0,0 @@ -From f342adbebaff74bae55e4ebb681683d951ba61a2 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Mon, 22 Jan 2018 13:51:41 +0100 -Subject: [PATCH 20/21] dump-guest-memory.py: fix python 2 support -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Marc-André Lureau -Message-id: <20180122135141.11068-1-marcandre.lureau@redhat.com> -Patchwork-id: 78691 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH] dump-guest-memory.py: fix python 2 support -Bugzilla: 1398633 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Michael S. Tsirkin -RH-Acked-by: Miroslav Rezanina - -Python GDB support may use Python 2 or 3. - -Inferior.read_memory() may return a 'buffer' with Python 2 or a -'memoryview' with Python 3 (see also -https://sourceware.org/gdb/onlinedocs/gdb/Inferiors-In-Python.html) - -The elf.add_vmcoreinfo_note() method expects a "bytes" object. Wrap -the returned memory with bytes(), which works with both 'memoryview' -and 'buffer'. - -Fixes a regression introduced with commit -d23bfa91b7789534d16ede6cb7d925bfac3f3c4c ("add vmcoreinfo"). - -Suggested-by: Peter Maydell -Signed-off-by: Marc-André Lureau -Acked-by: Laszlo Ersek -Reviewed-by: Eric Blake - -(cherry picked from commit 6f49ec4034e55dfb675a56a62c9579384f7fb8cc) -Signed-off-by: Marc-André Lureau -Signed-off-by: Miroslav Rezanina ---- - scripts/dump-guest-memory.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/scripts/dump-guest-memory.py b/scripts/dump-guest-memory.py -index 09bec92..03fbf69 100644 ---- a/scripts/dump-guest-memory.py -+++ b/scripts/dump-guest-memory.py -@@ -564,7 +564,7 @@ shape and this command should mostly work.""" - - vmcoreinfo = self.phys_memory_read(addr, size) - if vmcoreinfo: -- self.elf.add_vmcoreinfo_note(vmcoreinfo.tobytes()) -+ self.elf.add_vmcoreinfo_note(bytes(vmcoreinfo)) - - def invoke(self, args, from_tty): - """Handles command invocation from gdb.""" --- -1.8.3.1 - diff --git a/SOURCES/kvm-dump-guest-memory.py-skip-vmcoreinfo-section-if-not-.patch b/SOURCES/kvm-dump-guest-memory.py-skip-vmcoreinfo-section-if-not-.patch deleted file mode 100644 index fda8f30..0000000 --- a/SOURCES/kvm-dump-guest-memory.py-skip-vmcoreinfo-section-if-not-.patch +++ /dev/null @@ -1,60 +0,0 @@ -From cfa9ef75d5a2e814368940c0b6e70981bd082169 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Mon, 5 Feb 2018 16:38:47 +0100 -Subject: [PATCH 19/20] dump-guest-memory.py: skip vmcoreinfo section if not - available -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Marc-André Lureau -Message-id: <20180205163847.12004-1-marcandre.lureau@redhat.com> -Patchwork-id: 78897 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH] dump-guest-memory.py: skip vmcoreinfo section if not available -Bugzilla: 1398633 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier - -On some architectures, qemu doesn't support vmcoreinfo device, -and dump-guest-memory fails: - -(gdb) dump-guest-memory /tmp/vmcore ppc64-le -guest RAM blocks: -target_start target_end host_addr message count ----------------- ---------------- ---------------- ------- ----- -0000000000000000 0000000200000000 00003ffd86980000 added 1 -0000200080000000 0000200080800000 00003ffd86170000 added 2 -Python Exception No symbol "vmcoreinfo_realize" in current context.: -Error occurred in Python command: No symbol "vmcoreinfo_realize" in current context. - -Check that vmcoreinfo_realize symbol exists before evaluating an -expression with it. - -Signed-off-by: Marc-André Lureau -Reviewed-by: Laszlo Ersek - -(cherry picked from commit ce6b9e421a9ab45d7e6c97af092a07c049954444) - -Signed-off-by: Marc-André Lureau -Signed-off-by: Miroslav Rezanina ---- - scripts/dump-guest-memory.py | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/scripts/dump-guest-memory.py b/scripts/dump-guest-memory.py -index 03fbf69..51acfcd 100644 ---- a/scripts/dump-guest-memory.py -+++ b/scripts/dump-guest-memory.py -@@ -546,6 +546,8 @@ shape and this command should mostly work.""" - return None - - def add_vmcoreinfo(self): -+ if gdb.lookup_symbol("vmcoreinfo_realize")[0] is None: -+ return - vmci = 'vmcoreinfo_realize::vmcoreinfo_state' - if not gdb.parse_and_eval("%s" % vmci) \ - or not gdb.parse_and_eval("(%s)->has_vmcoreinfo" % vmci): --- -1.8.3.1 - diff --git a/SOURCES/kvm-dump-update-phys_base-header-field-based-on-VMCOREIN.patch b/SOURCES/kvm-dump-update-phys_base-header-field-based-on-VMCOREIN.patch deleted file mode 100644 index 62c2a6e..0000000 --- a/SOURCES/kvm-dump-update-phys_base-header-field-based-on-VMCOREIN.patch +++ /dev/null @@ -1,139 +0,0 @@ -From a1b9c54811a4fc6797259dae98548229dba53d76 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Mon, 27 Nov 2017 22:51:07 +0100 -Subject: [PATCH 09/21] dump: update phys_base header field based on VMCOREINFO - content -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Marc-André Lureau -Message-id: <20171127225111.24518-6-marcandre.lureau@redhat.com> -Patchwork-id: 77928 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 5/9] dump: update phys_base header field based on VMCOREINFO content -Bugzilla: 1398633 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Andrew Jones -RH-Acked-by: Miroslav Rezanina - -If the guest note is VMCOREINFO, try to get phys_base from it. - -Signed-off-by: Marc-André Lureau -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin - -(cherry picked from commit d9feb51772b4ade9700c7fa54529327a6c8183a7) -Signed-off-by: Marc-André Lureau -Signed-off-by: Miroslav Rezanina ---- - docs/specs/vmcoreinfo.txt | 8 +++++++ - dump.c | 56 +++++++++++++++++++++++++++++++++++++++++++++-- - 2 files changed, 62 insertions(+), 2 deletions(-) - -diff --git a/docs/specs/vmcoreinfo.txt b/docs/specs/vmcoreinfo.txt -index 2868a77..8212610 100644 ---- a/docs/specs/vmcoreinfo.txt -+++ b/docs/specs/vmcoreinfo.txt -@@ -39,3 +39,11 @@ qemu dumps. - - The note format/class must be of the target bitness and the size must - be less than 1Mb. -+ -+If the ELF note name is "VMCOREINFO", it is expected to be the Linux -+vmcoreinfo note (see Documentation/ABI/testing/sysfs-kernel-vmcoreinfo -+in Linux source). In this case, qemu dump code will read the content -+as a key=value text file, looking for "NUMBER(phys_base)" key -+value. The value is expected to be more accurate than architecture -+guess of the value. This is useful for KASLR-enabled guest with -+ancient tools not handling the VMCOREINFO note. -diff --git a/dump.c b/dump.c -index a4f175d..e3175d7 100644 ---- a/dump.c -+++ b/dump.c -@@ -780,6 +780,23 @@ static void get_note_sizes(DumpState *s, const void *note, - } - } - -+static bool note_name_equal(DumpState *s, -+ const uint8_t *note, const char *name) -+{ -+ int len = strlen(name) + 1; -+ uint64_t head_size, name_size; -+ -+ get_note_sizes(s, note, &head_size, &name_size, NULL); -+ head_size = ROUND_UP(head_size, 4); -+ -+ if (name_size != len || -+ memcmp(note + head_size, "VMCOREINFO", len)) { -+ return false; -+ } -+ -+ return true; -+} -+ - /* write common header, sub header and elf note to vmcore */ - static void create_header32(DumpState *s, Error **errp) - { -@@ -1554,6 +1571,39 @@ static int64_t dump_calculate_size(DumpState *s) - return total; - } - -+static void vmcoreinfo_update_phys_base(DumpState *s) -+{ -+ uint64_t size, note_head_size, name_size, phys_base; -+ char **lines; -+ uint8_t *vmci; -+ size_t i; -+ -+ if (!note_name_equal(s, s->guest_note, "VMCOREINFO")) { -+ return; -+ } -+ -+ get_note_sizes(s, s->guest_note, ¬e_head_size, &name_size, &size); -+ note_head_size = ROUND_UP(note_head_size, 4); -+ -+ vmci = s->guest_note + note_head_size + ROUND_UP(name_size, 4); -+ *(vmci + size) = '\0'; -+ -+ lines = g_strsplit((char *)vmci, "\n", -1); -+ for (i = 0; lines[i]; i++) { -+ if (g_str_has_prefix(lines[i], "NUMBER(phys_base)=")) { -+ if (qemu_strtou64(lines[i] + 18, NULL, 16, -+ &phys_base) < 0) { -+ warn_report("Failed to read NUMBER(phys_base)="); -+ } else { -+ s->dump_info.phys_base = phys_base; -+ } -+ break; -+ } -+ } -+ -+ g_strfreev(lines); -+} -+ - static void dump_init(DumpState *s, int fd, bool has_format, - DumpGuestMemoryFormat format, bool paging, bool has_filter, - int64_t begin, int64_t length, Error **errp) -@@ -1637,8 +1687,9 @@ static void dump_init(DumpState *s, int fd, bool has_format, - } - - /* -- * The goal of this block is to copy the guest note out of -- * the guest. Failure to do so is not fatal for dumping. -+ * The goal of this block is to (a) update the previously guessed -+ * phys_base, (b) copy the guest note out of the guest. -+ * Failure to do so is not fatal for dumping. - */ - if (vmci) { - uint64_t addr, note_head_size, name_size, desc_size; -@@ -1671,6 +1722,7 @@ static void dump_init(DumpState *s, int fd, bool has_format, - g_free(s->guest_note); - s->guest_note = NULL; - } else { -+ vmcoreinfo_update_phys_base(s); - s->note_size += s->guest_note_size; - } - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-e1000-Fix-tso_props-compat-for-82540em.patch b/SOURCES/kvm-e1000-Fix-tso_props-compat-for-82540em.patch new file mode 100644 index 0000000..0e96447 --- /dev/null +++ b/SOURCES/kvm-e1000-Fix-tso_props-compat-for-82540em.patch @@ -0,0 +1,47 @@ +From bddd766e9d3109a4dfd6f099edf8f5870a24bbf1 Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Thu, 26 Jul 2018 16:40:11 +0200 +Subject: [PATCH 11/15] e1000: Fix tso_props compat for 82540em + +RH-Author: Dr. David Alan Gilbert +Message-id: <20180726164011.21660-2-dgilbert@redhat.com> +Patchwork-id: 81522 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v2 1/1] e1000: Fix tso_props compat for 82540em +Bugzilla: 1608778 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Eduardo Habkost +RH-Acked-by: Juan Quintela +RH-Acked-by: Xiao Wang + +From: "Dr. David Alan Gilbert" + +In RHEL when you ask for an e1000-82540em that's the device you get, +however in upstream it's aliased to an e1000. +Because of the difference, we need to change the compat entry +for migrate_tso_props to the base type that changes e1000 as well. + +Signed-off-by: Dr. David Alan Gilbert +Signed-off-by: Miroslav Rezanina +--- + include/hw/compat.h | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/include/hw/compat.h b/include/hw/compat.h +index 5802e61..5804853 100644 +--- a/include/hw/compat.h ++++ b/include/hw/compat.h +@@ -464,8 +464,9 @@ + .driver = "vhost-user-blk-pci",\ + .property = "vectors",\ + .value = "2",\ +- },{ /* HW_COMPAT_RHEL7_5 from HW_COMPAT_2_11 */ \ +- .driver = "e1000",\ ++ },{ /* HW_COMPAT_RHEL7_5 from HW_COMPAT_2_11 but \ ++ bz 1608778 modified for our naming */ \ ++ .driver = "e1000-82540em",\ + .property = "migrate_tso_props",\ + .value = "off",\ + },{ /* HW_COMPAT_RHEL7_5 from HW_COMPAT_2_10 */ \ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-e1000e-Do-not-auto-clear-ICR-bits-which-aren-t-set-i.patch b/SOURCES/kvm-e1000e-Do-not-auto-clear-ICR-bits-which-aren-t-set-i.patch new file mode 100644 index 0000000..29fb7d2 --- /dev/null +++ b/SOURCES/kvm-e1000e-Do-not-auto-clear-ICR-bits-which-aren-t-set-i.patch @@ -0,0 +1,49 @@ +From d77dfec42fe78f5010780dadd10d7e20e0877867 Mon Sep 17 00:00:00 2001 +From: Xiao Wang +Date: Thu, 16 Aug 2018 06:09:02 +0200 +Subject: [PATCH 1/5] e1000e: Do not auto-clear ICR bits which aren't set in + EIAC + +RH-Author: Xiao Wang +Message-id: <1534399743-23973-2-git-send-email-jasowang@redhat.com> +Patchwork-id: 81850 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/2] e1000e: Do not auto-clear ICR bits which aren't set in EIAC +Bugzilla: 1596010 +RH-Acked-by: wexu@redhat.com +RH-Acked-by: Thomas Huth +RH-Acked-by: Paolo Bonzini + +From: Jan Kiszka + +The spec does not justify clearing of any E1000_ICR_OTHER_CAUSES when +E1000_ICR_OTHER is set in EIAC. In fact, removing this code fixes the +issue the Linux driver runs into since 4aea7a5c5e94 ("e1000e: Avoid +receiver overrun interrupt bursts") and was worked around by +745d0bd3af99 ("e1000e: Remove Other from EIAC"). + +Signed-off-by: Jan Kiszka +Signed-off-by: Jason Wang +(cherry picked from commit 2285a00c113469bb3e750ca4921cdb7baaae9e25) +Signed-off-by: Miroslav Rezanina +--- + hw/net/e1000e_core.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c +index c93c466..9504891 100644 +--- a/hw/net/e1000e_core.c ++++ b/hw/net/e1000e_core.c +@@ -2022,10 +2022,6 @@ e1000e_msix_notify_one(E1000ECore *core, uint32_t cause, uint32_t int_cfg) + + effective_eiac = core->mac[EIAC] & cause; + +- if (effective_eiac == E1000_ICR_OTHER) { +- effective_eiac |= E1000_ICR_OTHER_CAUSES; +- } +- + core->mac[ICR] &= ~effective_eiac; + + if (!(core->mac[CTRL_EXT] & E1000_CTRL_EXT_IAME)) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-e1000e-Prevent-MSI-MSI-X-storms.patch b/SOURCES/kvm-e1000e-Prevent-MSI-MSI-X-storms.patch new file mode 100644 index 0000000..b71c846 --- /dev/null +++ b/SOURCES/kvm-e1000e-Prevent-MSI-MSI-X-storms.patch @@ -0,0 +1,85 @@ +From 77782045cff9546feaf8863c0e7552343a488c6e Mon Sep 17 00:00:00 2001 +From: Xiao Wang +Date: Thu, 16 Aug 2018 06:09:03 +0200 +Subject: [PATCH 2/5] e1000e: Prevent MSI/MSI-X storms + +RH-Author: Xiao Wang +Message-id: <1534399743-23973-3-git-send-email-jasowang@redhat.com> +Patchwork-id: 81849 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 2/2] e1000e: Prevent MSI/MSI-X storms +Bugzilla: 1596010 +RH-Acked-by: wexu@redhat.com +RH-Acked-by: Thomas Huth +RH-Acked-by: Paolo Bonzini + +From: Jan Kiszka + +Only signal MSI/MSI-X events on rising edges. So far we re-triggered the +interrupt sources even if the guest did no consumed the pending one, +easily causing interrupt storms. + +Issue was observable with Linux 4.16 e1000e driver when MSI-X was used. +Vector 2 was causing interrupt storms after the driver activated the +device. + +Signed-off-by: Jan Kiszka +Signed-off-by: Jason Wang +(cherry picked from commit 4712c158c5276fd3c401152f4bb5c3fccf185946) +Signed-off-by: Miroslav Rezanina +--- + hw/net/e1000e_core.c | 11 +++++++++++ + hw/net/e1000e_core.h | 2 ++ + 2 files changed, 13 insertions(+) + +diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c +index 9504891..2a221c2 100644 +--- a/hw/net/e1000e_core.c ++++ b/hw/net/e1000e_core.c +@@ -2023,6 +2023,7 @@ e1000e_msix_notify_one(E1000ECore *core, uint32_t cause, uint32_t int_cfg) + effective_eiac = core->mac[EIAC] & cause; + + core->mac[ICR] &= ~effective_eiac; ++ core->msi_causes_pending &= ~effective_eiac; + + if (!(core->mac[CTRL_EXT] & E1000_CTRL_EXT_IAME)) { + core->mac[IMS] &= ~effective_eiac; +@@ -2119,6 +2120,13 @@ e1000e_send_msi(E1000ECore *core, bool msix) + { + uint32_t causes = core->mac[ICR] & core->mac[IMS] & ~E1000_ICR_ASSERTED; + ++ core->msi_causes_pending &= causes; ++ causes ^= core->msi_causes_pending; ++ if (causes == 0) { ++ return; ++ } ++ core->msi_causes_pending |= causes; ++ + if (msix) { + e1000e_msix_notify(core, causes); + } else { +@@ -2156,6 +2164,9 @@ e1000e_update_interrupt_state(E1000ECore *core) + core->mac[ICS] = core->mac[ICR]; + + interrupts_pending = (core->mac[IMS] & core->mac[ICR]) ? true : false; ++ if (!interrupts_pending) { ++ core->msi_causes_pending = 0; ++ } + + trace_e1000e_irq_pending_interrupts(core->mac[ICR] & core->mac[IMS], + core->mac[ICR], core->mac[IMS]); +diff --git a/hw/net/e1000e_core.h b/hw/net/e1000e_core.h +index 7d8ff41..63a1551 100644 +--- a/hw/net/e1000e_core.h ++++ b/hw/net/e1000e_core.h +@@ -109,6 +109,8 @@ struct E1000Core { + NICState *owner_nic; + PCIDevice *owner; + void (*owner_start_recv)(PCIDevice *d); ++ ++ uint32_t msi_causes_pending; + }; + + void +-- +1.8.3.1 + diff --git a/SOURCES/kvm-exec-Explicitly-export-target-AS-from-address_space_.patch b/SOURCES/kvm-exec-Explicitly-export-target-AS-from-address_space_.patch deleted file mode 100644 index b327a76..0000000 --- a/SOURCES/kvm-exec-Explicitly-export-target-AS-from-address_space_.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 7d5255d9aa2d1b0da0e7fae12264c7582080de63 Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Thu, 16 Nov 2017 03:07:14 +0100 -Subject: [PATCH 10/30] exec: Explicitly export target AS from - address_space_translate_internal - -RH-Author: David Gibson -Message-id: <20171116030732.8560-5-dgibson@redhat.com> -Patchwork-id: 77696 -O-Subject: [PATCH 04/22] exec: Explicitly export target AS from address_space_translate_internal -Bugzilla: 1481593 -RH-Acked-by: Thomas Huth -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Eduardo Habkost -RH-Acked-by: Laurent Vivier - -From: Alexey Kardashevskiy - -This adds an AS** parameter to address_space_do_translate() -to make it easier for the next patch to share FlatViews. - -This should cause no behavioural change. - -Signed-off-by: Alexey Kardashevskiy -Message-Id: <20170921085110.25598-2-aik@ozlabs.ru> -Signed-off-by: Paolo Bonzini -(cherry picked from commit e76bb18f7e430e0c50fb38d051feacf268bd78f4) -Signed-off-by: Miroslav Rezanina - -Conflicts: - exec.c - -Conflicts because we applied 076a93d7 "exec: simplify -address_space_get_iotlb_entry" out of order downstream. - -Signed-off-by: David Gibson ---- - exec.c | 10 ++++++---- - 1 file changed, 6 insertions(+), 4 deletions(-) - -diff --git a/exec.c b/exec.c -index ae37a60..f00bd4e 100644 ---- a/exec.c -+++ b/exec.c -@@ -478,7 +478,8 @@ static MemoryRegionSection address_space_do_translate(AddressSpace *as, - hwaddr *plen_out, - hwaddr *page_mask_out, - bool is_write, -- bool is_mmio) -+ bool is_mmio, -+ AddressSpace **target_as) - { - IOMMUTLBEntry iotlb; - MemoryRegionSection *section; -@@ -512,6 +513,7 @@ static MemoryRegionSection address_space_do_translate(AddressSpace *as, - } - - as = iotlb.target_as; -+ *target_as = iotlb.target_as; - } - - *xlat = addr; -@@ -547,7 +549,7 @@ IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr, - * but page mask. - */ - section = address_space_do_translate(as, addr, &xlat, NULL, -- &page_mask, is_write, false); -+ &page_mask, is_write, false, &as); - - /* Illegal translation */ - if (section.mr == &io_mem_unassigned) { -@@ -559,7 +561,7 @@ IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr, - section.offset_within_region; - - return (IOMMUTLBEntry) { -- .target_as = section.address_space, -+ .target_as = as, - .iova = addr & ~page_mask, - .translated_addr = xlat & ~page_mask, - .addr_mask = page_mask, -@@ -581,7 +583,7 @@ MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr, - - /* This can be MMIO, so setup MMIO bit. */ - section = address_space_do_translate(as, addr, xlat, plen, NULL, -- is_write, true); -+ is_write, true, &as); - mr = section.mr; - - if (xen_enabled() && memory_access_is_direct(mr, is_write)) { --- -1.8.3.1 - diff --git a/SOURCES/kvm-exec-add-page_mask-for-address_space_do_translate.patch b/SOURCES/kvm-exec-add-page_mask-for-address_space_do_translate.patch deleted file mode 100644 index cc3455a..0000000 --- a/SOURCES/kvm-exec-add-page_mask-for-address_space_do_translate.patch +++ /dev/null @@ -1,145 +0,0 @@ -From 59ad61373f73de6a3eb17e0c1989bc048b51b55c Mon Sep 17 00:00:00 2001 -From: Maxime Coquelin -Date: Fri, 20 Oct 2017 14:17:06 +0200 -Subject: [PATCH 04/19] exec: add page_mask for address_space_do_translate - -RH-Author: Maxime Coquelin -Message-id: <20171020141707.17637-2-maxime.coquelin@redhat.com> -Patchwork-id: 77417 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 1/2] exec: add page_mask for address_space_do_translate -Bugzilla: 1498817 -RH-Acked-by: Peter Xu -RH-Acked-by: Michael S. Tsirkin -RH-Acked-by: Jens Freimann - -From: Peter Xu - -The function is originally used for address_space_space_translate() and -what we care about most is (xlat, plen) range. However for iotlb -requests, we don't really care about "plen", but the size of the page -that "xlat" is located on. While, plen cannot really contain this -information. - -A simple example to show why "plen" is not good for IOTLB translations: - -E.g., for huge pages, it is possible that guest mapped 1G huge page on -device side that used this GPA range: - - 0x100000000 - 0x13fffffff - -Then let's say we want to translate one IOVA that finally mapped to GPA -0x13ffffe00 (which is located on this 1G huge page). Then here we'll -get: - - (xlat, plen) = (0x13fffe00, 0x200) - -So the IOTLB would be only covering a very small range since from -"plen" (which is 0x200 bytes) we cannot tell the size of the page. - -Actually we can really know that this is a huge page - we just throw the -information away in address_space_do_translate(). - -This patch introduced "page_mask" optional parameter to capture that -page mask info. Also, I made "plen" an optional parameter as well, with -some comments for the whole function. - -No functional change yet. - -Signed-off-by: Peter Xu -Signed-off-by: Maxime Coquelin -Message-Id: <20171010094247.10173-2-maxime.coquelin@redhat.com> -Signed-off-by: Paolo Bonzini -(cherry picked from commit d5e5fafd11be4458443c43f19c1ebdd24d99a751) -Signed-off-by: Maxime Coquelin -Signed-off-by: Miroslav Rezanina - -Conflicts: - exec.c (Skipping 166206845f7f) ---- - exec.c | 32 +++++++++++++++++++++++++++----- - 1 file changed, 27 insertions(+), 5 deletions(-) - -diff --git a/exec.c b/exec.c -index d20c34c..e5f97fd 100644 ---- a/exec.c -+++ b/exec.c -@@ -475,7 +475,8 @@ address_space_translate_internal(AddressSpaceDispatch *d, hwaddr addr, hwaddr *x - static MemoryRegionSection address_space_do_translate(AddressSpace *as, - hwaddr addr, - hwaddr *xlat, -- hwaddr *plen, -+ hwaddr *plen_out, -+ hwaddr *page_mask_out, - bool is_write, - bool is_mmio) - { -@@ -483,10 +484,16 @@ static MemoryRegionSection address_space_do_translate(AddressSpace *as, - MemoryRegionSection *section; - IOMMUMemoryRegion *iommu_mr; - IOMMUMemoryRegionClass *imrc; -+ hwaddr page_mask = (hwaddr)(-1); -+ hwaddr plen = (hwaddr)(-1); -+ -+ if (plen_out) { -+ plen = *plen_out; -+ } - - for (;;) { - AddressSpaceDispatch *d = atomic_rcu_read(&as->dispatch); -- section = address_space_translate_internal(d, addr, &addr, plen, is_mmio); -+ section = address_space_translate_internal(d, addr, &addr, &plen, is_mmio); - - iommu_mr = memory_region_get_iommu(section->mr); - if (!iommu_mr) { -@@ -498,7 +505,8 @@ static MemoryRegionSection address_space_do_translate(AddressSpace *as, - IOMMU_WO : IOMMU_RO); - addr = ((iotlb.translated_addr & ~iotlb.addr_mask) - | (addr & iotlb.addr_mask)); -- *plen = MIN(*plen, (addr | iotlb.addr_mask) - addr + 1); -+ page_mask &= iotlb.addr_mask; -+ plen = MIN(plen, (addr | iotlb.addr_mask) - addr + 1); - if (!(iotlb.perm & (1 << is_write))) { - goto translate_fail; - } -@@ -508,6 +516,19 @@ static MemoryRegionSection address_space_do_translate(AddressSpace *as, - - *xlat = addr; - -+ if (page_mask == (hwaddr)(-1)) { -+ /* Not behind an IOMMU, use default page size. */ -+ page_mask = ~TARGET_PAGE_MASK; -+ } -+ -+ if (page_mask_out) { -+ *page_mask_out = page_mask; -+ } -+ -+ if (plen_out) { -+ *plen_out = plen; -+ } -+ - return *section; - - translate_fail: -@@ -526,7 +547,7 @@ IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr, - - /* This can never be MMIO. */ - section = address_space_do_translate(as, addr, &xlat, &plen, -- is_write, false); -+ NULL, is_write, false); - - /* Illegal translation */ - if (section.mr == &io_mem_unassigned) { -@@ -570,7 +591,8 @@ MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr, - MemoryRegionSection section; - - /* This can be MMIO, so setup MMIO bit. */ -- section = address_space_do_translate(as, addr, xlat, plen, is_write, true); -+ section = address_space_do_translate(as, addr, xlat, plen, NULL, -+ is_write, true); - mr = section.mr; - - if (xen_enabled() && memory_access_is_direct(mr, is_write)) { --- -1.8.3.1 - diff --git a/SOURCES/kvm-exec-simplify-address_space_get_iotlb_entry.patch b/SOURCES/kvm-exec-simplify-address_space_get_iotlb_entry.patch deleted file mode 100644 index cef5b63..0000000 --- a/SOURCES/kvm-exec-simplify-address_space_get_iotlb_entry.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 134252b0775bcb125487eacc4d9f5a6921b0aa96 Mon Sep 17 00:00:00 2001 -From: Maxime Coquelin -Date: Fri, 20 Oct 2017 14:17:07 +0200 -Subject: [PATCH 05/19] exec: simplify address_space_get_iotlb_entry - -RH-Author: Maxime Coquelin -Message-id: <20171020141707.17637-3-maxime.coquelin@redhat.com> -Patchwork-id: 77418 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 2/2] exec: simplify address_space_get_iotlb_entry -Bugzilla: 1498817 -RH-Acked-by: Peter Xu -RH-Acked-by: Michael S. Tsirkin -RH-Acked-by: Jens Freimann - -From: Peter Xu - -This patch let address_space_get_iotlb_entry() to use the newly -introduced page_mask parameter in address_space_do_translate(). -Then we will be sure the IOTLB can be aligned to page mask, also -we should nicely support huge pages now when introducing a764040. - -Fixes: a764040 ("exec: abstract address_space_do_translate()") -Signed-off-by: Peter Xu -Signed-off-by: Maxime Coquelin -Acked-by: Michael S. Tsirkin -Message-Id: <20171010094247.10173-3-maxime.coquelin@redhat.com> -Signed-off-by: Paolo Bonzini -(cherry picked from commit 076a93d7972c9c1e3839d2f65edc32568a2cce93) -Signed-off-by: Maxime Coquelin -Signed-off-by: Miroslav Rezanina - -Conflicts: - exec.c (Skipping 166206845f7f) ---- - exec.c | 31 ++++++++++--------------------- - 1 file changed, 10 insertions(+), 21 deletions(-) - -diff --git a/exec.c b/exec.c -index e5f97fd..ae37a60 100644 ---- a/exec.c -+++ b/exec.c -@@ -540,14 +540,14 @@ IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr, - bool is_write) - { - MemoryRegionSection section; -- hwaddr xlat, plen; -+ hwaddr xlat, page_mask; - -- /* Try to get maximum page mask during translation. */ -- plen = (hwaddr)-1; -- -- /* This can never be MMIO. */ -- section = address_space_do_translate(as, addr, &xlat, &plen, -- NULL, is_write, false); -+ /* -+ * This can never be MMIO, and we don't really care about plen, -+ * but page mask. -+ */ -+ section = address_space_do_translate(as, addr, &xlat, NULL, -+ &page_mask, is_write, false); - - /* Illegal translation */ - if (section.mr == &io_mem_unassigned) { -@@ -558,22 +558,11 @@ IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr, - xlat += section.offset_within_address_space - - section.offset_within_region; - -- if (plen == (hwaddr)-1) { -- /* -- * We use default page size here. Logically it only happens -- * for identity mappings. -- */ -- plen = TARGET_PAGE_SIZE; -- } -- -- /* Convert to address mask */ -- plen -= 1; -- - return (IOMMUTLBEntry) { - .target_as = section.address_space, -- .iova = addr & ~plen, -- .translated_addr = xlat & ~plen, -- .addr_mask = plen, -+ .iova = addr & ~page_mask, -+ .translated_addr = xlat & ~page_mask, -+ .addr_mask = page_mask, - /* IOTLBs are for DMAs, and DMA only allows on RAMs. */ - .perm = IOMMU_RW, - }; --- -1.8.3.1 - diff --git a/SOURCES/kvm-file-posix-Fix-EINTR-handling.patch b/SOURCES/kvm-file-posix-Fix-EINTR-handling.patch new file mode 100644 index 0000000..e1a85c2 --- /dev/null +++ b/SOURCES/kvm-file-posix-Fix-EINTR-handling.patch @@ -0,0 +1,65 @@ +From 9075cb2c3c074b395192ce166fe17664b0d9543c Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 29 Jun 2018 06:11:53 +0200 +Subject: [PATCH 49/57] file-posix: Fix EINTR handling + +RH-Author: Fam Zheng +Message-id: <20180629061153.12687-14-famz@redhat.com> +Patchwork-id: 81164 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v2 13/13] file-posix: Fix EINTR handling +Bugzilla: 1482537 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Kevin Wolf + +EINTR should be checked against errno, not ret. While fixing the bug, +collect the branches with a switch block. + +Also, change the return value from -ENOSTUP to -ENOSPC when the actual +issue is request range passes EOF, which should be distinguishable from +the case of error == ENOSYS by the caller, so that it could still retry +with other byte ranges, whereas it shouldn't retry anymore upon ENOSYS. + +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/file-posix.c | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +diff --git a/block/file-posix.c b/block/file-posix.c +index 29ff699..0a9df5b 100644 +--- a/block/file-posix.c ++++ b/block/file-posix.c +@@ -1449,20 +1449,21 @@ static ssize_t handle_aiocb_copy_range(RawPosixAIOData *aiocb) + ssize_t ret = copy_file_range(aiocb->aio_fildes, &in_off, + aiocb->aio_fd2, &out_off, + bytes, 0); +- if (ret == -EINTR) { +- continue; ++ if (ret == 0) { ++ /* No progress (e.g. when beyond EOF), let the caller fall back to ++ * buffer I/O. */ ++ return -ENOSPC; + } + if (ret < 0) { +- if (errno == ENOSYS) { ++ switch (errno) { ++ case ENOSYS: + return -ENOTSUP; +- } else { ++ case EINTR: ++ continue; ++ default: + return -errno; + } + } +- if (!ret) { +- /* No progress (e.g. when beyond EOF), fall back to buffer I/O. */ +- return -ENOTSUP; +- } + bytes -= ret; + } + return 0; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-file-posix-Fix-creation-locking.patch b/SOURCES/kvm-file-posix-Fix-creation-locking.patch new file mode 100644 index 0000000..f95e53f --- /dev/null +++ b/SOURCES/kvm-file-posix-Fix-creation-locking.patch @@ -0,0 +1,56 @@ +From 19452491c1ec03ce4eef24388ec24076eb306377 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 9 Jul 2018 15:11:21 +0200 +Subject: [PATCH 29/89] file-posix: Fix creation locking + +RH-Author: Max Reitz +Message-id: <20180709151122.27541-2-mreitz@redhat.com> +Patchwork-id: 81271 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 1/2] file-posix: Fix creation locking +Bugzilla: 1599335 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Kevin Wolf +RH-Acked-by: John Snow + +raw_apply_lock_bytes() takes a bit mask of "permissions that are NOT +shared". + +Also, make the "perm" and "shared" variables uint64_t, because I do not +particularly like using ~ on signed integers (and other permission masks +are usually uint64_t, too). + +Reported-by: Kevin Wolf +Signed-off-by: Max Reitz +Signed-off-by: Kevin Wolf +(cherry picked from commit d815efcaf01b1698e2fdf0f3e125201025c53191) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + block/file-posix.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/block/file-posix.c b/block/file-posix.c +index 0a9df5b..e876770 100644 +--- a/block/file-posix.c ++++ b/block/file-posix.c +@@ -2052,7 +2052,7 @@ static int raw_co_create(BlockdevCreateOptions *options, Error **errp) + { + BlockdevCreateOptionsFile *file_opts; + int fd; +- int perm, shared; ++ uint64_t perm, shared; + int result = 0; + + /* Validate options and set default values */ +@@ -2088,7 +2088,7 @@ static int raw_co_create(BlockdevCreateOptions *options, Error **errp) + shared = BLK_PERM_ALL & ~BLK_PERM_RESIZE; + + /* Step one: Take locks */ +- result = raw_apply_lock_bytes(fd, perm, shared, false, errp); ++ result = raw_apply_lock_bytes(fd, perm, ~shared, false, errp); + if (result < 0) { + goto out_close; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-file-posix-Implement-bdrv_co_copy_range.patch b/SOURCES/kvm-file-posix-Implement-bdrv_co_copy_range.patch new file mode 100644 index 0000000..8872926 --- /dev/null +++ b/SOURCES/kvm-file-posix-Implement-bdrv_co_copy_range.patch @@ -0,0 +1,261 @@ +From 29d5339959b539767f6482adc00e02f0bb6083f9 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 29 Jun 2018 06:11:45 +0200 +Subject: [PATCH 41/57] file-posix: Implement bdrv_co_copy_range + +RH-Author: Fam Zheng +Message-id: <20180629061153.12687-6-famz@redhat.com> +Patchwork-id: 81156 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v2 05/13] file-posix: Implement bdrv_co_copy_range +Bugzilla: 1482537 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Kevin Wolf + +With copy_file_range(2), we can implement the bdrv_co_copy_range +semantics. + +Signed-off-by: Fam Zheng +Message-id: 20180601092648.24614-6-famz@redhat.com +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 1efad060d7e131dd52ecd1e038a6ddd37a3940c8) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/file-posix.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++-- + configure | 17 +++++++++ + include/block/raw-aio.h | 10 ++++- + 3 files changed, 120 insertions(+), 5 deletions(-) + +diff --git a/block/file-posix.c b/block/file-posix.c +index 370a483..29ff699 100644 +--- a/block/file-posix.c ++++ b/block/file-posix.c +@@ -59,6 +59,7 @@ + #ifdef __linux__ + #include + #include ++#include + #include + #include + #include +@@ -185,6 +186,8 @@ typedef struct RawPosixAIOData { + #define aio_ioctl_cmd aio_nbytes /* for QEMU_AIO_IOCTL */ + off_t aio_offset; + int aio_type; ++ int aio_fd2; ++ off_t aio_offset2; + } RawPosixAIOData; + + #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +@@ -1422,6 +1425,49 @@ static ssize_t handle_aiocb_write_zeroes(RawPosixAIOData *aiocb) + return -ENOTSUP; + } + ++#ifndef HAVE_COPY_FILE_RANGE ++static off_t copy_file_range(int in_fd, off_t *in_off, int out_fd, ++ off_t *out_off, size_t len, unsigned int flags) ++{ ++#ifdef __NR_copy_file_range ++ return syscall(__NR_copy_file_range, in_fd, in_off, out_fd, ++ out_off, len, flags); ++#else ++ errno = ENOSYS; ++ return -1; ++#endif ++} ++#endif ++ ++static ssize_t handle_aiocb_copy_range(RawPosixAIOData *aiocb) ++{ ++ uint64_t bytes = aiocb->aio_nbytes; ++ off_t in_off = aiocb->aio_offset; ++ off_t out_off = aiocb->aio_offset2; ++ ++ while (bytes) { ++ ssize_t ret = copy_file_range(aiocb->aio_fildes, &in_off, ++ aiocb->aio_fd2, &out_off, ++ bytes, 0); ++ if (ret == -EINTR) { ++ continue; ++ } ++ if (ret < 0) { ++ if (errno == ENOSYS) { ++ return -ENOTSUP; ++ } else { ++ return -errno; ++ } ++ } ++ if (!ret) { ++ /* No progress (e.g. when beyond EOF), fall back to buffer I/O. */ ++ return -ENOTSUP; ++ } ++ bytes -= ret; ++ } ++ return 0; ++} ++ + static ssize_t handle_aiocb_discard(RawPosixAIOData *aiocb) + { + int ret = -EOPNOTSUPP; +@@ -1502,6 +1548,9 @@ static int aio_worker(void *arg) + case QEMU_AIO_WRITE_ZEROES: + ret = handle_aiocb_write_zeroes(aiocb); + break; ++ case QEMU_AIO_COPY_RANGE: ++ ret = handle_aiocb_copy_range(aiocb); ++ break; + default: + fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type); + ret = -EINVAL; +@@ -1512,9 +1561,10 @@ static int aio_worker(void *arg) + return ret; + } + +-static int paio_submit_co(BlockDriverState *bs, int fd, +- int64_t offset, QEMUIOVector *qiov, +- int bytes, int type) ++static int paio_submit_co_full(BlockDriverState *bs, int fd, ++ int64_t offset, int fd2, int64_t offset2, ++ QEMUIOVector *qiov, ++ int bytes, int type) + { + RawPosixAIOData *acb = g_new(RawPosixAIOData, 1); + ThreadPool *pool; +@@ -1522,6 +1572,8 @@ static int paio_submit_co(BlockDriverState *bs, int fd, + acb->bs = bs; + acb->aio_type = type; + acb->aio_fildes = fd; ++ acb->aio_fd2 = fd2; ++ acb->aio_offset2 = offset2; + + acb->aio_nbytes = bytes; + acb->aio_offset = offset; +@@ -1537,6 +1589,13 @@ static int paio_submit_co(BlockDriverState *bs, int fd, + return thread_pool_submit_co(pool, aio_worker, acb); + } + ++static inline int paio_submit_co(BlockDriverState *bs, int fd, ++ int64_t offset, QEMUIOVector *qiov, ++ int bytes, int type) ++{ ++ return paio_submit_co_full(bs, fd, offset, -1, 0, qiov, bytes, type); ++} ++ + static BlockAIOCB *paio_submit(BlockDriverState *bs, int fd, + int64_t offset, QEMUIOVector *qiov, int bytes, + BlockCompletionFunc *cb, void *opaque, int type) +@@ -2346,6 +2405,35 @@ static void raw_abort_perm_update(BlockDriverState *bs) + raw_handle_perm_lock(bs, RAW_PL_ABORT, 0, 0, NULL); + } + ++static int coroutine_fn raw_co_copy_range_from(BlockDriverState *bs, ++ BdrvChild *src, uint64_t src_offset, ++ BdrvChild *dst, uint64_t dst_offset, ++ uint64_t bytes, BdrvRequestFlags flags) ++{ ++ return bdrv_co_copy_range_to(src, src_offset, dst, dst_offset, bytes, flags); ++} ++ ++static int coroutine_fn raw_co_copy_range_to(BlockDriverState *bs, ++ BdrvChild *src, uint64_t src_offset, ++ BdrvChild *dst, uint64_t dst_offset, ++ uint64_t bytes, BdrvRequestFlags flags) ++{ ++ BDRVRawState *s = bs->opaque; ++ BDRVRawState *src_s; ++ ++ assert(dst->bs == bs); ++ if (src->bs->drv->bdrv_co_copy_range_to != raw_co_copy_range_to) { ++ return -ENOTSUP; ++ } ++ ++ src_s = src->bs->opaque; ++ if (fd_open(bs) < 0 || fd_open(bs) < 0) { ++ return -EIO; ++ } ++ return paio_submit_co_full(bs, src_s->fd, src_offset, s->fd, dst_offset, ++ NULL, bytes, QEMU_AIO_COPY_RANGE); ++} ++ + BlockDriver bdrv_file = { + .format_name = "file", + .protocol_name = "file", +@@ -2368,6 +2456,8 @@ BlockDriver bdrv_file = { + .bdrv_co_pwritev = raw_co_pwritev, + .bdrv_aio_flush = raw_aio_flush, + .bdrv_aio_pdiscard = raw_aio_pdiscard, ++ .bdrv_co_copy_range_from = raw_co_copy_range_from, ++ .bdrv_co_copy_range_to = raw_co_copy_range_to, + .bdrv_refresh_limits = raw_refresh_limits, + .bdrv_io_plug = raw_aio_plug, + .bdrv_io_unplug = raw_aio_unplug, +@@ -2845,6 +2935,8 @@ static BlockDriver bdrv_host_device = { + .bdrv_co_pwritev = raw_co_pwritev, + .bdrv_aio_flush = raw_aio_flush, + .bdrv_aio_pdiscard = hdev_aio_pdiscard, ++ .bdrv_co_copy_range_from = raw_co_copy_range_from, ++ .bdrv_co_copy_range_to = raw_co_copy_range_to, + .bdrv_refresh_limits = raw_refresh_limits, + .bdrv_io_plug = raw_aio_plug, + .bdrv_io_unplug = raw_aio_unplug, +diff --git a/configure b/configure +index d2367f1..a869f19 100755 +--- a/configure ++++ b/configure +@@ -5156,6 +5156,20 @@ if test "$fortify_source" != "no"; then + fi + fi + ++############################################### ++# Check if copy_file_range is provided by glibc ++have_copy_file_range=no ++cat > $TMPC << EOF ++#include ++int main(void) { ++ copy_file_range(0, NULL, 0, NULL, 0, 0); ++ return 0; ++} ++EOF ++if compile_prog "" "" ; then ++ have_copy_file_range=yes ++fi ++ + ########################################## + # check if struct fsxattr is available via linux/fs.h + +@@ -6233,6 +6247,9 @@ fi + if test "$have_fsxattr" = "yes" ; then + echo "HAVE_FSXATTR=y" >> $config_host_mak + fi ++if test "$have_copy_file_range" = "yes" ; then ++ echo "HAVE_COPY_FILE_RANGE=y" >> $config_host_mak ++fi + if test "$vte" = "yes" ; then + echo "CONFIG_VTE=y" >> $config_host_mak + echo "VTE_CFLAGS=$vte_cflags" >> $config_host_mak +diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h +index a4cdbbf..3240530 100644 +--- a/include/block/raw-aio.h ++++ b/include/block/raw-aio.h +@@ -25,9 +25,15 @@ + #define QEMU_AIO_FLUSH 0x0008 + #define QEMU_AIO_DISCARD 0x0010 + #define QEMU_AIO_WRITE_ZEROES 0x0020 ++#define QEMU_AIO_COPY_RANGE 0x0040 + #define QEMU_AIO_TYPE_MASK \ +- (QEMU_AIO_READ|QEMU_AIO_WRITE|QEMU_AIO_IOCTL|QEMU_AIO_FLUSH| \ +- QEMU_AIO_DISCARD|QEMU_AIO_WRITE_ZEROES) ++ (QEMU_AIO_READ | \ ++ QEMU_AIO_WRITE | \ ++ QEMU_AIO_IOCTL | \ ++ QEMU_AIO_FLUSH | \ ++ QEMU_AIO_DISCARD | \ ++ QEMU_AIO_WRITE_ZEROES | \ ++ QEMU_AIO_COPY_RANGE) + + /* AIO flags */ + #define QEMU_AIO_MISALIGNED 0x1000 +-- +1.8.3.1 + diff --git a/SOURCES/kvm-file-posix-Make-.bdrv_co_truncate-asynchronous.patch b/SOURCES/kvm-file-posix-Make-.bdrv_co_truncate-asynchronous.patch new file mode 100644 index 0000000..b6a0528 --- /dev/null +++ b/SOURCES/kvm-file-posix-Make-.bdrv_co_truncate-asynchronous.patch @@ -0,0 +1,384 @@ +From 3bcd3a26a88ebeafa17dcf7e17d589f78e17500b Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 24 Jul 2018 09:23:26 +0200 +Subject: [PATCH 39/89] file-posix: Make .bdrv_co_truncate asynchronous + +RH-Author: Kevin Wolf +Message-id: <20180712144258.17303-7-kwolf@redhat.com> +Patchwork-id: 81324 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 6/6] file-posix: Make .bdrv_co_truncate asynchronous +Bugzilla: 1595173 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: John Snow + +This moves the code to resize an image file to the thread pool to avoid +blocking. + +Creating large images with preallocation with blockdev-create is now +actually a background job instead of blocking the monitor (and most +other things) until the preallocation has completed. + +Signed-off-by: Kevin Wolf +Reviewed-by: Stefan Hajnoczi +(cherry picked from commit 93f4e2ff4b31205d8bab0856631a52ed442b8b1c) +Signed-off-by: Kevin Wolf +--- + block/file-posix.c | 266 +++++++++++++++++++++++++++--------------------- + include/block/raw-aio.h | 4 +- + 2 files changed, 154 insertions(+), 116 deletions(-) + +diff --git a/block/file-posix.c b/block/file-posix.c +index f8488ec..24c2367 100644 +--- a/block/file-posix.c ++++ b/block/file-posix.c +@@ -186,8 +186,16 @@ typedef struct RawPosixAIOData { + #define aio_ioctl_cmd aio_nbytes /* for QEMU_AIO_IOCTL */ + off_t aio_offset; + int aio_type; +- int aio_fd2; +- off_t aio_offset2; ++ union { ++ struct { ++ int aio_fd2; ++ off_t aio_offset2; ++ }; ++ struct { ++ PreallocMode prealloc; ++ Error **errp; ++ }; ++ }; + } RawPosixAIOData; + + #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +@@ -1509,6 +1517,122 @@ static ssize_t handle_aiocb_discard(RawPosixAIOData *aiocb) + return ret; + } + ++static int handle_aiocb_truncate(RawPosixAIOData *aiocb) ++{ ++ int result = 0; ++ int64_t current_length = 0; ++ char *buf = NULL; ++ struct stat st; ++ int fd = aiocb->aio_fildes; ++ int64_t offset = aiocb->aio_offset; ++ Error **errp = aiocb->errp; ++ ++ if (fstat(fd, &st) < 0) { ++ result = -errno; ++ error_setg_errno(errp, -result, "Could not stat file"); ++ return result; ++ } ++ ++ current_length = st.st_size; ++ if (current_length > offset && aiocb->prealloc != PREALLOC_MODE_OFF) { ++ error_setg(errp, "Cannot use preallocation for shrinking files"); ++ return -ENOTSUP; ++ } ++ ++ switch (aiocb->prealloc) { ++#ifdef CONFIG_POSIX_FALLOCATE ++ case PREALLOC_MODE_FALLOC: ++ /* ++ * Truncating before posix_fallocate() makes it about twice slower on ++ * file systems that do not support fallocate(), trying to check if a ++ * block is allocated before allocating it, so don't do that here. ++ */ ++ if (offset != current_length) { ++ result = -posix_fallocate(fd, current_length, ++ offset - current_length); ++ if (result != 0) { ++ /* posix_fallocate() doesn't set errno. */ ++ error_setg_errno(errp, -result, ++ "Could not preallocate new data"); ++ } ++ } else { ++ result = 0; ++ } ++ goto out; ++#endif ++ case PREALLOC_MODE_FULL: ++ { ++ int64_t num = 0, left = offset - current_length; ++ off_t seek_result; ++ ++ /* ++ * Knowing the final size from the beginning could allow the file ++ * system driver to do less allocations and possibly avoid ++ * fragmentation of the file. ++ */ ++ if (ftruncate(fd, offset) != 0) { ++ result = -errno; ++ error_setg_errno(errp, -result, "Could not resize file"); ++ goto out; ++ } ++ ++ buf = g_malloc0(65536); ++ ++ seek_result = lseek(fd, current_length, SEEK_SET); ++ if (seek_result < 0) { ++ result = -errno; ++ error_setg_errno(errp, -result, ++ "Failed to seek to the old end of file"); ++ goto out; ++ } ++ ++ while (left > 0) { ++ num = MIN(left, 65536); ++ result = write(fd, buf, num); ++ if (result < 0) { ++ result = -errno; ++ error_setg_errno(errp, -result, ++ "Could not write zeros for preallocation"); ++ goto out; ++ } ++ left -= result; ++ } ++ if (result >= 0) { ++ result = fsync(fd); ++ if (result < 0) { ++ result = -errno; ++ error_setg_errno(errp, -result, ++ "Could not flush file to disk"); ++ goto out; ++ } ++ } ++ goto out; ++ } ++ case PREALLOC_MODE_OFF: ++ if (ftruncate(fd, offset) != 0) { ++ result = -errno; ++ error_setg_errno(errp, -result, "Could not resize file"); ++ } ++ return result; ++ default: ++ result = -ENOTSUP; ++ error_setg(errp, "Unsupported preallocation mode: %s", ++ PreallocMode_str(aiocb->prealloc)); ++ return result; ++ } ++ ++out: ++ if (result < 0) { ++ if (ftruncate(fd, current_length) < 0) { ++ error_report("Failed to restore old file length: %s", ++ strerror(errno)); ++ } ++ } ++ ++ g_free(buf); ++ return result; ++} ++ + static int aio_worker(void *arg) + { + RawPosixAIOData *aiocb = arg; +@@ -1552,6 +1676,9 @@ static int aio_worker(void *arg) + case QEMU_AIO_COPY_RANGE: + ret = handle_aiocb_copy_range(aiocb); + break; ++ case QEMU_AIO_TRUNCATE: ++ ret = handle_aiocb_truncate(aiocb); ++ break; + default: + fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type); + ret = -EINVAL; +@@ -1719,117 +1846,25 @@ static void raw_close(BlockDriverState *bs) + * + * Returns: 0 on success, -errno on failure. + */ +-static int raw_regular_truncate(int fd, int64_t offset, PreallocMode prealloc, +- Error **errp) ++static int coroutine_fn ++raw_regular_truncate(BlockDriverState *bs, int fd, int64_t offset, ++ PreallocMode prealloc, Error **errp) + { +- int result = 0; +- int64_t current_length = 0; +- char *buf = NULL; +- struct stat st; +- +- if (fstat(fd, &st) < 0) { +- result = -errno; +- error_setg_errno(errp, -result, "Could not stat file"); +- return result; +- } +- +- current_length = st.st_size; +- if (current_length > offset && prealloc != PREALLOC_MODE_OFF) { +- error_setg(errp, "Cannot use preallocation for shrinking files"); +- return -ENOTSUP; +- } +- +- switch (prealloc) { +-#ifdef CONFIG_POSIX_FALLOCATE +- case PREALLOC_MODE_FALLOC: +- /* +- * Truncating before posix_fallocate() makes it about twice slower on +- * file systems that do not support fallocate(), trying to check if a +- * block is allocated before allocating it, so don't do that here. +- */ +- if (offset != current_length) { +- result = -posix_fallocate(fd, current_length, offset - current_length); +- if (result != 0) { +- /* posix_fallocate() doesn't set errno. */ +- error_setg_errno(errp, -result, +- "Could not preallocate new data"); +- } +- } else { +- result = 0; +- } +- goto out; +-#endif +- case PREALLOC_MODE_FULL: +- { +- int64_t num = 0, left = offset - current_length; +- off_t seek_result; +- +- /* +- * Knowing the final size from the beginning could allow the file +- * system driver to do less allocations and possibly avoid +- * fragmentation of the file. +- */ +- if (ftruncate(fd, offset) != 0) { +- result = -errno; +- error_setg_errno(errp, -result, "Could not resize file"); +- goto out; +- } +- +- buf = g_malloc0(65536); +- +- seek_result = lseek(fd, current_length, SEEK_SET); +- if (seek_result < 0) { +- result = -errno; +- error_setg_errno(errp, -result, +- "Failed to seek to the old end of file"); +- goto out; +- } +- +- while (left > 0) { +- num = MIN(left, 65536); +- result = write(fd, buf, num); +- if (result < 0) { +- result = -errno; +- error_setg_errno(errp, -result, +- "Could not write zeros for preallocation"); +- goto out; +- } +- left -= result; +- } +- if (result >= 0) { +- result = fsync(fd); +- if (result < 0) { +- result = -errno; +- error_setg_errno(errp, -result, +- "Could not flush file to disk"); +- goto out; +- } +- } +- goto out; +- } +- case PREALLOC_MODE_OFF: +- if (ftruncate(fd, offset) != 0) { +- result = -errno; +- error_setg_errno(errp, -result, "Could not resize file"); +- } +- return result; +- default: +- result = -ENOTSUP; +- error_setg(errp, "Unsupported preallocation mode: %s", +- PreallocMode_str(prealloc)); +- return result; +- } ++ RawPosixAIOData *acb = g_new(RawPosixAIOData, 1); ++ ThreadPool *pool; + +-out: +- if (result < 0) { +- if (ftruncate(fd, current_length) < 0) { +- error_report("Failed to restore old file length: %s", +- strerror(errno)); +- } +- } ++ *acb = (RawPosixAIOData) { ++ .bs = bs, ++ .aio_fildes = fd, ++ .aio_type = QEMU_AIO_TRUNCATE, ++ .aio_offset = offset, ++ .prealloc = prealloc, ++ .errp = errp, ++ }; + +- g_free(buf); +- return result; ++ /* @bs can be NULL, bdrv_get_aio_context() returns the main context then */ ++ pool = aio_get_thread_pool(bdrv_get_aio_context(bs)); ++ return thread_pool_submit_co(pool, aio_worker, acb); + } + + static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, +@@ -1846,7 +1881,7 @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, + } + + if (S_ISREG(st.st_mode)) { +- return raw_regular_truncate(s->fd, offset, prealloc, errp); ++ return raw_regular_truncate(bs, s->fd, offset, prealloc, errp); + } + + if (prealloc != PREALLOC_MODE_OFF) { +@@ -2048,7 +2083,8 @@ static int64_t raw_get_allocated_file_size(BlockDriverState *bs) + return (int64_t)st.st_blocks * 512; + } + +-static int raw_co_create(BlockdevCreateOptions *options, Error **errp) ++static int coroutine_fn ++raw_co_create(BlockdevCreateOptions *options, Error **errp) + { + BlockdevCreateOptionsFile *file_opts; + Error *local_err = NULL; +@@ -2101,7 +2137,7 @@ static int raw_co_create(BlockdevCreateOptions *options, Error **errp) + } + + /* Clear the file by truncating it to 0 */ +- result = raw_regular_truncate(fd, 0, PREALLOC_MODE_OFF, errp); ++ result = raw_regular_truncate(NULL, fd, 0, PREALLOC_MODE_OFF, errp); + if (result < 0) { + goto out_unlock; + } +@@ -2123,8 +2159,8 @@ static int raw_co_create(BlockdevCreateOptions *options, Error **errp) + + /* Resize and potentially preallocate the file to the desired + * final size */ +- result = raw_regular_truncate(fd, file_opts->size, file_opts->preallocation, +- errp); ++ result = raw_regular_truncate(NULL, fd, file_opts->size, ++ file_opts->preallocation, errp); + if (result < 0) { + goto out_unlock; + } +diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h +index 3240530..2ffcd9d 100644 +--- a/include/block/raw-aio.h ++++ b/include/block/raw-aio.h +@@ -26,6 +26,7 @@ + #define QEMU_AIO_DISCARD 0x0010 + #define QEMU_AIO_WRITE_ZEROES 0x0020 + #define QEMU_AIO_COPY_RANGE 0x0040 ++#define QEMU_AIO_TRUNCATE 0x0080 + #define QEMU_AIO_TYPE_MASK \ + (QEMU_AIO_READ | \ + QEMU_AIO_WRITE | \ +@@ -33,7 +34,8 @@ + QEMU_AIO_FLUSH | \ + QEMU_AIO_DISCARD | \ + QEMU_AIO_WRITE_ZEROES | \ +- QEMU_AIO_COPY_RANGE) ++ QEMU_AIO_COPY_RANGE | \ ++ QEMU_AIO_TRUNCATE) + + /* AIO flags */ + #define QEMU_AIO_MISALIGNED 0x1000 +-- +1.8.3.1 + diff --git a/SOURCES/kvm-file-posix-Unlock-FD-after-creation.patch b/SOURCES/kvm-file-posix-Unlock-FD-after-creation.patch new file mode 100644 index 0000000..c463fca --- /dev/null +++ b/SOURCES/kvm-file-posix-Unlock-FD-after-creation.patch @@ -0,0 +1,77 @@ +From 1375d18f600b29111c7d8e6e5a2c73d01afe994b Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 9 Jul 2018 15:11:22 +0200 +Subject: [PATCH 30/89] file-posix: Unlock FD after creation + +RH-Author: Max Reitz +Message-id: <20180709151122.27541-3-mreitz@redhat.com> +Patchwork-id: 81269 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 2/2] file-posix: Unlock FD after creation +Bugzilla: 1599335 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Kevin Wolf +RH-Acked-by: John Snow + +Closing the FD does not necessarily mean that it is unlocked. Fix this +by relinquishing all permission locks before qemu_close(). + +Reported-by: Kevin Wolf +Signed-off-by: Max Reitz +Signed-off-by: Kevin Wolf +(cherry picked from commit 7c20c808a5cbf5d244735bc78fc3138c739c1946) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + block/file-posix.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/block/file-posix.c b/block/file-posix.c +index e876770..cbf7c11 100644 +--- a/block/file-posix.c ++++ b/block/file-posix.c +@@ -2051,6 +2051,7 @@ static int64_t raw_get_allocated_file_size(BlockDriverState *bs) + static int raw_co_create(BlockdevCreateOptions *options, Error **errp) + { + BlockdevCreateOptionsFile *file_opts; ++ Error *local_err = NULL; + int fd; + uint64_t perm, shared; + int result = 0; +@@ -2096,13 +2097,13 @@ static int raw_co_create(BlockdevCreateOptions *options, Error **errp) + /* Step two: Check that nobody else has taken conflicting locks */ + result = raw_check_lock_bytes(fd, perm, shared, errp); + if (result < 0) { +- goto out_close; ++ goto out_unlock; + } + + /* Clear the file by truncating it to 0 */ + result = raw_regular_truncate(fd, 0, PREALLOC_MODE_OFF, errp); + if (result < 0) { +- goto out_close; ++ goto out_unlock; + } + + if (file_opts->nocow) { +@@ -2125,7 +2126,17 @@ static int raw_co_create(BlockdevCreateOptions *options, Error **errp) + result = raw_regular_truncate(fd, file_opts->size, file_opts->preallocation, + errp); + if (result < 0) { +- goto out_close; ++ goto out_unlock; ++ } ++ ++out_unlock: ++ raw_apply_lock_bytes(fd, 0, 0, true, &local_err); ++ if (local_err) { ++ /* The above call should not fail, and if it does, that does ++ * not mean the whole creation operation has failed. So ++ * report it the user for their convenience, but do not report ++ * it to the caller. */ ++ error_report_err(local_err); + } + + out_close: +-- +1.8.3.1 + diff --git a/SOURCES/kvm-file-posix-specify-expected-filetypes.patch b/SOURCES/kvm-file-posix-specify-expected-filetypes.patch new file mode 100644 index 0000000..8318184 --- /dev/null +++ b/SOURCES/kvm-file-posix-specify-expected-filetypes.patch @@ -0,0 +1,151 @@ +From 75d7ceaa7c842deeae5cd7c09bbfd982c3dd0f2e Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 13 Jul 2018 14:50:01 +0200 +Subject: [PATCH 43/89] file-posix: specify expected filetypes + +RH-Author: Kevin Wolf +Message-id: <20180713145002.20953-2-kwolf@redhat.com> +Patchwork-id: 81350 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 1/2] file-posix: specify expected filetypes +Bugzilla: 1525829 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +From: John Snow + +Adjust each caller of raw_open_common to specify if they are expecting +host and character devices or not. Tighten expectations of file types upon +open in the common code and refuse types that are not expected. + +This has two effects: + +(1) Character and block devices are now considered deprecated for the + 'file' driver, which expects only S_IFREG, and +(2) no file-posix driver (file, host_cdrom, or host_device) can open + directories now. + +I don't think there's a legitimate reason to open directories as if +they were files. This prevents QEMU from opening and attempting to probe +a directory inode, which can break in exciting ways. One of those ways +is lseek on ext4/xfs, which will return 0x7fffffffffffffff as the file +size instead of EISDIR. This can coax QEMU into responding with a +confusing "file too big" instead of "Hey, that's not a file". + +See: https://bugs.launchpad.net/qemu/+bug/1739304/ +Signed-off-by: John Snow +Signed-off-by: Kevin Wolf +(cherry picked from commit 230ff73904e72dde2d7718c2da407786a1c72e57) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/file-posix.c | 39 +++++++++++++++++++++++++++++++-------- + qemu-doc.texi | 6 ++++++ + 2 files changed, 37 insertions(+), 8 deletions(-) + +diff --git a/block/file-posix.c b/block/file-posix.c +index 24c2367..06ec67d 100644 +--- a/block/file-posix.c ++++ b/block/file-posix.c +@@ -431,7 +431,8 @@ static QemuOptsList raw_runtime_opts = { + }; + + static int raw_open_common(BlockDriverState *bs, QDict *options, +- int bdrv_flags, int open_flags, Error **errp) ++ int bdrv_flags, int open_flags, ++ bool device, Error **errp) + { + BDRVRawState *s = bs->opaque; + QemuOpts *opts; +@@ -569,10 +570,32 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, + error_setg_errno(errp, errno, "Could not stat file"); + goto fail; + } +- if (S_ISREG(st.st_mode)) { +- s->discard_zeroes = true; +- s->has_fallocate = true; ++ ++ if (!device) { ++ if (S_ISBLK(st.st_mode)) { ++ warn_report("Opening a block device as a file using the '%s' " ++ "driver is deprecated", bs->drv->format_name); ++ } else if (S_ISCHR(st.st_mode)) { ++ warn_report("Opening a character device as a file using the '%s' " ++ "driver is deprecated", bs->drv->format_name); ++ } else if (!S_ISREG(st.st_mode)) { ++ error_setg(errp, "A regular file was expected by the '%s' driver, " ++ "but something else was given", bs->drv->format_name); ++ ret = -EINVAL; ++ goto fail; ++ } else { ++ s->discard_zeroes = true; ++ s->has_fallocate = true; ++ } ++ } else { ++ if (!(S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))) { ++ error_setg(errp, "'%s' driver expects either " ++ "a character or block device", bs->drv->format_name); ++ ret = -EINVAL; ++ goto fail; ++ } + } ++ + if (S_ISBLK(st.st_mode)) { + #ifdef BLKDISCARDZEROES + unsigned int arg; +@@ -625,7 +648,7 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, + BDRVRawState *s = bs->opaque; + + s->type = FTYPE_FILE; +- return raw_open_common(bs, options, flags, 0, errp); ++ return raw_open_common(bs, options, flags, 0, false, errp); + } + + typedef enum { +@@ -2794,7 +2817,7 @@ hdev_open_Mac_error: + + s->type = FTYPE_FILE; + +- ret = raw_open_common(bs, options, flags, 0, &local_err); ++ ret = raw_open_common(bs, options, flags, 0, true, &local_err); + if (ret < 0) { + error_propagate(errp, local_err); + #if defined(__APPLE__) && defined(__MACH__) +@@ -3023,7 +3046,7 @@ static int cdrom_open(BlockDriverState *bs, QDict *options, int flags, + s->type = FTYPE_CD; + + /* open will not fail even if no CD is inserted, so add O_NONBLOCK */ +- return raw_open_common(bs, options, flags, O_NONBLOCK, errp); ++ return raw_open_common(bs, options, flags, O_NONBLOCK, true, errp); + } + + static int cdrom_probe_device(const char *filename) +@@ -3136,7 +3159,7 @@ static int cdrom_open(BlockDriverState *bs, QDict *options, int flags, + + s->type = FTYPE_CD; + +- ret = raw_open_common(bs, options, flags, 0, &local_err); ++ ret = raw_open_common(bs, options, flags, 0, true, &local_err); + if (ret) { + error_propagate(errp, local_err); + return ret; +diff --git a/qemu-doc.texi b/qemu-doc.texi +index de5097a..985e0f2 100644 +--- a/qemu-doc.texi ++++ b/qemu-doc.texi +@@ -2938,6 +2938,12 @@ The @code{-startdate} option has been replaced by @code{-rtc base=@var{date}}. + The ``convert -s snapshot_id_or_name'' argument is obsoleted + by the ``convert -l snapshot_param'' argument instead. + ++@subsection -drive file=json:@{...@{'driver':'file'@}@} (since 3.0) ++ ++The 'file' driver for drives is no longer appropriate for character or host ++devices and will only accept regular files (S_IFREG). The correct driver ++for these file types is 'host_cdrom' or 'host_device' as appropriate. ++ + @section QEMU Machine Protocol (QMP) commands + + @subsection block-dirty-bitmap-add "autoload" parameter (since 2.12.0) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-fw_cfg-add-write-callback.patch b/SOURCES/kvm-fw_cfg-add-write-callback.patch deleted file mode 100644 index 07ae0d1..0000000 --- a/SOURCES/kvm-fw_cfg-add-write-callback.patch +++ /dev/null @@ -1,210 +0,0 @@ -From 57c6cfd7cf03d6fcc26dfd6a2481b8997616739a Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Mon, 27 Nov 2017 22:51:04 +0100 -Subject: [PATCH 06/21] fw_cfg: add write callback -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Marc-André Lureau -Message-id: <20171127225111.24518-3-marcandre.lureau@redhat.com> -Patchwork-id: 77922 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 2/9] fw_cfg: add write callback -Bugzilla: 1398633 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Andrew Jones -RH-Acked-by: Miroslav Rezanina - -Reintroduce the write callback that was removed when write support was -removed in commit 023e3148567ac898c7258138f8e86c3c2bb40d07. - -Contrary to the previous callback implementation, the write_cb -callback is called whenever a write happened, so handlers must be -ready to handle partial write as necessary. - -Signed-off-by: Marc-André Lureau -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin - -(cherry picked from commit 5f9252f7cc12c5cec1b3c6695aca02eb52ea7acc) -Signed-off-by: Marc-André Lureau -Signed-off-by: Miroslav Rezanina ---- - hw/acpi/vmgenid.c | 2 +- - hw/core/loader.c | 2 +- - hw/i386/acpi-build.c | 2 +- - hw/isa/lpc_ich9.c | 4 ++-- - hw/nvram/fw_cfg.c | 14 ++++++++++---- - include/hw/nvram/fw_cfg.h | 3 +++ - 6 files changed, 18 insertions(+), 9 deletions(-) - -diff --git a/hw/acpi/vmgenid.c b/hw/acpi/vmgenid.c -index a32b847..c1e935d 100644 ---- a/hw/acpi/vmgenid.c -+++ b/hw/acpi/vmgenid.c -@@ -124,7 +124,7 @@ void vmgenid_add_fw_cfg(VmGenIdState *vms, FWCfgState *s, GArray *guid) - fw_cfg_add_file(s, VMGENID_GUID_FW_CFG_FILE, guid->data, - VMGENID_FW_CFG_SIZE); - /* Create a read-write fw_cfg file for Address */ -- fw_cfg_add_file_callback(s, VMGENID_ADDR_FW_CFG_FILE, NULL, NULL, -+ fw_cfg_add_file_callback(s, VMGENID_ADDR_FW_CFG_FILE, NULL, NULL, NULL, - vms->vmgenid_addr_le, - ARRAY_SIZE(vms->vmgenid_addr_le), false); - } -diff --git a/hw/core/loader.c b/hw/core/loader.c -index 4593061..91669d6 100644 ---- a/hw/core/loader.c -+++ b/hw/core/loader.c -@@ -1023,7 +1023,7 @@ MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len, - } - - fw_cfg_add_file_callback(fw_cfg, fw_file_name, -- fw_callback, callback_opaque, -+ fw_callback, NULL, callback_opaque, - data, rom->datasize, read_only); - } - return mr; -diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c -index e38fff2..a61560f 100644 ---- a/hw/i386/acpi-build.c -+++ b/hw/i386/acpi-build.c -@@ -2924,7 +2924,7 @@ void acpi_setup(void) - - build_state->rsdp = g_memdup(tables.rsdp->data, rsdp_size); - fw_cfg_add_file_callback(pcms->fw_cfg, ACPI_BUILD_RSDP_FILE, -- acpi_build_update, build_state, -+ acpi_build_update, NULL, build_state, - build_state->rsdp, rsdp_size, true); - build_state->rsdp_mr = NULL; - } else { -diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c -index 39f56ba..ec3c9f7 100644 ---- a/hw/isa/lpc_ich9.c -+++ b/hw/isa/lpc_ich9.c -@@ -402,12 +402,12 @@ void ich9_lpc_pm_init(PCIDevice *lpc_pci, bool smm_enabled) - * just link them into fw_cfg here. - */ - fw_cfg_add_file_callback(fw_cfg, "etc/smi/requested-features", -- NULL, NULL, -+ NULL, NULL, NULL, - lpc->smi_guest_features_le, - sizeof lpc->smi_guest_features_le, - false); - fw_cfg_add_file_callback(fw_cfg, "etc/smi/features-ok", -- smi_features_ok_callback, lpc, -+ smi_features_ok_callback, NULL, lpc, - &lpc->smi_features_ok, - sizeof lpc->smi_features_ok, - true); -diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c -index e3bd626..753ac0e 100644 ---- a/hw/nvram/fw_cfg.c -+++ b/hw/nvram/fw_cfg.c -@@ -56,6 +56,7 @@ struct FWCfgEntry { - uint8_t *data; - void *callback_opaque; - FWCfgCallback select_cb; -+ FWCfgWriteCallback write_cb; - }; - - #define JPG_FILE 0 -@@ -370,6 +371,8 @@ static void fw_cfg_dma_transfer(FWCfgState *s) - dma_memory_read(s->dma_as, dma.address, - &e->data[s->cur_offset], len)) { - dma.control |= FW_CFG_DMA_CTL_ERROR; -+ } else if (e->write_cb) { -+ e->write_cb(e->callback_opaque, s->cur_offset, len); - } - } - -@@ -570,6 +573,7 @@ static const VMStateDescription vmstate_fw_cfg = { - - static void fw_cfg_add_bytes_callback(FWCfgState *s, uint16_t key, - FWCfgCallback select_cb, -+ FWCfgWriteCallback write_cb, - void *callback_opaque, - void *data, size_t len, - bool read_only) -@@ -584,6 +588,7 @@ static void fw_cfg_add_bytes_callback(FWCfgState *s, uint16_t key, - s->entries[arch][key].data = data; - s->entries[arch][key].len = (uint32_t)len; - s->entries[arch][key].select_cb = select_cb; -+ s->entries[arch][key].write_cb = write_cb; - s->entries[arch][key].callback_opaque = callback_opaque; - s->entries[arch][key].allow_write = !read_only; - } -@@ -610,7 +615,7 @@ static void *fw_cfg_modify_bytes_read(FWCfgState *s, uint16_t key, - - void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len) - { -- fw_cfg_add_bytes_callback(s, key, NULL, NULL, data, len, true); -+ fw_cfg_add_bytes_callback(s, key, NULL, NULL, NULL, data, len, true); - } - - void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value) -@@ -737,6 +742,7 @@ static int get_fw_cfg_order(FWCfgState *s, const char *name) - - void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, - FWCfgCallback select_cb, -+ FWCfgWriteCallback write_cb, - void *callback_opaque, - void *data, size_t len, bool read_only) - { -@@ -800,7 +806,7 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, - } - - fw_cfg_add_bytes_callback(s, FW_CFG_FILE_FIRST + index, -- select_cb, -+ select_cb, write_cb, - callback_opaque, data, len, - read_only); - -@@ -815,7 +821,7 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, - void fw_cfg_add_file(FWCfgState *s, const char *filename, - void *data, size_t len) - { -- fw_cfg_add_file_callback(s, filename, NULL, NULL, data, len, true); -+ fw_cfg_add_file_callback(s, filename, NULL, NULL, NULL, data, len, true); - } - - void *fw_cfg_modify_file(FWCfgState *s, const char *filename, -@@ -838,7 +844,7 @@ void *fw_cfg_modify_file(FWCfgState *s, const char *filename, - } - } - /* add new one */ -- fw_cfg_add_file_callback(s, filename, NULL, NULL, data, len, true); -+ fw_cfg_add_file_callback(s, filename, NULL, NULL, NULL, data, len, true); - return NULL; - } - -diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h -index f50d068..7ccbae5 100644 ---- a/include/hw/nvram/fw_cfg.h -+++ b/include/hw/nvram/fw_cfg.h -@@ -45,6 +45,7 @@ typedef struct FWCfgDmaAccess { - } QEMU_PACKED FWCfgDmaAccess; - - typedef void (*FWCfgCallback)(void *opaque); -+typedef void (*FWCfgWriteCallback)(void *opaque, off_t start, size_t len); - - struct FWCfgState { - /*< private >*/ -@@ -183,6 +184,7 @@ void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data, - * @s: fw_cfg device being modified - * @filename: name of new fw_cfg file item - * @select_cb: callback function when selecting -+ * @write_cb: callback function after a write - * @callback_opaque: argument to be passed into callback function - * @data: pointer to start of item data - * @len: size of item data -@@ -202,6 +204,7 @@ void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data, - */ - void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, - FWCfgCallback select_cb, -+ FWCfgWriteCallback write_cb, - void *callback_opaque, - void *data, size_t len, bool read_only); - --- -1.8.3.1 - diff --git a/SOURCES/kvm-fw_cfg-fix-memory-corruption-when-all-fw_cfg-slots-a.patch b/SOURCES/kvm-fw_cfg-fix-memory-corruption-when-all-fw_cfg-slots-a.patch deleted file mode 100644 index 9a7c5c8..0000000 --- a/SOURCES/kvm-fw_cfg-fix-memory-corruption-when-all-fw_cfg-slots-a.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 0df9f346cb7d66701c79cb6fa1b187aa603d659b Mon Sep 17 00:00:00 2001 -From: Marcel Apfelbaum -Date: Mon, 15 Jan 2018 10:06:42 +0100 -Subject: [PATCH 09/12] fw_cfg: fix memory corruption when all fw_cfg slots are - used -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Marcel Apfelbaum -Message-id: <20180115100642.64493-1-marcel@redhat.com> -Patchwork-id: 78571 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH] fw_cfg: fix memory corruption when all fw_cfg slots are used -Bugzilla: 1462145 -RH-Acked-by: Marc-André Lureau -RH-Acked-by: Igor Mammedov -RH-Acked-by: Gerd Hoffmann -RH-Acked-by: Laszlo Ersek - -When all the fw_cfg slots are used, a write is made outside the -bounds of the fw_cfg files array as part of the sort algorithm. - -Fix it by avoiding an unnecessary array element move. -Fix also an assert while at it. - -Signed-off-by: Marcel Apfelbaum -Message-Id: <20180108215007.46471-1-marcel@redhat.com> -Reviewed-by: Laszlo Ersek -Signed-off-by: Eduardo Habkost -(cherry picked from commit 45eda6c8eb45107630da670bc993074cf85ef64c) -Signed-off-by: Marcel Apfelbaum -Signed-off-by: Miroslav Rezanina ---- - hw/nvram/fw_cfg.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c -index 753ac0e..4313484 100644 ---- a/hw/nvram/fw_cfg.c -+++ b/hw/nvram/fw_cfg.c -@@ -784,7 +784,7 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, - * index and "i - 1" is the one being copied from, thus the - * unusual start and end in the for statement. - */ -- for (i = count + 1; i > index; i--) { -+ for (i = count; i > index; i--) { - s->files->f[i] = s->files->f[i - 1]; - s->files->f[i].select = cpu_to_be16(FW_CFG_FILE_FIRST + i); - s->entries[0][FW_CFG_FILE_FIRST + i] = -@@ -833,7 +833,6 @@ void *fw_cfg_modify_file(FWCfgState *s, const char *filename, - assert(s->files); - - index = be32_to_cpu(s->files->count); -- assert(index < fw_cfg_file_slots(s)); - - for (i = 0; i < index; i++) { - if (strcmp(filename, s->files->f[i].name) == 0) { -@@ -843,6 +842,9 @@ void *fw_cfg_modify_file(FWCfgState *s, const char *filename, - return ptr; - } - } -+ -+ assert(index < fw_cfg_file_slots(s)); -+ - /* add new one */ - fw_cfg_add_file_callback(s, filename, NULL, NULL, NULL, data, len, true); - return NULL; --- -1.8.3.1 - diff --git a/SOURCES/kvm-fw_cfg-rename-read-callback.patch b/SOURCES/kvm-fw_cfg-rename-read-callback.patch deleted file mode 100644 index b216681..0000000 --- a/SOURCES/kvm-fw_cfg-rename-read-callback.patch +++ /dev/null @@ -1,180 +0,0 @@ -From 571cf340ae415185ab21a1af146cb3df7b489286 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Mon, 27 Nov 2017 22:51:03 +0100 -Subject: [PATCH 05/21] fw_cfg: rename read callback -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Marc-André Lureau -Message-id: <20171127225111.24518-2-marcandre.lureau@redhat.com> -Patchwork-id: 77921 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 1/9] fw_cfg: rename read callback -Bugzilla: 1398633 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Andrew Jones -RH-Acked-by: Miroslav Rezanina - -The callback is called on select. - -Furthermore, the next patch introduced a new callback, so rename the -function type with a generic name. - -Signed-off-by: Marc-André Lureau -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin - -(cherry picked from commit 6f6f4aec749ba9a4fb58c7c20536a61b0381ff35) -Signed-off-by: Marc-André Lureau -Signed-off-by: Miroslav Rezanina ---- - hw/core/loader.c | 2 +- - hw/nvram/fw_cfg.c | 30 ++++++++++++++++-------------- - include/hw/loader.h | 2 +- - include/hw/nvram/fw_cfg.h | 7 ++++--- - 4 files changed, 22 insertions(+), 19 deletions(-) - -diff --git a/hw/core/loader.c b/hw/core/loader.c -index ebe574c..4593061 100644 ---- a/hw/core/loader.c -+++ b/hw/core/loader.c -@@ -989,7 +989,7 @@ err: - - MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len, - size_t max_len, hwaddr addr, const char *fw_file_name, -- FWCfgReadCallback fw_callback, void *callback_opaque, -+ FWCfgCallback fw_callback, void *callback_opaque, - AddressSpace *as, bool read_only) - { - MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); -diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c -index 5bd9044..e3bd626 100644 ---- a/hw/nvram/fw_cfg.c -+++ b/hw/nvram/fw_cfg.c -@@ -55,7 +55,7 @@ struct FWCfgEntry { - bool allow_write; - uint8_t *data; - void *callback_opaque; -- FWCfgReadCallback read_callback; -+ FWCfgCallback select_cb; - }; - - #define JPG_FILE 0 -@@ -236,8 +236,8 @@ static int fw_cfg_select(FWCfgState *s, uint16_t key) - /* entry successfully selected, now run callback if present */ - arch = !!(key & FW_CFG_ARCH_LOCAL); - e = &s->entries[arch][key & FW_CFG_ENTRY_MASK]; -- if (e->read_callback) { -- e->read_callback(e->callback_opaque); -+ if (e->select_cb) { -+ e->select_cb(e->callback_opaque); - } - } - -@@ -568,11 +568,11 @@ static const VMStateDescription vmstate_fw_cfg = { - } - }; - --static void fw_cfg_add_bytes_read_callback(FWCfgState *s, uint16_t key, -- FWCfgReadCallback callback, -- void *callback_opaque, -- void *data, size_t len, -- bool read_only) -+static void fw_cfg_add_bytes_callback(FWCfgState *s, uint16_t key, -+ FWCfgCallback select_cb, -+ void *callback_opaque, -+ void *data, size_t len, -+ bool read_only) - { - int arch = !!(key & FW_CFG_ARCH_LOCAL); - -@@ -583,7 +583,7 @@ static void fw_cfg_add_bytes_read_callback(FWCfgState *s, uint16_t key, - - s->entries[arch][key].data = data; - s->entries[arch][key].len = (uint32_t)len; -- s->entries[arch][key].read_callback = callback; -+ s->entries[arch][key].select_cb = select_cb; - s->entries[arch][key].callback_opaque = callback_opaque; - s->entries[arch][key].allow_write = !read_only; - } -@@ -610,7 +610,7 @@ static void *fw_cfg_modify_bytes_read(FWCfgState *s, uint16_t key, - - void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len) - { -- fw_cfg_add_bytes_read_callback(s, key, NULL, NULL, data, len, true); -+ fw_cfg_add_bytes_callback(s, key, NULL, NULL, data, len, true); - } - - void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value) -@@ -736,7 +736,8 @@ static int get_fw_cfg_order(FWCfgState *s, const char *name) - } - - void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, -- FWCfgReadCallback callback, void *callback_opaque, -+ FWCfgCallback select_cb, -+ void *callback_opaque, - void *data, size_t len, bool read_only) - { - int i, index, count; -@@ -798,9 +799,10 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, - } - } - -- fw_cfg_add_bytes_read_callback(s, FW_CFG_FILE_FIRST + index, -- callback, callback_opaque, data, len, -- read_only); -+ fw_cfg_add_bytes_callback(s, FW_CFG_FILE_FIRST + index, -+ select_cb, -+ callback_opaque, data, len, -+ read_only); - - s->files->f[index].size = cpu_to_be32(len); - s->files->f[index].select = cpu_to_be16(FW_CFG_FILE_FIRST + index); -diff --git a/include/hw/loader.h b/include/hw/loader.h -index 490c9ff..355fe0f 100644 ---- a/include/hw/loader.h -+++ b/include/hw/loader.h -@@ -192,7 +192,7 @@ int rom_add_file(const char *file, const char *fw_dir, - MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len, - size_t max_len, hwaddr addr, - const char *fw_file_name, -- FWCfgReadCallback fw_callback, -+ FWCfgCallback fw_callback, - void *callback_opaque, AddressSpace *as, - bool read_only); - int rom_add_elf_program(const char *name, void *data, size_t datasize, -diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h -index b77ea48..f50d068 100644 ---- a/include/hw/nvram/fw_cfg.h -+++ b/include/hw/nvram/fw_cfg.h -@@ -44,7 +44,7 @@ typedef struct FWCfgDmaAccess { - uint64_t address; - } QEMU_PACKED FWCfgDmaAccess; - --typedef void (*FWCfgReadCallback)(void *opaque); -+typedef void (*FWCfgCallback)(void *opaque); - - struct FWCfgState { - /*< private >*/ -@@ -182,7 +182,7 @@ void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data, - * fw_cfg_add_file_callback: - * @s: fw_cfg device being modified - * @filename: name of new fw_cfg file item -- * @callback: callback function -+ * @select_cb: callback function when selecting - * @callback_opaque: argument to be passed into callback function - * @data: pointer to start of item data - * @len: size of item data -@@ -201,7 +201,8 @@ void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data, - * with FW_CFG_DMA_CTL_SELECT). - */ - void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, -- FWCfgReadCallback callback, void *callback_opaque, -+ FWCfgCallback select_cb, -+ void *callback_opaque, - void *data, size_t len, bool read_only); - - /** --- -1.8.3.1 - diff --git a/SOURCES/kvm-gicv3-Convert-to-DEFINE_PROP_LINK.patch b/SOURCES/kvm-gicv3-Convert-to-DEFINE_PROP_LINK.patch deleted file mode 100644 index 03d2e52..0000000 --- a/SOURCES/kvm-gicv3-Convert-to-DEFINE_PROP_LINK.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 11098ad708cd535e4d79bf82c07ef78ca16b647c Mon Sep 17 00:00:00 2001 -From: Auger Eric -Date: Tue, 28 Nov 2017 15:14:02 +0100 -Subject: [PATCH 1/9] gicv3: Convert to DEFINE_PROP_LINK - -RH-Author: Auger Eric -Message-id: <1511882048-11256-2-git-send-email-eric.auger@redhat.com> -Patchwork-id: 77939 -O-Subject: [RHV7.5 qemu-kvm-ma PATCH 1/7] gicv3: Convert to DEFINE_PROP_LINK -Bugzilla: 1513323 -RH-Acked-by: Andrew Jones -RH-Acked-by: Miroslav Rezanina -RH-Acked-by: Wei Huang - -From: Fam Zheng - -Signed-off-by: Fam Zheng -Message-id: 20170905131149.10669-4-famz@redhat.com -Reviewed-by: Peter Maydell -Signed-off-by: Peter Maydell -(cherry picked from commit 9ea26c70498cde1887746222c3cada968e46ec23) -Signed-off-by: Eric Auger -Signed-off-by: Miroslav Rezanina ---- - hw/intc/arm_gicv3_its_kvm.c | 19 +++++++------------ - 1 file changed, 7 insertions(+), 12 deletions(-) - -diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c -index 1f8991b..39903d5 100644 ---- a/hw/intc/arm_gicv3_its_kvm.c -+++ b/hw/intc/arm_gicv3_its_kvm.c -@@ -120,17 +120,6 @@ static void kvm_arm_its_realize(DeviceState *dev, Error **errp) - qemu_add_vm_change_state_handler(vm_change_state_handler, s); - } - --static void kvm_arm_its_init(Object *obj) --{ -- GICv3ITSState *s = KVM_ARM_ITS(obj); -- -- object_property_add_link(obj, "parent-gicv3", -- "kvm-arm-gicv3", (Object **)&s->gicv3, -- object_property_allow_set_link, -- OBJ_PROP_LINK_UNREF_ON_RELEASE, -- &error_abort); --} -- - /** - * kvm_arm_its_pre_save - handles the saving of ITS registers. - * ITS tables are flushed into guest RAM separately and earlier, -@@ -205,12 +194,19 @@ static void kvm_arm_its_post_load(GICv3ITSState *s) - GITS_CTLR, &s->ctlr, true, &error_abort); - } - -+static Property kvm_arm_its_props[] = { -+ DEFINE_PROP_LINK("parent-gicv3", GICv3ITSState, gicv3, "kvm-arm-gicv3", -+ GICv3State *), -+ DEFINE_PROP_END_OF_LIST(), -+}; -+ - static void kvm_arm_its_class_init(ObjectClass *klass, void *data) - { - DeviceClass *dc = DEVICE_CLASS(klass); - GICv3ITSCommonClass *icc = ARM_GICV3_ITS_COMMON_CLASS(klass); - - dc->realize = kvm_arm_its_realize; -+ dc->props = kvm_arm_its_props; - icc->send_msi = kvm_its_send_msi; - icc->pre_save = kvm_arm_its_pre_save; - icc->post_load = kvm_arm_its_post_load; -@@ -220,7 +216,6 @@ static const TypeInfo kvm_arm_its_info = { - .name = TYPE_KVM_ARM_ITS, - .parent = TYPE_ARM_GICV3_ITS_COMMON, - .instance_size = sizeof(GICv3ITSState), -- .instance_init = kvm_arm_its_init, - .class_init = kvm_arm_its_class_init, - }; - --- -1.8.3.1 - diff --git a/SOURCES/kvm-hostmem-file-Add-discard-data-option.patch b/SOURCES/kvm-hostmem-file-Add-discard-data-option.patch deleted file mode 100644 index 7e5ffa2..0000000 --- a/SOURCES/kvm-hostmem-file-Add-discard-data-option.patch +++ /dev/null @@ -1,122 +0,0 @@ -From ebf96eb206cfc94a1db16f28b281fee0c56fef8c Mon Sep 17 00:00:00 2001 -From: Eduardo Habkost -Date: Thu, 19 Oct 2017 01:34:53 +0200 -Subject: [PATCH 64/69] hostmem-file: Add "discard-data" option - -RH-Author: Eduardo Habkost -Message-id: <20171019013453.21449-5-ehabkost@redhat.com> -Patchwork-id: 77370 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 4/4] hostmem-file: Add "discard-data" option -Bugzilla: 1460848 -RH-Acked-by: Michael S. Tsirkin -RH-Acked-by: Igor Mammedov -RH-Acked-by: Paolo Bonzini - -The new option can be used to indicate that the file contents can -be destroyed and don't need to be flushed to disk when QEMU exits -or when the memory backend object is removed. - -Internally, it will trigger a madvise(MADV_REMOVE) call when the -memory backend is removed. - -Signed-off-by: Eduardo Habkost -Message-Id: <20170824192315.5897-4-ehabkost@redhat.com> -[ehabkost: fixup: improved documentation] -Reviewed-by: Daniel P. Berrange -Tested-by: Zack Cornelius -Signed-off-by: Eduardo Habkost -(cherry picked from commit 11ae6ed8affdd131e735bac39b21e7d3cde66f7b) -Signed-off-by: Eduardo Habkost - -Signed-off-by: Miroslav Rezanina ---- - backends/hostmem-file.c | 29 +++++++++++++++++++++++++++++ - qemu-options.hx | 8 +++++++- - 2 files changed, 36 insertions(+), 1 deletion(-) - -diff --git a/backends/hostmem-file.c b/backends/hostmem-file.c -index fc4ef46..e44c319 100644 ---- a/backends/hostmem-file.c -+++ b/backends/hostmem-file.c -@@ -32,6 +32,7 @@ struct HostMemoryBackendFile { - HostMemoryBackend parent_obj; - - bool share; -+ bool discard_data; - char *mem_path; - }; - -@@ -103,16 +104,44 @@ static void file_memory_backend_set_share(Object *o, bool value, Error **errp) - fb->share = value; - } - -+static bool file_memory_backend_get_discard_data(Object *o, Error **errp) -+{ -+ return MEMORY_BACKEND_FILE(o)->discard_data; -+} -+ -+static void file_memory_backend_set_discard_data(Object *o, bool value, -+ Error **errp) -+{ -+ MEMORY_BACKEND_FILE(o)->discard_data = value; -+} -+ -+static void file_backend_unparent(Object *obj) -+{ -+ HostMemoryBackend *backend = MEMORY_BACKEND(obj); -+ HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(obj); -+ -+ if (host_memory_backend_mr_inited(backend) && fb->discard_data) { -+ void *ptr = memory_region_get_ram_ptr(&backend->mr); -+ uint64_t sz = memory_region_size(&backend->mr); -+ -+ qemu_madvise(ptr, sz, QEMU_MADV_REMOVE); -+ } -+} -+ - static void - file_backend_class_init(ObjectClass *oc, void *data) - { - HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc); - - bc->alloc = file_backend_memory_alloc; -+ oc->unparent = file_backend_unparent; - - object_class_property_add_bool(oc, "share", - file_memory_backend_get_share, file_memory_backend_set_share, - &error_abort); -+ object_class_property_add_bool(oc, "discard-data", -+ file_memory_backend_get_discard_data, file_memory_backend_set_discard_data, -+ &error_abort); - object_class_property_add_str(oc, "mem-path", - get_mem_path, set_mem_path, - &error_abort); -diff --git a/qemu-options.hx b/qemu-options.hx -index 5220120..50ba50e 100644 ---- a/qemu-options.hx -+++ b/qemu-options.hx -@@ -4155,7 +4155,7 @@ property must be set. These objects are placed in the - - @table @option - --@item -object memory-backend-file,id=@var{id},size=@var{size},mem-path=@var{dir},share=@var{on|off} -+@item -object memory-backend-file,id=@var{id},size=@var{size},mem-path=@var{dir},share=@var{on|off},discard-data=@var{on|off} - - Creates a memory file backend object, which can be used to back - the guest RAM with huge pages. The @option{id} parameter is a -@@ -4167,6 +4167,12 @@ the path to either a shared memory or huge page filesystem mount. - The @option{share} boolean option determines whether the memory - region is marked as private to QEMU, or shared. The latter allows - a co-operating external process to access the QEMU memory region. -+Setting the @option{discard-data} boolean option to @var{on} -+indicates that file contents can be destroyed when QEMU exits, -+to avoid unnecessarily flushing data to the backing file. Note -+that @option{discard-data} is only an optimization, and QEMU -+might not discard file contents if it aborts unexpectedly or is -+terminated using SIGKILL. - - @item -object rng-random,id=@var{id},filename=@var{/dev/random} - --- -1.8.3.1 - diff --git a/SOURCES/kvm-hostmem-file-add-the-pmem-option.patch b/SOURCES/kvm-hostmem-file-add-the-pmem-option.patch new file mode 100644 index 0000000..f495bf4 --- /dev/null +++ b/SOURCES/kvm-hostmem-file-add-the-pmem-option.patch @@ -0,0 +1,274 @@ +From 0b7c71b8b4afcbc92a9ef549d485c54da92204b3 Mon Sep 17 00:00:00 2001 +From: "plai@redhat.com" +Date: Fri, 31 Aug 2018 16:25:56 +0200 +Subject: [PATCH 14/29] hostmem-file: add the 'pmem' option + +RH-Author: plai@redhat.com +Message-id: <1535732759-22481-7-git-send-email-plai@redhat.com> +Patchwork-id: 82007 +O-Subject: [RHEL7.6 PATCH BZ 1539280 6/9] hostmem-file: add the 'pmem' option +Bugzilla: 1539280 +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Pankaj Gupta +RH-Acked-by: Miroslav Rezanina + +From: Junyan He + +When QEMU emulates vNVDIMM labels and migrates vNVDIMM devices, it +needs to know whether the backend storage is a real persistent memory, +in order to decide whether special operations should be performed to +ensure the data persistence. + +This boolean option 'pmem' allows users to specify whether the backend +storage of memory-backend-file is a real persistent memory. If +'pmem=on', QEMU will set the flag RAM_PMEM in the RAM block of the +corresponding memory region. If 'pmem' is set while lack of libpmem +support, a error is generated. + +Signed-off-by: Junyan He +Signed-off-by: Haozhong Zhang +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Igor Mammedov +Reviewed-by: Richard Henderson +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit a4de8552b2580adf6fa4874439217b65d3bdd88b) +Signed-off-by: Paul Lai + +Resolved Conflicts: + docs/nvdimm.txt + +Signed-off-by: Miroslav Rezanina +--- + backends/hostmem-file.c | 43 +++++++++++++++++++++++++++++++++++++++++-- + docs/nvdimm.txt | 42 ++++++++++++++++++++++++++++++++++++++++++ + exec.c | 8 ++++++++ + include/exec/memory.h | 4 ++++ + include/exec/ram_addr.h | 3 +++ + qemu-options.hx | 7 +++++++ + 6 files changed, 105 insertions(+), 2 deletions(-) + +diff --git a/backends/hostmem-file.c b/backends/hostmem-file.c +index 34c68bb..2476dcb 100644 +--- a/backends/hostmem-file.c ++++ b/backends/hostmem-file.c +@@ -12,6 +12,7 @@ + #include "qemu/osdep.h" + #include "qapi/error.h" + #include "qemu-common.h" ++#include "qemu/error-report.h" + #include "sysemu/hostmem.h" + #include "sysemu/sysemu.h" + #include "qom/object_interfaces.h" +@@ -31,9 +32,10 @@ typedef struct HostMemoryBackendFile HostMemoryBackendFile; + struct HostMemoryBackendFile { + HostMemoryBackend parent_obj; + +- bool discard_data; + char *mem_path; + uint64_t align; ++ bool discard_data; ++ bool is_pmem; + }; + + static void +@@ -59,7 +61,8 @@ file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp) + memory_region_init_ram_from_file(&backend->mr, OBJECT(backend), + path, + backend->size, fb->align, +- backend->share ? RAM_SHARED : 0, ++ (backend->share ? RAM_SHARED : 0) | ++ (fb->is_pmem ? RAM_PMEM : 0), + fb->mem_path, errp); + g_free(path); + } +@@ -131,6 +134,39 @@ static void file_memory_backend_set_align(Object *o, Visitor *v, + error_propagate(errp, local_err); + } + ++static bool file_memory_backend_get_pmem(Object *o, Error **errp) ++{ ++ return MEMORY_BACKEND_FILE(o)->is_pmem; ++} ++ ++static void file_memory_backend_set_pmem(Object *o, bool value, Error **errp) ++{ ++ HostMemoryBackend *backend = MEMORY_BACKEND(o); ++ HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o); ++ ++ if (host_memory_backend_mr_inited(backend)) { ++ error_setg(errp, "cannot change property 'pmem' of %s '%s'", ++ object_get_typename(o), ++ object_get_canonical_path_component(o)); ++ return; ++ } ++ ++#ifndef CONFIG_LIBPMEM ++ if (value) { ++ Error *local_err = NULL; ++ error_setg(&local_err, ++ "Lack of libpmem support while setting the 'pmem=on'" ++ " of %s '%s'. We can't ensure data persistence.", ++ object_get_typename(o), ++ object_get_canonical_path_component(o)); ++ error_propagate(errp, local_err); ++ return; ++ } ++#endif ++ ++ fb->is_pmem = value; ++} ++ + static void file_backend_unparent(Object *obj) + { + HostMemoryBackend *backend = MEMORY_BACKEND(obj); +@@ -162,6 +198,9 @@ file_backend_class_init(ObjectClass *oc, void *data) + file_memory_backend_get_align, + file_memory_backend_set_align, + NULL, NULL, &error_abort); ++ object_class_property_add_bool(oc, "pmem", ++ file_memory_backend_get_pmem, file_memory_backend_set_pmem, ++ &error_abort); + } + + static void file_backend_instance_finalize(Object *o) +diff --git a/docs/nvdimm.txt b/docs/nvdimm.txt +index e903d8b..5f158a6 100644 +--- a/docs/nvdimm.txt ++++ b/docs/nvdimm.txt +@@ -153,3 +153,45 @@ guest NVDIMM region mapping structure. This unarmed flag indicates + guest software that this vNVDIMM device contains a region that cannot + accept persistent writes. In result, for example, the guest Linux + NVDIMM driver, marks such vNVDIMM device as read-only. ++ ++NVDIMM Persistence ++------------------ ++ ++ACPI 6.2 Errata A added support for a new Platform Capabilities Structure ++which allows the platform to communicate what features it supports related to ++NVDIMM data persistence. Users can provide a persistence value to a guest via ++the optional "nvdimm-persistence" machine command line option: ++ ++ -machine pc,accel=kvm,nvdimm,nvdimm-persistence=cpu ++ ++There are currently two valid values for this option: ++ ++"mem-ctrl" - The platform supports flushing dirty data from the memory ++ controller to the NVDIMMs in the event of power loss. ++ ++"cpu" - The platform supports flushing dirty data from the CPU cache to ++ the NVDIMMs in the event of power loss. This implies that the ++ platform also supports flushing dirty data through the memory ++ controller on power loss. ++ ++If the vNVDIMM backend is in host persistent memory that can be accessed in ++SNIA NVM Programming Model [1] (e.g., Intel NVDIMM), it's suggested to set ++the 'pmem' option of memory-backend-file to 'on'. When 'pmem' is 'on' and QEMU ++is built with libpmem [2] support (configured with --enable-libpmem), QEMU ++will take necessary operations to guarantee the persistence of its own writes ++to the vNVDIMM backend(e.g., in vNVDIMM label emulation and live migration). ++If 'pmem' is 'on' while there is no libpmem support, qemu will exit and report ++a "lack of libpmem support" message to ensure the persistence is available. ++For example, if we want to ensure the persistence for some backend file, ++use the QEMU command line: ++ ++ -object memory-backend-file,id=nv_mem,mem-path=/XXX/yyy,size=4G,pmem=on ++ ++References ++---------- ++ ++[1] NVM Programming Model (NPM) ++ Version 1.2 ++ https://www.snia.org/sites/default/files/technical_work/final/NVMProgrammingModel_v1.2.pdf ++[2] Persistent Memory Development Kit (PMDK), formerly known as NVML project, home page: ++ http://pmem.io/pmdk/ +diff --git a/exec.c b/exec.c +index 295142b..c670185 100644 +--- a/exec.c ++++ b/exec.c +@@ -2045,6 +2045,9 @@ RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr, + Error *local_err = NULL; + int64_t file_size; + ++ /* Just support these ram flags by now. */ ++ assert((ram_flags & ~(RAM_SHARED | RAM_PMEM)) == 0); ++ + if (xen_enabled()) { + error_setg(errp, "-mem-path not supported with Xen"); + return NULL; +@@ -3863,6 +3866,11 @@ err: + return ret; + } + ++bool ramblock_is_pmem(RAMBlock *rb) ++{ ++ return rb->flags & RAM_PMEM; ++} ++ + #endif + + void page_size_init(void) +diff --git a/include/exec/memory.h b/include/exec/memory.h +index b3abe61..fd2c574 100644 +--- a/include/exec/memory.h ++++ b/include/exec/memory.h +@@ -122,6 +122,9 @@ typedef struct IOMMUNotifier IOMMUNotifier; + /* RAM can be migrated */ + #define RAM_MIGRATABLE (1 << 4) + ++/* RAM is a persistent kind memory */ ++#define RAM_PMEM (1 << 5) ++ + static inline void iommu_notifier_init(IOMMUNotifier *n, IOMMUNotify fn, + IOMMUNotifierFlag flags, + hwaddr start, hwaddr end) +@@ -541,6 +544,7 @@ void memory_region_init_resizeable_ram(MemoryRegion *mr, + * (getpagesize()) will be used. + * @ram_flags: Memory region features: + * - RAM_SHARED: memory must be mmaped with the MAP_SHARED flag ++ * - RAM_PMEM: the memory is persistent memory + * Other bits are ignored now. + * @path: the path in which to allocate the RAM. + * @errp: pointer to Error*, to store an error if it happens. +diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h +index 67e163e..922305d 100644 +--- a/include/exec/ram_addr.h ++++ b/include/exec/ram_addr.h +@@ -70,6 +70,8 @@ static inline unsigned long int ramblock_recv_bitmap_offset(void *host_addr, + return host_addr_offset >> TARGET_PAGE_BITS; + } + ++bool ramblock_is_pmem(RAMBlock *rb); ++ + long qemu_getrampagesize(void); + unsigned long last_ram_page(void); + +@@ -84,6 +86,7 @@ unsigned long last_ram_page(void); + * @ram_flags: specify the properties of the ram block, which can be one + * or bit-or of following values + * - RAM_SHARED: mmap the backing file or device with MAP_SHARED ++ * - RAM_PMEM: the backend @mem_path or @fd is persistent memory + * Other bits are ignored. + * @mem_path or @fd: specify the backing file or device + * @errp: pointer to Error*, to store an error if it happens +diff --git a/qemu-options.hx b/qemu-options.hx +index 4271cd3..5c58760 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -4045,6 +4045,13 @@ requires an alignment different than the default one used by QEMU, eg + the device DAX /dev/dax0.0 requires 2M alignment rather than 4K. In + such cases, users can specify the required alignment via this option. + ++The @option{pmem} option specifies whether the backing file specified ++by @option{mem-path} is in host persistent memory that can be accessed ++using the SNIA NVM programming model (e.g. Intel NVDIMM). ++If @option{pmem} is set to 'on', QEMU will take necessary operations to ++guarantee the persistence of its own writes to @option{mem-path} ++(e.g. in vNVDIMM label emulation and live migration). ++ + @item -object memory-backend-ram,id=@var{id},merge=@var{on|off},dump=@var{on|off},share=@var{on|off},prealloc=@var{on|off},size=@var{size},host-nodes=@var{host-nodes},policy=@var{default|preferred|bind|interleave} + + Creates a memory backend object, which can be used to back the guest RAM. +-- +1.8.3.1 + diff --git a/SOURCES/kvm-hw-Remove-the-redundant-user_creatable-false-from-SY.patch b/SOURCES/kvm-hw-Remove-the-redundant-user_creatable-false-from-SY.patch deleted file mode 100644 index 71baf41..0000000 --- a/SOURCES/kvm-hw-Remove-the-redundant-user_creatable-false-from-SY.patch +++ /dev/null @@ -1,93 +0,0 @@ -From e6c4563d68a353e9b3938c9f49a239b5dca61868 Mon Sep 17 00:00:00 2001 -From: Thomas Huth -Date: Thu, 19 Oct 2017 10:16:49 +0200 -Subject: [PATCH 67/69] hw: Remove the redundant user_creatable = false from - SYS_BUS_DEVICEs - -RH-Author: Thomas Huth -Message-id: <1508408209-5712-4-git-send-email-thuth@redhat.com> -Patchwork-id: 77375 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 3/3] hw: Remove the redundant user_creatable = false from SYS_BUS_DEVICEs -Bugzilla: 1503998 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Cornelia Huck -RH-Acked-by: Eduardo Habkost - -The devices that are addressed by this patch are SYS_BUS_DEVICE, and -in QEMU 2.10, sysbus devices are marked with user_creatable = false by -default already. So there is now no need anymore to explicitely set -this flag to false in the downstream qemu-kvm build. - -Signed-off-by: Thomas Huth -Signed-off-by: Miroslav Rezanina ---- - hw/block/pflash_cfi01.c | 1 - - hw/i386/kvm/clock.c | 1 - - hw/ide/ahci.c | 1 - - hw/isa/isa-bus.c | 1 - - hw/virtio/virtio-mmio.c | 1 - - 5 files changed, 5 deletions(-) - -diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c -index afe6230..1113ab1 100644 ---- a/hw/block/pflash_cfi01.c -+++ b/hw/block/pflash_cfi01.c -@@ -925,7 +925,6 @@ static void pflash_cfi01_class_init(ObjectClass *klass, void *data) - dc->realize = pflash_cfi01_realize; - dc->props = pflash_cfi01_properties; - dc->vmsd = &vmstate_pflash; -- dc->user_creatable = false; /* RH state preserve */ - set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); - } - -diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c -index fc7212f..363d1b5 100644 ---- a/hw/i386/kvm/clock.c -+++ b/hw/i386/kvm/clock.c -@@ -289,7 +289,6 @@ static void kvmclock_class_init(ObjectClass *klass, void *data) - dc->realize = kvmclock_realize; - dc->vmsd = &kvmclock_vmsd; - dc->props = kvmclock_properties; -- dc->user_creatable = false; /* RH state preserve */ - } - - static const TypeInfo kvmclock_info = { -diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c -index 2cb41fc..da6c23d 100644 ---- a/hw/ide/ahci.c -+++ b/hw/ide/ahci.c -@@ -1720,7 +1720,6 @@ static void sysbus_ahci_class_init(ObjectClass *klass, void *data) - dc->vmsd = &vmstate_sysbus_ahci; - dc->props = sysbus_ahci_properties; - dc->reset = sysbus_ahci_reset; -- dc->user_creatable = false; /* RH state preserve */ - set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); - } - -diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c -index 467042f..348e0ea 100644 ---- a/hw/isa/isa-bus.c -+++ b/hw/isa/isa-bus.c -@@ -221,7 +221,6 @@ static void isabus_bridge_class_init(ObjectClass *klass, void *data) - - set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); - dc->fw_name = "isa"; -- dc->user_creatable = false; /* RH state preserve */ - } - - static const TypeInfo isabus_bridge_info = { -diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c -index 62df6c2..5807aa8 100644 ---- a/hw/virtio/virtio-mmio.c -+++ b/hw/virtio/virtio-mmio.c -@@ -448,7 +448,6 @@ static void virtio_mmio_class_init(ObjectClass *klass, void *data) - - dc->realize = virtio_mmio_realizefn; - dc->reset = virtio_mmio_reset; -- dc->user_creatable = false; /* RH state preserve */ - set_bit(DEVICE_CATEGORY_MISC, dc->categories); - dc->props = virtio_mmio_properties; - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-acpi-Move-acpi_set_pci_info-to-pcihp.patch b/SOURCES/kvm-hw-acpi-Move-acpi_set_pci_info-to-pcihp.patch deleted file mode 100644 index 1def82e..0000000 --- a/SOURCES/kvm-hw-acpi-Move-acpi_set_pci_info-to-pcihp.patch +++ /dev/null @@ -1,202 +0,0 @@ -From acb06b5ca2ea9f30a7b14c34674b930f0e8a1a60 Mon Sep 17 00:00:00 2001 -From: Marcel Apfelbaum -Date: Tue, 16 Jan 2018 14:15:34 +0100 -Subject: [PATCH 02/21] hw/acpi: Move acpi_set_pci_info to pcihp - -RH-Author: Marcel Apfelbaum -Message-id: <20180116141534.100478-1-marcel@redhat.com> -Patchwork-id: 78628 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH V2] hw/acpi: Move acpi_set_pci_info to pcihp -Bugzilla: 1507693 -RH-Acked-by: Igor Mammedov -RH-Acked-by: Michael S. Tsirkin -RH-Acked-by: Laszlo Ersek - -From: Anthony PERARD - -RHEL Note: - rhel6 machine types don't generate their ACPI payload - (pcmc->has_acpi_build = false), SeaBIOS does it for them - (m->default_machine_opts = "firmware=bios.bin"). In turn, before the - patch, these machine types never call acpi_setup() -> - acpi_set_pci_info(), and never set BSEL. After the patch, BSEL is set in - all i440fx-based machine types, via piix4_reset() -> acpi_pcihp_reset() - -> acpi_set_pci_info(). - -HW part of ACPI PCI hotplug in QEMU depends on ACPI_PCIHP_PROP_BSEL -being set on a PCI bus that supports ACPI hotplug. It should work -regardless of the source of ACPI tables (QEMU generator/legacy SeaBIOS/Xen). -So move ACPI_PCIHP_PROP_BSEL initialization into HW ACPI implementation -part from QEMU's ACPI table generator. - -To do PCI passthrough with Xen, the property ACPI_PCIHP_PROP_BSEL needs -to be set, but this was done only when ACPI tables are built which is -not needed for a Xen guest. The need for the property starts with commit -"pc: pcihp: avoid adding ACPI_PCIHP_PROP_BSEL twice" -(f0c9d64a68b776374ec4732424a3e27753ce37b6). - -Adding find_i440fx into stubs so that mips-softmmu target can be built. - -Reported-by: Sander Eikelenboom -Signed-off-by: Anthony PERARD -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit ab938ae43f8a3a71a3525566edf586081b7a7452) -Signed-off-by: Marcel Apfelbaum - - Conflicts: - stubs/Makefile.objs - (some stubs were added before it) - -Signed-off-by: Marcel Apfelbaum ---- - -V1 -> V2: - Added the RHEL Note (Laszlo) - - hw/acpi/pcihp.c | 38 ++++++++++++++++++++++++++++++++++++++ - hw/i386/acpi-build.c | 32 -------------------------------- - stubs/Makefile.objs | 1 + - stubs/pci-host-piix.c | 6 ++++++ - 4 files changed, 45 insertions(+), 32 deletions(-) - create mode 100644 stubs/pci-host-piix.c - -Signed-off-by: Miroslav Rezanina ---- - hw/acpi/pcihp.c | 38 ++++++++++++++++++++++++++++++++++++++ - hw/i386/acpi-build.c | 32 -------------------------------- - stubs/Makefile.objs | 1 + - stubs/pci-host-piix.c | 6 ++++++ - 4 files changed, 45 insertions(+), 32 deletions(-) - create mode 100644 stubs/pci-host-piix.c - -diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c -index c420a38..9ad5edc 100644 ---- a/hw/acpi/pcihp.c -+++ b/hw/acpi/pcihp.c -@@ -75,6 +75,43 @@ static int acpi_pcihp_get_bsel(PCIBus *bus) - } - } - -+/* Assign BSEL property to all buses. In the future, this can be changed -+ * to only assign to buses that support hotplug. -+ */ -+static void *acpi_set_bsel(PCIBus *bus, void *opaque) -+{ -+ unsigned *bsel_alloc = opaque; -+ unsigned *bus_bsel; -+ -+ if (qbus_is_hotpluggable(BUS(bus))) { -+ bus_bsel = g_malloc(sizeof *bus_bsel); -+ -+ *bus_bsel = (*bsel_alloc)++; -+ object_property_add_uint32_ptr(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, -+ bus_bsel, &error_abort); -+ } -+ -+ return bsel_alloc; -+} -+ -+static void acpi_set_pci_info(void) -+{ -+ static bool bsel_is_set; -+ PCIBus *bus; -+ unsigned bsel_alloc = ACPI_PCIHP_BSEL_DEFAULT; -+ -+ if (bsel_is_set) { -+ return; -+ } -+ bsel_is_set = true; -+ -+ bus = find_i440fx(); /* TODO: Q35 support */ -+ if (bus) { -+ /* Scan all PCI buses. Set property to enable acpi based hotplug. */ -+ pci_for_each_bus_depth_first(bus, acpi_set_bsel, NULL, &bsel_alloc); -+ } -+} -+ - static void acpi_pcihp_test_hotplug_bus(PCIBus *bus, void *opaque) - { - AcpiPciHpFind *find = opaque; -@@ -177,6 +214,7 @@ static void acpi_pcihp_update(AcpiPciHpState *s) - - void acpi_pcihp_reset(AcpiPciHpState *s) - { -+ acpi_set_pci_info(); - acpi_pcihp_update(s); - } - -diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c -index a61560f..8117321 100644 ---- a/hw/i386/acpi-build.c -+++ b/hw/i386/acpi-build.c -@@ -495,36 +495,6 @@ build_madt(GArray *table_data, BIOSLinker *linker, PCMachineState *pcms) - table_data->len - madt_start, 1, NULL, NULL); - } - --/* Assign BSEL property to all buses. In the future, this can be changed -- * to only assign to buses that support hotplug. -- */ --static void *acpi_set_bsel(PCIBus *bus, void *opaque) --{ -- unsigned *bsel_alloc = opaque; -- unsigned *bus_bsel; -- -- if (qbus_is_hotpluggable(BUS(bus))) { -- bus_bsel = g_malloc(sizeof *bus_bsel); -- -- *bus_bsel = (*bsel_alloc)++; -- object_property_add_uint32_ptr(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, -- bus_bsel, &error_abort); -- } -- -- return bsel_alloc; --} -- --static void acpi_set_pci_info(void) --{ -- PCIBus *bus = find_i440fx(); /* TODO: Q35 support */ -- unsigned bsel_alloc = ACPI_PCIHP_BSEL_DEFAULT; -- -- if (bus) { -- /* Scan all PCI buses. Set property to enable acpi based hotplug. */ -- pci_for_each_bus_depth_first(bus, acpi_set_bsel, NULL, &bsel_alloc); -- } --} -- - static void build_append_pcihp_notify_entry(Aml *method, int slot) - { - Aml *if_ctx; -@@ -2890,8 +2860,6 @@ void acpi_setup(void) - - build_state = g_malloc0(sizeof *build_state); - -- acpi_set_pci_info(); -- - acpi_build_tables_init(&tables); - acpi_build(&tables, MACHINE(pcms)); - -diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs -index 7e9f94d..e3b9e6b 100644 ---- a/stubs/Makefile.objs -+++ b/stubs/Makefile.objs -@@ -42,3 +42,4 @@ stub-obj-y += xen-common.o - stub-obj-y += xen-hvm.o - stub-obj-y += shadow-bios.o - stub-obj-y += ide-isa.o -+stub-obj-y += pci-host-piix.o -diff --git a/stubs/pci-host-piix.c b/stubs/pci-host-piix.c -new file mode 100644 -index 0000000..6ed81b1 ---- /dev/null -+++ b/stubs/pci-host-piix.c -@@ -0,0 +1,6 @@ -+#include "qemu/osdep.h" -+#include "hw/i386/pc.h" -+PCIBus *find_i440fx(void) -+{ -+ return NULL; -+} --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-arm-virt-Set-INTx-gsi-mapping.patch b/SOURCES/kvm-hw-arm-virt-Set-INTx-gsi-mapping.patch deleted file mode 100644 index 42aa525..0000000 --- a/SOURCES/kvm-hw-arm-virt-Set-INTx-gsi-mapping.patch +++ /dev/null @@ -1,48 +0,0 @@ -From fe6e65efe39932521b861b4de358a9b73d2ac4cf Mon Sep 17 00:00:00 2001 -From: Auger Eric -Date: Mon, 6 Nov 2017 17:08:43 +0100 -Subject: [PATCH 7/9] hw/arm/virt: Set INTx/gsi mapping - -RH-Author: Auger Eric -Message-id: <1509988125-30275-3-git-send-email-eric.auger@redhat.com> -Patchwork-id: 77508 -O-Subject: [RHV7.5 qemu-kvm-ma PATCH 2/4] hw/arm/virt: Set INTx/gsi mapping -Bugzilla: 1460957 -RH-Acked-by: Alex Williamson -RH-Acked-by: Laurent Vivier -RH-Acked-by: Miroslav Rezanina - -From: Pranavkumar Sawargaonkar - -Let's provide the GPEX host bridge with the INTx/gsi mapping. This is -needed for INTx/gsi routing. - -Signed-off-by: Pranavkumar Sawargaonkar -Signed-off-by: Tushar Jagad -Signed-off-by: Eric Auger -Reviewed-by: Andrew Jones -Tested-by: Feng Kan -Message-id: 1505296004-6798-3-git-send-email-eric.auger@redhat.com -Signed-off-by: Peter Maydell -(cherry picked from commit c9bb8e16080d189a0c393a1061b427993516ae2b) -Signed-off-by: Eric Auger -Signed-off-by: Miroslav Rezanina ---- - hw/arm/virt.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/hw/arm/virt.c b/hw/arm/virt.c -index f243536..b175e36 100644 ---- a/hw/arm/virt.c -+++ b/hw/arm/virt.c -@@ -1079,6 +1079,7 @@ static void create_pcie(const VirtMachineState *vms, qemu_irq *pic) - - for (i = 0; i < GPEX_NUM_IRQS; i++) { - sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]); -+ gpex_set_irq_num(GPEX_HOST(dev), i, irq + i); - } - - pci = PCI_HOST_BRIDGE(dev); --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-char-serial-Only-retry-if-qemu_chr_fe_write-retur.patch b/SOURCES/kvm-hw-char-serial-Only-retry-if-qemu_chr_fe_write-retur.patch new file mode 100644 index 0000000..2ae2575 --- /dev/null +++ b/SOURCES/kvm-hw-char-serial-Only-retry-if-qemu_chr_fe_write-retur.patch @@ -0,0 +1,59 @@ +From a7a6995e2a24e9e4c89084acf3241e5640f30f3e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Fri, 20 Jul 2018 12:17:59 +0200 +Subject: [PATCH 87/89] hw/char/serial: Only retry if qemu_chr_fe_write returns + 0 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20180720121800.18952-2-marcandre.lureau@redhat.com> +Patchwork-id: 81454 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v2 1/2] hw/char/serial: Only retry if qemu_chr_fe_write returns 0 +Bugzilla: 1592817 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Markus Armbruster +RH-Acked-by: John Snow + +From: Sergio Lopez + +Only retry on serial_xmit if qemu_chr_fe_write returns 0, as this is the +only recoverable error. + +Retrying with any other scenario, in addition to being a waste of CPU +cycles, can compromise the Guest stability if by the vCPU issuing the +write and the main loop thread are, by chance or explicit pinning, +running on the same pCPU. + +Previous discussion: + +https://lists.nongnu.org/archive/html/qemu-devel/2018-05/msg06998.html + +Signed-off-by: Sergio Lopez +Message-Id: <1528185295-14199-1-git-send-email-slp@redhat.com> +Signed-off-by: Paolo Bonzini + +(cherry picked from commit 019288bf137183bf3407c9824655b753bfafc99f) +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + hw/char/serial.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/char/serial.c b/hw/char/serial.c +index d6d9b18..d4057bf 100644 +--- a/hw/char/serial.c ++++ b/hw/char/serial.c +@@ -262,7 +262,7 @@ static void serial_xmit(SerialState *s) + if (s->mcr & UART_MCR_LOOP) { + /* in loopback mode, say that we just received a char */ + serial_receive1(s, &s->tsr, 1); +- } else if (qemu_chr_fe_write(&s->chr, &s->tsr, 1) != 1 && ++ } else if (qemu_chr_fe_write(&s->chr, &s->tsr, 1) == 0 && + s->tsr_retry < MAX_XMIT_RETRY) { + assert(s->watch_tag == 0); + s->watch_tag = +-- +1.8.3.1 + diff --git a/SOURCES/kvm-hw-char-serial-retry-write-if-EAGAIN.patch b/SOURCES/kvm-hw-char-serial-retry-write-if-EAGAIN.patch new file mode 100644 index 0000000..222ee98 --- /dev/null +++ b/SOURCES/kvm-hw-char-serial-retry-write-if-EAGAIN.patch @@ -0,0 +1,72 @@ +From d357e5f3a56416c6f5a7a9308b8c30f825d89cfa Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Fri, 20 Jul 2018 12:18:00 +0200 +Subject: [PATCH 88/89] hw/char/serial: retry write if EAGAIN +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20180720121800.18952-3-marcandre.lureau@redhat.com> +Patchwork-id: 81455 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v2 2/2] hw/char/serial: retry write if EAGAIN +Bugzilla: 1592817 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Markus Armbruster +RH-Acked-by: John Snow + +If the chardev returns -1 with EAGAIN errno on write(), it should try +to send it again (EINTR is handled by the chardev itself). + +This fixes commit 019288bf137183bf3407c9824655b753bfafc99f +"hw/char/serial: Only retry if qemu_chr_fe_write returns 0" + +Tested-by: Igor Mammedov +Signed-off-by: Marc-André Lureau +Message-Id: <20180716110755.12499-1-marcandre.lureau@redhat.com> +Signed-off-by: Paolo Bonzini + +(cherry picked from commit f3575af130c700cea060b51a89008a76dae22259) +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + hw/char/serial.c | 23 ++++++++++++++--------- + 1 file changed, 14 insertions(+), 9 deletions(-) + +diff --git a/hw/char/serial.c b/hw/char/serial.c +index d4057bf..478f9a8 100644 +--- a/hw/char/serial.c ++++ b/hw/char/serial.c +@@ -262,15 +262,20 @@ static void serial_xmit(SerialState *s) + if (s->mcr & UART_MCR_LOOP) { + /* in loopback mode, say that we just received a char */ + serial_receive1(s, &s->tsr, 1); +- } else if (qemu_chr_fe_write(&s->chr, &s->tsr, 1) == 0 && +- s->tsr_retry < MAX_XMIT_RETRY) { +- assert(s->watch_tag == 0); +- s->watch_tag = +- qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP, +- serial_watch_cb, s); +- if (s->watch_tag > 0) { +- s->tsr_retry++; +- return; ++ } else { ++ int rc = qemu_chr_fe_write(&s->chr, &s->tsr, 1); ++ ++ if ((rc == 0 || ++ (rc == -1 && errno == EAGAIN)) && ++ s->tsr_retry < MAX_XMIT_RETRY) { ++ assert(s->watch_tag == 0); ++ s->watch_tag = ++ qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP, ++ serial_watch_cb, s); ++ if (s->watch_tag > 0) { ++ s->tsr_retry++; ++ return; ++ } + } + } + s->tsr_retry = 0; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-hw-dma-i8257-Remove-redundant-downstream-user_creata.patch b/SOURCES/kvm-hw-dma-i8257-Remove-redundant-downstream-user_creata.patch deleted file mode 100644 index 489e513..0000000 --- a/SOURCES/kvm-hw-dma-i8257-Remove-redundant-downstream-user_creata.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 374294de467ebc115e70f0804e98081753d51c3b Mon Sep 17 00:00:00 2001 -From: Thomas Huth -Date: Thu, 19 Oct 2017 10:16:47 +0200 -Subject: [PATCH 65/69] hw/dma/i8257: Remove redundant downstream - user_creatable = false - -RH-Author: Thomas Huth -Message-id: <1508408209-5712-2-git-send-email-thuth@redhat.com> -Patchwork-id: 77372 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 1/3] hw/dma/i8257: Remove redundant downstream user_creatable = false -Bugzilla: 1503998 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Cornelia Huck -RH-Acked-by: Eduardo Habkost - -The i8257_class_init() function has already user_creatable = false -at the end of the function in the upstream code, so there is no -need to set this again with downstream-only code. - -Signed-off-by: Thomas Huth -Signed-off-by: Miroslav Rezanina ---- - hw/dma/i8257.c | 2 -- - 1 file changed, 2 deletions(-) - -diff --git a/hw/dma/i8257.c b/hw/dma/i8257.c -index e52a679..bd23e89 100644 ---- a/hw/dma/i8257.c -+++ b/hw/dma/i8257.c -@@ -591,8 +591,6 @@ static void i8257_class_init(ObjectClass *klass, void *data) - dc->reset = i8257_reset; - dc->vmsd = &vmstate_i8257; - dc->props = i8257_properties; -- /* Disabled for Red Hat Enterprise Linux: */ -- dc->user_creatable = false; - - idc->get_transfer_mode = i8257_dma_get_transfer_mode; - idc->has_autoinitialization = i8257_dma_has_autoinitialization; --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-gen_pcie_root_port-make-IO-RO-0-on-IO-disabled.patch b/SOURCES/kvm-hw-gen_pcie_root_port-make-IO-RO-0-on-IO-disabled.patch deleted file mode 100644 index 73a8cd9..0000000 --- a/SOURCES/kvm-hw-gen_pcie_root_port-make-IO-RO-0-on-IO-disabled.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 7802df183a0b1f457c97e6f920e720f6fef36a18 Mon Sep 17 00:00:00 2001 -From: Marcel Apfelbaum -Date: Mon, 13 Nov 2017 19:03:30 +0100 -Subject: [PATCH 04/30] hw/gen_pcie_root_port: make IO RO 0 on IO disabled - -RH-Author: Marcel Apfelbaum -Message-id: <20171113190330.57188-1-marcel@redhat.com> -Patchwork-id: 77666 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH] hw/gen_pcie_root_port: make IO RO 0 on IO disabled -Bugzilla: 1344299 -RH-Acked-by: Michael S. Tsirkin -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Dr. David Alan Gilbert - -IO_LIMIT and IO_BASE registers should not be writable if -gen_pcie_root_port's io-reserve property is set to 0. -The COMMAND register should have the IO flag read only. - -Signed-off-by: Marcel Apfelbaum -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 8e36c336d943c3bfe0d06f5465cc64d44b306e13) -Signed-off-by: Marcel Apfelbaum -Signed-off-by: Miroslav Rezanina ---- - hw/pci-bridge/gen_pcie_root_port.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/hw/pci-bridge/gen_pcie_root_port.c b/hw/pci-bridge/gen_pcie_root_port.c -index ed03ffc..ad4e6aa 100644 ---- a/hw/pci-bridge/gen_pcie_root_port.c -+++ b/hw/pci-bridge/gen_pcie_root_port.c -@@ -85,6 +85,13 @@ static void gen_rp_realize(DeviceState *dev, Error **errp) - rpc->parent_class.exit(d); - return; - } -+ -+ if (!grp->io_reserve) { -+ pci_word_test_and_clear_mask(d->wmask + PCI_COMMAND, -+ PCI_COMMAND_IO); -+ d->wmask[PCI_IO_BASE] = 0; -+ d->wmask[PCI_IO_LIMIT] = 0; -+ } - } - - static const VMStateDescription vmstate_rp_dev = { --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-intc-arm_gicv3_its-Don-t-abort-on-table-save-fail.patch b/SOURCES/kvm-hw-intc-arm_gicv3_its-Don-t-abort-on-table-save-fail.patch deleted file mode 100644 index 4459ae0..0000000 --- a/SOURCES/kvm-hw-intc-arm_gicv3_its-Don-t-abort-on-table-save-fail.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 3e611f18f7a3d0a76c07f822e6190a79c09f82e7 Mon Sep 17 00:00:00 2001 -From: Auger Eric -Date: Tue, 28 Nov 2017 15:14:04 +0100 -Subject: [PATCH 3/9] hw/intc/arm_gicv3_its: Don't abort on table save failure - -RH-Author: Auger Eric -Message-id: <1511882048-11256-4-git-send-email-eric.auger@redhat.com> -Patchwork-id: 77940 -O-Subject: [RHV7.5 qemu-kvm-ma PATCH 3/7] hw/intc/arm_gicv3_its: Don't abort on table save failure -Bugzilla: 1513323 -RH-Acked-by: Andrew Jones -RH-Acked-by: Miroslav Rezanina -RH-Acked-by: Wei Huang - -The ITS is not fully properly reset at the moment. Caches are -not emptied. - -After a reset, in case we attempt to save the state before -the bound devices have registered their MSIs and after the -1st level table has been allocated by the ITS driver -(device BASER is valid), the first level entries are still -invalid. If the device cache is not empty (devices registered -before the reset), vgic_its_save_device_tables fails with -EINVAL. -This causes a QEMU abort(). - -Cc: qemu-stable@nongnu.org -Signed-off-by: Eric Auger -Reported-by: wanghaibin -Reviewed-by: Peter Maydell -Signed-off-by: Peter Maydell -(cherry picked from commit 8a7348b5d62d7ea16807e6bea54b448a0184bb0f) -Signed-off-by: Eric Auger -Signed-off-by: Miroslav Rezanina ---- - hw/intc/arm_gicv3_its_kvm.c | 8 ++------ - 1 file changed, 2 insertions(+), 6 deletions(-) - -diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c -index 9b00ce5..6fb45df 100644 ---- a/hw/intc/arm_gicv3_its_kvm.c -+++ b/hw/intc/arm_gicv3_its_kvm.c -@@ -64,20 +64,16 @@ static void vm_change_state_handler(void *opaque, int running, - { - GICv3ITSState *s = (GICv3ITSState *)opaque; - Error *err = NULL; -- int ret; - - if (running) { - return; - } - -- ret = kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, -- KVM_DEV_ARM_ITS_SAVE_TABLES, NULL, true, &err); -+ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, -+ KVM_DEV_ARM_ITS_SAVE_TABLES, NULL, true, &err); - if (err) { - error_report_err(err); - } -- if (ret < 0 && ret != -EFAULT) { -- abort(); -- } - } - - static void kvm_arm_its_realize(DeviceState *dev, Error **errp) --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-intc-arm_gicv3_its-Don-t-call-post_load-on-reset.patch b/SOURCES/kvm-hw-intc-arm_gicv3_its-Don-t-call-post_load-on-reset.patch deleted file mode 100644 index 1c9e871..0000000 --- a/SOURCES/kvm-hw-intc-arm_gicv3_its-Don-t-call-post_load-on-reset.patch +++ /dev/null @@ -1,65 +0,0 @@ -From c63efdd05d3c8c79fceba7bb55c4946685e2a191 Mon Sep 17 00:00:00 2001 -From: Auger Eric -Date: Tue, 28 Nov 2017 15:14:05 +0100 -Subject: [PATCH 4/9] hw/intc/arm_gicv3_its: Don't call post_load on reset - -RH-Author: Auger Eric -Message-id: <1511882048-11256-5-git-send-email-eric.auger@redhat.com> -Patchwork-id: 77941 -O-Subject: [RHV7.5 qemu-kvm-ma PATCH 4/7] hw/intc/arm_gicv3_its: Don't call post_load on reset -Bugzilla: 1513323 -RH-Acked-by: Andrew Jones -RH-Acked-by: Miroslav Rezanina -RH-Acked-by: Wei Huang - ->From the very beginning, post_load() was called from common -reset. This is not standard and obliged to discriminate the -reset case from the restore case using the iidr value. - -Let's get rid of that call. - -Signed-off-by: Eric Auger -Reviewed-by: Peter Maydell - ---- - -v4 -> V5: -- added Peter's R-b - -Signed-off-by: Miroslav Rezanina ---- - hw/intc/arm_gicv3_its_common.c | 2 -- - hw/intc/arm_gicv3_its_kvm.c | 4 ---- - 2 files changed, 6 deletions(-) - -diff --git a/hw/intc/arm_gicv3_its_common.c b/hw/intc/arm_gicv3_its_common.c -index 68b20fc..a029e3c 100644 ---- a/hw/intc/arm_gicv3_its_common.c -+++ b/hw/intc/arm_gicv3_its_common.c -@@ -129,8 +129,6 @@ static void gicv3_its_common_reset(DeviceState *dev) - s->creadr = 0; - s->iidr = 0; - memset(&s->baser, 0, sizeof(s->baser)); -- -- gicv3_its_post_load(s, 0); - } - - static void gicv3_its_common_class_init(ObjectClass *klass, void *data) -diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c -index 6fb45df..b1b322b 100644 ---- a/hw/intc/arm_gicv3_its_kvm.c -+++ b/hw/intc/arm_gicv3_its_kvm.c -@@ -155,10 +155,6 @@ static void kvm_arm_its_post_load(GICv3ITSState *s) - { - int i; - -- if (!s->iidr) { -- return; -- } -- - kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, - GITS_IIDR, &s->iidr, true, &error_abort); - --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-intc-arm_gicv3_its-Fix-the-VM-termination-in-vm_c.patch b/SOURCES/kvm-hw-intc-arm_gicv3_its-Fix-the-VM-termination-in-vm_c.patch deleted file mode 100644 index 8cdf9b4..0000000 --- a/SOURCES/kvm-hw-intc-arm_gicv3_its-Fix-the-VM-termination-in-vm_c.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 1bc2106857269cd428567fed2f8afedd25c2c288 Mon Sep 17 00:00:00 2001 -From: Auger Eric -Date: Tue, 28 Nov 2017 15:14:03 +0100 -Subject: [PATCH 2/9] hw/intc/arm_gicv3_its: Fix the VM termination in - vm_change_state_handler() - -RH-Author: Auger Eric -Message-id: <1511882048-11256-3-git-send-email-eric.auger@redhat.com> -Patchwork-id: 77937 -O-Subject: [RHV7.5 qemu-kvm-ma PATCH 2/7] hw/intc/arm_gicv3_its: Fix the VM termination in vm_change_state_handler() -Bugzilla: 1513323 -RH-Acked-by: Andrew Jones -RH-Acked-by: Miroslav Rezanina -RH-Acked-by: Wei Huang - -From: Shanker Donthineni - -The commit cddafd8f353d ("hw/intc/arm_gicv3_its: Implement state save -/restore") breaks the backward compatibility with the older kernels -where vITS save/restore support is not available. The vmstate function -vm_change_state_handler() should not be registered if the running kernel -doesn't support ITS save/restore feature. Otherwise VM instance will be -killed whenever vmstate callback function is invoked. - -Observed a virtual machine shutdown with QEMU-2.10+linux-4.11 when testing -the reboot command "virsh reboot --mode acpi" instead of reboot. - -KVM Error: 'KVM_SET_DEVICE_ATTR failed: Group 4 attr 0x00000000000001' - -Signed-off-by: Shanker Donthineni -Reviewed-by: Eric Auger -Message-id: 1509712671-16299-1-git-send-email-shankerd@codeaurora.org -Signed-off-by: Peter Maydell -(cherry picked from commit 3a575cd2c2411f139a95ace4b2523bc1dfd21755) -Signed-off-by: Eric Auger -Signed-off-by: Miroslav Rezanina ---- - hw/intc/arm_gicv3_its_kvm.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c -index 39903d5..9b00ce5 100644 ---- a/hw/intc/arm_gicv3_its_kvm.c -+++ b/hw/intc/arm_gicv3_its_kvm.c -@@ -111,13 +111,13 @@ static void kvm_arm_its_realize(DeviceState *dev, Error **errp) - error_free(s->migration_blocker); - return; - } -+ } else { -+ qemu_add_vm_change_state_handler(vm_change_state_handler, s); - } - - kvm_msi_use_devid = true; - kvm_gsi_direct_mapping = false; - kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled(); -- -- qemu_add_vm_change_state_handler(vm_change_state_handler, s); - } - - /** --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-intc-arm_gicv3_its-Implement-a-minimalist-reset.patch b/SOURCES/kvm-hw-intc-arm_gicv3_its-Implement-a-minimalist-reset.patch deleted file mode 100644 index 2dc874d..0000000 --- a/SOURCES/kvm-hw-intc-arm_gicv3_its-Implement-a-minimalist-reset.patch +++ /dev/null @@ -1,122 +0,0 @@ -From ef9a83242e22841ce988c14870fd9391dc832a99 Mon Sep 17 00:00:00 2001 -From: Auger Eric -Date: Tue, 28 Nov 2017 15:14:06 +0100 -Subject: [PATCH 5/9] hw/intc/arm_gicv3_its: Implement a minimalist reset - -RH-Author: Auger Eric -Message-id: <1511882048-11256-6-git-send-email-eric.auger@redhat.com> -Patchwork-id: 77943 -O-Subject: [RHV7.5 qemu-kvm-ma PATCH 5/7] hw/intc/arm_gicv3_its: Implement a minimalist reset -Bugzilla: 1513323 -RH-Acked-by: Andrew Jones -RH-Acked-by: Miroslav Rezanina -RH-Acked-by: Wei Huang - -At the moment the ITS is not properly reset and this causes -various bugs on save/restore. We implement a minimalist reset -through individual register writes but for kernel versions -before v4.15 this fails voiding the vITS cache. We cannot -claim we have a comprehensive reset (hence the error message) -but that's better than nothing. - -Signed-off-by: Eric Auger - ---- -v5 -> v6: -- add class_size - -v4 -> v5: -- correct error message - -v2 -> v3: -- individual register writes performed in kvm_arm_its_reset -- check KVM_DEV_ARM_VGIC_GRP_ITS_REGS support - -Signed-off-by: Miroslav Rezanina ---- - hw/intc/arm_gicv3_its_kvm.c | 42 ++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 42 insertions(+) - -diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c -index b1b322b..1c663ac 100644 ---- a/hw/intc/arm_gicv3_its_kvm.c -+++ b/hw/intc/arm_gicv3_its_kvm.c -@@ -28,6 +28,16 @@ - - #define TYPE_KVM_ARM_ITS "arm-its-kvm" - #define KVM_ARM_ITS(obj) OBJECT_CHECK(GICv3ITSState, (obj), TYPE_KVM_ARM_ITS) -+#define KVM_ARM_ITS_CLASS(klass) \ -+ OBJECT_CLASS_CHECK(KVMARMITSClass, (klass), TYPE_KVM_ARM_ITS) -+#define KVM_ARM_ITS_GET_CLASS(obj) \ -+ OBJECT_GET_CLASS(KVMARMITSClass, (obj), TYPE_KVM_ARM_ITS) -+ -+typedef struct KVMARMITSClass { -+ GICv3ITSCommonClass parent_class; -+ void (*parent_reset)(DeviceState *dev); -+} KVMARMITSClass; -+ - - static int kvm_its_send_msi(GICv3ITSState *s, uint32_t value, uint16_t devid) - { -@@ -186,6 +196,34 @@ static void kvm_arm_its_post_load(GICv3ITSState *s) - GITS_CTLR, &s->ctlr, true, &error_abort); - } - -+static void kvm_arm_its_reset(DeviceState *dev) -+{ -+ GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev); -+ KVMARMITSClass *c = KVM_ARM_ITS_GET_CLASS(s); -+ int i; -+ -+ c->parent_reset(dev); -+ -+ error_report("ITS KVM: full reset is not supported by QEMU"); -+ -+ if (!kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, -+ GITS_CTLR)) { -+ return; -+ } -+ -+ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, -+ GITS_CTLR, &s->ctlr, true, &error_abort); -+ -+ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, -+ GITS_CBASER, &s->cbaser, true, &error_abort); -+ -+ for (i = 0; i < 8; i++) { -+ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, -+ GITS_BASER + i * 8, &s->baser[i], true, -+ &error_abort); -+ } -+} -+ - static Property kvm_arm_its_props[] = { - DEFINE_PROP_LINK("parent-gicv3", GICv3ITSState, gicv3, "kvm-arm-gicv3", - GICv3State *), -@@ -196,12 +234,15 @@ static void kvm_arm_its_class_init(ObjectClass *klass, void *data) - { - DeviceClass *dc = DEVICE_CLASS(klass); - GICv3ITSCommonClass *icc = ARM_GICV3_ITS_COMMON_CLASS(klass); -+ KVMARMITSClass *ic = KVM_ARM_ITS_CLASS(klass); - - dc->realize = kvm_arm_its_realize; - dc->props = kvm_arm_its_props; -+ ic->parent_reset = dc->reset; - icc->send_msi = kvm_its_send_msi; - icc->pre_save = kvm_arm_its_pre_save; - icc->post_load = kvm_arm_its_post_load; -+ dc->reset = kvm_arm_its_reset; - } - - static const TypeInfo kvm_arm_its_info = { -@@ -209,6 +250,7 @@ static const TypeInfo kvm_arm_its_info = { - .parent = TYPE_ARM_GICV3_ITS_COMMON, - .instance_size = sizeof(GICv3ITSState), - .class_init = kvm_arm_its_class_init, -+ .class_size = sizeof(KVMARMITSClass), - }; - - static void kvm_arm_its_register_types(void) --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-intc-arm_gicv3_its-Implement-full-reset.patch b/SOURCES/kvm-hw-intc-arm_gicv3_its-Implement-full-reset.patch deleted file mode 100644 index 82552ae..0000000 --- a/SOURCES/kvm-hw-intc-arm_gicv3_its-Implement-full-reset.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 4a5658befb21d06adda6e6faf5c507990f08d270 Mon Sep 17 00:00:00 2001 -From: Auger Eric -Date: Tue, 28 Nov 2017 15:14:08 +0100 -Subject: [PATCH 7/9] hw/intc/arm_gicv3_its: Implement full reset - -RH-Author: Auger Eric -Message-id: <1511882048-11256-8-git-send-email-eric.auger@redhat.com> -Patchwork-id: 77942 -O-Subject: [RHV7.5 qemu-kvm-ma PATCH 7/7] hw/intc/arm_gicv3_its: Implement full reset -Bugzilla: 1513323 -RH-Acked-by: Andrew Jones -RH-Acked-by: Miroslav Rezanina -RH-Acked-by: Wei Huang - -Voiding the ITS caches is not supposed to happen via -individual register writes. So we introduced a dedicated -ITS KVM device ioctl to perform a cold reset of the ITS: -KVM_DEV_ARM_VGIC_GRP_CTRL/KVM_DEV_ARM_ITS_CTRL_RESET. Let's -use this latter if the kernel supports it. - -Signed-off-by: Eric Auger -Signed-off-by: Miroslav Rezanina ---- - hw/intc/arm_gicv3_its_kvm.c | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c -index 1c663ac..bf290b8 100644 ---- a/hw/intc/arm_gicv3_its_kvm.c -+++ b/hw/intc/arm_gicv3_its_kvm.c -@@ -204,7 +204,14 @@ static void kvm_arm_its_reset(DeviceState *dev) - - c->parent_reset(dev); - -- error_report("ITS KVM: full reset is not supported by QEMU"); -+ if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, -+ KVM_DEV_ARM_ITS_CTRL_RESET)) { -+ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, -+ KVM_DEV_ARM_ITS_CTRL_RESET, NULL, true, &error_abort); -+ return; -+ } -+ -+ error_report("ITS KVM: full reset is not supported by the host kernel"); - - if (!kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, - GITS_CTLR)) { --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-misc-add-vmcoreinfo-device.patch b/SOURCES/kvm-hw-misc-add-vmcoreinfo-device.patch deleted file mode 100644 index 1feae60..0000000 --- a/SOURCES/kvm-hw-misc-add-vmcoreinfo-device.patch +++ /dev/null @@ -1,257 +0,0 @@ -From a230ce8214e3d23ddb3aae86c9afa9bfb0242e83 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Mon, 27 Nov 2017 22:51:05 +0100 -Subject: [PATCH 07/21] hw/misc: add vmcoreinfo device -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Marc-André Lureau -Message-id: <20171127225111.24518-4-marcandre.lureau@redhat.com> -Patchwork-id: 77924 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 3/9] hw/misc: add vmcoreinfo device -Bugzilla: 1398633 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Andrew Jones -RH-Acked-by: Miroslav Rezanina - -See docs/specs/vmcoreinfo.txt for details. - -"etc/vmcoreinfo" fw_cfg entry is added when using "-device vmcoreinfo". - -Minor conflict in hw/misc/Makefile.objs due to commented device -introduced in commit 0e72e616b2d80e47c0eb6c5976276e9f8d920e92 - -Signed-off-by: Marc-André Lureau -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin - -(cherry picked from commit 6e43353f10c6688060af0bc26bdfdd4cf9c96ea2) -Signed-off-by: Marc-André Lureau -Signed-off-by: Miroslav Rezanina ---- - docs/specs/vmcoreinfo.txt | 41 +++++++++++++++++++ - hw/misc/Makefile.objs | 1 + - hw/misc/vmcoreinfo.c | 96 ++++++++++++++++++++++++++++++++++++++++++++ - include/hw/misc/vmcoreinfo.h | 46 +++++++++++++++++++++ - 4 files changed, 184 insertions(+) - create mode 100644 docs/specs/vmcoreinfo.txt - create mode 100644 hw/misc/vmcoreinfo.c - create mode 100644 include/hw/misc/vmcoreinfo.h - -diff --git a/docs/specs/vmcoreinfo.txt b/docs/specs/vmcoreinfo.txt -new file mode 100644 -index 0000000..2868a77 ---- /dev/null -+++ b/docs/specs/vmcoreinfo.txt -@@ -0,0 +1,41 @@ -+================= -+VMCoreInfo device -+================= -+ -+The `-device vmcoreinfo` will create a fw_cfg entry for a guest to -+store dump details. -+ -+etc/vmcoreinfo -+************** -+ -+A guest may use this fw_cfg entry to add information details to qemu -+dumps. -+ -+The entry of 16 bytes has the following layout, in little-endian:: -+ -+#define VMCOREINFO_FORMAT_NONE 0x0 -+#define VMCOREINFO_FORMAT_ELF 0x1 -+ -+ struct FWCfgVMCoreInfo { -+ uint16_t host_format; /* formats host supports */ -+ uint16_t guest_format; /* format guest supplies */ -+ uint32_t size; /* size of vmcoreinfo region */ -+ uint64_t paddr; /* physical address of vmcoreinfo region */ -+ }; -+ -+Only full write (of 16 bytes) are considered valid for further -+processing of entry values. -+ -+A write of 0 in guest_format will disable further processing of -+vmcoreinfo entry values & content. -+ -+Format & content -+**************** -+ -+As of qemu 2.11, only VMCOREINFO_FORMAT_ELF is supported. -+ -+The entry gives location and size of an ELF note that is appended in -+qemu dumps. -+ -+The note format/class must be of the target bitness and the size must -+be less than 1Mb. -diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs -index a1007ae..b4cbebf 100644 ---- a/hw/misc/Makefile.objs -+++ b/hw/misc/Makefile.objs -@@ -9,6 +9,7 @@ common-obj-$(CONFIG_PCI_TESTDEV) += pci-testdev.o - common-obj-$(CONFIG_EDU) += edu.o - - #common-obj-y += unimp.o -+common-obj-y += vmcoreinfo.o - - obj-$(CONFIG_VMPORT) += vmport.o - -diff --git a/hw/misc/vmcoreinfo.c b/hw/misc/vmcoreinfo.c -new file mode 100644 -index 0000000..a618e12 ---- /dev/null -+++ b/hw/misc/vmcoreinfo.c -@@ -0,0 +1,96 @@ -+/* -+ * Virtual Machine coreinfo device -+ * -+ * Copyright (C) 2017 Red Hat, Inc. -+ * -+ * Authors: Marc-André Lureau -+ * -+ * 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/error.h" -+#include "hw/nvram/fw_cfg.h" -+#include "hw/misc/vmcoreinfo.h" -+ -+static void fw_cfg_vmci_write(void *dev, off_t offset, size_t len) -+{ -+ VMCoreInfoState *s = VMCOREINFO(dev); -+ -+ s->has_vmcoreinfo = offset == 0 && len == sizeof(s->vmcoreinfo) -+ && s->vmcoreinfo.guest_format != VMCOREINFO_FORMAT_NONE; -+} -+ -+static void vmcoreinfo_reset(void *dev) -+{ -+ VMCoreInfoState *s = VMCOREINFO(dev); -+ -+ s->has_vmcoreinfo = false; -+ memset(&s->vmcoreinfo, 0, sizeof(s->vmcoreinfo)); -+ s->vmcoreinfo.host_format = cpu_to_le16(VMCOREINFO_FORMAT_ELF); -+} -+ -+static void vmcoreinfo_realize(DeviceState *dev, Error **errp) -+{ -+ VMCoreInfoState *s = VMCOREINFO(dev); -+ FWCfgState *fw_cfg = fw_cfg_find(); -+ -+ /* Given that this function is executing, there is at least one VMCOREINFO -+ * device. Check if there are several. -+ */ -+ if (!vmcoreinfo_find()) { -+ error_setg(errp, "at most one %s device is permitted", -+ VMCOREINFO_DEVICE); -+ return; -+ } -+ -+ if (!fw_cfg || !fw_cfg->dma_enabled) { -+ error_setg(errp, "%s device requires fw_cfg with DMA", -+ VMCOREINFO_DEVICE); -+ return; -+ } -+ -+ fw_cfg_add_file_callback(fw_cfg, "etc/vmcoreinfo", -+ NULL, fw_cfg_vmci_write, s, -+ &s->vmcoreinfo, sizeof(s->vmcoreinfo), false); -+ -+ qemu_register_reset(vmcoreinfo_reset, dev); -+} -+ -+static const VMStateDescription vmstate_vmcoreinfo = { -+ .name = "vmcoreinfo", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = (VMStateField[]) { -+ VMSTATE_BOOL(has_vmcoreinfo, VMCoreInfoState), -+ VMSTATE_UINT16(vmcoreinfo.host_format, VMCoreInfoState), -+ VMSTATE_UINT16(vmcoreinfo.guest_format, VMCoreInfoState), -+ VMSTATE_UINT32(vmcoreinfo.size, VMCoreInfoState), -+ VMSTATE_UINT64(vmcoreinfo.paddr, VMCoreInfoState), -+ VMSTATE_END_OF_LIST() -+ }, -+}; -+ -+static void vmcoreinfo_device_class_init(ObjectClass *klass, void *data) -+{ -+ DeviceClass *dc = DEVICE_CLASS(klass); -+ -+ dc->vmsd = &vmstate_vmcoreinfo; -+ dc->realize = vmcoreinfo_realize; -+ dc->hotpluggable = false; -+} -+ -+static const TypeInfo vmcoreinfo_device_info = { -+ .name = VMCOREINFO_DEVICE, -+ .parent = TYPE_DEVICE, -+ .instance_size = sizeof(VMCoreInfoState), -+ .class_init = vmcoreinfo_device_class_init, -+}; -+ -+static void vmcoreinfo_register_types(void) -+{ -+ type_register_static(&vmcoreinfo_device_info); -+} -+ -+type_init(vmcoreinfo_register_types) -diff --git a/include/hw/misc/vmcoreinfo.h b/include/hw/misc/vmcoreinfo.h -new file mode 100644 -index 0000000..c3aa856 ---- /dev/null -+++ b/include/hw/misc/vmcoreinfo.h -@@ -0,0 +1,46 @@ -+/* -+ * Virtual Machine coreinfo device -+ * -+ * Copyright (C) 2017 Red Hat, Inc. -+ * -+ * Authors: Marc-André Lureau -+ * -+ * 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 VMCOREINFO_H -+#define VMCOREINFO_H -+ -+#include "hw/qdev.h" -+ -+#define VMCOREINFO_DEVICE "vmcoreinfo" -+#define VMCOREINFO(obj) OBJECT_CHECK(VMCoreInfoState, (obj), VMCOREINFO_DEVICE) -+ -+#define VMCOREINFO_FORMAT_NONE 0x0 -+#define VMCOREINFO_FORMAT_ELF 0x1 -+ -+/* all fields are little-endian */ -+typedef struct FWCfgVMCoreInfo { -+ uint16_t host_format; /* set on reset */ -+ uint16_t guest_format; -+ uint32_t size; -+ uint64_t paddr; -+} QEMU_PACKED FWCfgVMCoreInfo; -+ -+typedef struct VMCoreInfoState { -+ DeviceClass parent_obj; -+ -+ bool has_vmcoreinfo; -+ FWCfgVMCoreInfo vmcoreinfo; -+} VMCoreInfoState; -+ -+/* returns NULL unless there is exactly one device */ -+static inline VMCoreInfoState *vmcoreinfo_find(void) -+{ -+ Object *o = object_resolve_path_type("", VMCOREINFO_DEVICE, NULL); -+ -+ return o ? VMCOREINFO(o) : NULL; -+} -+ -+#endif --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-nvram-spapr_nvram-Device-can-not-be-created-by-th.patch b/SOURCES/kvm-hw-nvram-spapr_nvram-Device-can-not-be-created-by-th.patch deleted file mode 100644 index fbc403f..0000000 --- a/SOURCES/kvm-hw-nvram-spapr_nvram-Device-can-not-be-created-by-th.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 04b5f1821a275b874f372ad3c0f758305b856545 Mon Sep 17 00:00:00 2001 -From: Sam Bobroff -Date: Tue, 10 Oct 2017 03:07:14 +0200 -Subject: [PATCH 32/34] hw/nvram/spapr_nvram: Device can not be created by the - users - -RH-Author: Sam Bobroff -Message-id: <1507604834-28278-1-git-send-email-sbobroff@redhat.com> -Patchwork-id: 77048 -O-Subject: [PATCH] hw/nvram/spapr_nvram: Device can not be created by the users -Bugzilla: 1490869 -RH-Acked-by: Thomas Huth -RH-Acked-by: David Gibson -RH-Acked-by: Laurent Vivier - -From: Thomas Huth - -Trying to add a spapr-nvram device currently aborts QEMU like this: - -$ ppc64-softmmu/qemu-system-ppc64 -device spapr-nvram -qemu-system-ppc64: hw/ppc/spapr_rtas.c:407: spapr_rtas_register: - Assertion `!rtas_table[token].name' failed. -Aborted (core dumped) - -This NVRAM device registers RTAS calls during its realize function -and thus can only be used once - and that's internally from spapr.c. -So let's mark the device with user_creatable = false to avoid that -the users can crash their QEMU this way. - -Signed-off-by: Thomas Huth -Signed-off-by: David Gibson -(cherry picked from commit 280503ee9d7833a793770d732dda5358659825e9) - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1490869 -Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=14217542 -Testing: Run "ppc64-softmmu/qemu-system-ppc64 -device spapr-nvram". -Signed-off-by: Sam Bobroff -Signed-off-by: Miroslav Rezanina ---- - hw/nvram/spapr_nvram.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/hw/nvram/spapr_nvram.c b/hw/nvram/spapr_nvram.c -index bc355a4..4a0aec8 100644 ---- a/hw/nvram/spapr_nvram.c -+++ b/hw/nvram/spapr_nvram.c -@@ -264,6 +264,8 @@ static void spapr_nvram_class_init(ObjectClass *klass, void *data) - set_bit(DEVICE_CATEGORY_MISC, dc->categories); - dc->props = spapr_nvram_properties; - dc->vmsd = &vmstate_spapr_nvram; -+ /* Reason: Internal device only, uses spapr_rtas_register() in realize() */ -+ dc->user_creatable = false; - } - - static const TypeInfo spapr_nvram_type_info = { --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-pci-add-QEMU-specific-PCI-capability-to-the-Gener.patch b/SOURCES/kvm-hw-pci-add-QEMU-specific-PCI-capability-to-the-Gener.patch deleted file mode 100644 index 8ea5a55..0000000 --- a/SOURCES/kvm-hw-pci-add-QEMU-specific-PCI-capability-to-the-Gener.patch +++ /dev/null @@ -1,128 +0,0 @@ -From e624b4d9b2fcc27ce36cb2a37009d8083ee3ca9e Mon Sep 17 00:00:00 2001 -From: Marcel Apfelbaum -Date: Mon, 13 Nov 2017 15:59:40 +0100 -Subject: [PATCH 02/30] hw/pci: add QEMU-specific PCI capability to the Generic - PCI Express Root Port - -RH-Author: Marcel Apfelbaum -Message-id: <20171113155940.50793-3-marcel@redhat.com> -Patchwork-id: 77663 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 2/2] hw/pci: add QEMU-specific PCI capability to the Generic PCI Express Root Port -Bugzilla: 1437113 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Michael S. Tsirkin -RH-Acked-by: Gerd Hoffmann - -From: Aleksandr Bezzubikov - -To enable hotplugging of a newly created pcie-pci-bridge, -we need to tell firmware (e.g. SeaBIOS) to reserve -additional buses or IO/MEM/PREF space for pcie-root-port. -Additional bus reservation allows us to hotplug pcie-pci-bridge into this root port. -The number of buses and IO/MEM/PREF space to reserve are provided to the device via -a corresponding property, and to the firmware via new PCI capability. -The properties' default values are -1 to keep default behavior unchanged. - -Signed-off-by: Aleksandr Bezzubikov -Reviewed-by: Marcel Apfelbaum -Tested-by: Marcel Apfelbaum -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 226263fb5cdaa4a4a95f1680fabbc9dd2123fd67) -Signed-off-by: Marcel Apfelbaum -Signed-off-by: Miroslav Rezanina ---- - hw/pci-bridge/gen_pcie_root_port.c | 36 ++++++++++++++++++++++++++++++++++++ - include/hw/pci/pcie_port.h | 1 + - 2 files changed, 37 insertions(+) - -diff --git a/hw/pci-bridge/gen_pcie_root_port.c b/hw/pci-bridge/gen_pcie_root_port.c -index cb694d6..ed03ffc 100644 ---- a/hw/pci-bridge/gen_pcie_root_port.c -+++ b/hw/pci-bridge/gen_pcie_root_port.c -@@ -16,6 +16,8 @@ - #include "hw/pci/pcie_port.h" - - #define TYPE_GEN_PCIE_ROOT_PORT "pcie-root-port" -+#define GEN_PCIE_ROOT_PORT(obj) \ -+ OBJECT_CHECK(GenPCIERootPort, (obj), TYPE_GEN_PCIE_ROOT_PORT) - - #define GEN_PCIE_ROOT_PORT_AER_OFFSET 0x100 - #define GEN_PCIE_ROOT_PORT_MSIX_NR_VECTOR 1 -@@ -26,6 +28,13 @@ typedef struct GenPCIERootPort { - /*< public >*/ - - bool migrate_msix; -+ -+ /* additional resources to reserve on firmware init */ -+ uint32_t bus_reserve; -+ uint64_t io_reserve; -+ uint64_t mem_reserve; -+ uint64_t pref32_reserve; -+ uint64_t pref64_reserve; - } GenPCIERootPort; - - static uint8_t gen_rp_aer_vector(const PCIDevice *d) -@@ -60,6 +69,24 @@ static bool gen_rp_test_migrate_msix(void *opaque, int version_id) - return rp->migrate_msix; - } - -+static void gen_rp_realize(DeviceState *dev, Error **errp) -+{ -+ PCIDevice *d = PCI_DEVICE(dev); -+ GenPCIERootPort *grp = GEN_PCIE_ROOT_PORT(d); -+ PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(d); -+ -+ rpc->parent_realize(dev, errp); -+ -+ int rc = pci_bridge_qemu_reserve_cap_init(d, 0, grp->bus_reserve, -+ grp->io_reserve, grp->mem_reserve, grp->pref32_reserve, -+ grp->pref64_reserve, errp); -+ -+ if (rc < 0) { -+ rpc->parent_class.exit(d); -+ return; -+ } -+} -+ - static const VMStateDescription vmstate_rp_dev = { - .name = "pcie-root-port", - .version_id = 1, -@@ -78,6 +105,11 @@ static const VMStateDescription vmstate_rp_dev = { - - static Property gen_rp_props[] = { - DEFINE_PROP_BOOL("x-migrate-msix", GenPCIERootPort, migrate_msix, true), -+ DEFINE_PROP_UINT32("bus-reserve", GenPCIERootPort, bus_reserve, -1), -+ DEFINE_PROP_SIZE("io-reserve", GenPCIERootPort, io_reserve, -1), -+ DEFINE_PROP_SIZE("mem-reserve", GenPCIERootPort, mem_reserve, -1), -+ DEFINE_PROP_SIZE("pref32-reserve", GenPCIERootPort, pref32_reserve, -1), -+ DEFINE_PROP_SIZE("pref64-reserve", GenPCIERootPort, pref64_reserve, -1), - DEFINE_PROP_END_OF_LIST() - }; - -@@ -92,6 +124,10 @@ static void gen_rp_dev_class_init(ObjectClass *klass, void *data) - dc->desc = "PCI Express Root Port"; - dc->vmsd = &vmstate_rp_dev; - dc->props = gen_rp_props; -+ -+ rpc->parent_realize = dc->realize; -+ dc->realize = gen_rp_realize; -+ - rpc->aer_vector = gen_rp_aer_vector; - rpc->interrupts_init = gen_rp_interrupts_init; - rpc->interrupts_uninit = gen_rp_interrupts_uninit; -diff --git a/include/hw/pci/pcie_port.h b/include/hw/pci/pcie_port.h -index 1333266..0736014 100644 ---- a/include/hw/pci/pcie_port.h -+++ b/include/hw/pci/pcie_port.h -@@ -65,6 +65,7 @@ void pcie_chassis_del_slot(PCIESlot *s); - - typedef struct PCIERootPortClass { - PCIDeviceClass parent_class; -+ DeviceRealize parent_realize; - - uint8_t (*aer_vector)(const PCIDevice *dev); - int (*interrupts_init)(PCIDevice *dev, Error **errp); --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-pci-bridge-fix-QEMU-crash-because-of-pcie-root-po.patch b/SOURCES/kvm-hw-pci-bridge-fix-QEMU-crash-because-of-pcie-root-po.patch deleted file mode 100644 index 8eb5672..0000000 --- a/SOURCES/kvm-hw-pci-bridge-fix-QEMU-crash-because-of-pcie-root-po.patch +++ /dev/null @@ -1,53 +0,0 @@ -From c424945b8ae8bbb6ce6aa6a9178b55b3b7498975 Mon Sep 17 00:00:00 2001 -From: Marcel Apfelbaum -Date: Thu, 18 Jan 2018 15:49:40 +0100 -Subject: [PATCH 07/21] hw/pci-bridge: fix QEMU crash because of pcie-root-port - -RH-Author: Marcel Apfelbaum -Message-id: <20180118154940.32815-1-marcel@redhat.com> -Patchwork-id: 78666 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH] hw/pci-bridge: fix QEMU crash because of pcie-root-port -Bugzilla: 1520858 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Thomas Huth -RH-Acked-by: Miroslav Rezanina - -If we try to use more pcie_root_ports then available slots -and an IO hint is passed to the port, QEMU crashes because -we try to init the "IO hint" capability even if the device -is not created. -Fix it by checking for error before adding the capability, -so QEMU can fail gracefully. - -Signed-off-by: Marcel Apfelbaum -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit fced4d00e68e7559c73746d963265f7fd0b6abf9) -Signed-off-by: Marcel Apfelbaum -Signed-off-by: Miroslav Rezanina ---- - hw/pci-bridge/gen_pcie_root_port.c | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/hw/pci-bridge/gen_pcie_root_port.c b/hw/pci-bridge/gen_pcie_root_port.c -index ad4e6aa..0e2f2e8 100644 ---- a/hw/pci-bridge/gen_pcie_root_port.c -+++ b/hw/pci-bridge/gen_pcie_root_port.c -@@ -74,8 +74,13 @@ static void gen_rp_realize(DeviceState *dev, Error **errp) - PCIDevice *d = PCI_DEVICE(dev); - GenPCIERootPort *grp = GEN_PCIE_ROOT_PORT(d); - PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(d); -+ Error *local_err = NULL; - -- rpc->parent_realize(dev, errp); -+ rpc->parent_realize(dev, &local_err); -+ if (local_err) { -+ error_propagate(errp, local_err); -+ return; -+ } - - int rc = pci_bridge_qemu_reserve_cap_init(d, 0, grp->bus_reserve, - grp->io_reserve, grp->mem_reserve, grp->pref32_reserve, --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-pci-host-Fix-x86-Host-Bridges-64bit-PCI-hole.patch b/SOURCES/kvm-hw-pci-host-Fix-x86-Host-Bridges-64bit-PCI-hole.patch deleted file mode 100644 index f1aa555..0000000 --- a/SOURCES/kvm-hw-pci-host-Fix-x86-Host-Bridges-64bit-PCI-hole.patch +++ /dev/null @@ -1,333 +0,0 @@ -From 888e98c6d61b16f59867b91e41af9c878f4d1193 Mon Sep 17 00:00:00 2001 -From: Marcel Apfelbaum -Date: Fri, 17 Nov 2017 16:26:38 +0100 -Subject: [PATCH 29/30] hw/pci-host: Fix x86 Host Bridges 64bit PCI hole - -RH-Author: Marcel Apfelbaum -Message-id: <20171117162638.34466-1-marcel@redhat.com> -Patchwork-id: 77746 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH] hw/pci-host: Fix x86 Host Bridges 64bit PCI hole -Bugzilla: 1390346 -RH-Acked-by: Michael S. Tsirkin -RH-Acked-by: Eduardo Habkost -RH-Acked-by: Laszlo Ersek - -Tests: Hotplug an ivshmem device with 2G on Q35 and I440fx machines - (passes only if this patch is applied) - -Signed-off-by: Miroslav Rezanina - -Conflicts: - - include/hw/i386/pc.h - Moved x-pci-hole64-fix compat property from PC_COMPAT_2_10 - to PC_RHEL7_4_COMPAT - -Currently there is no MMIO range over 4G -reserved for PCI hotplug. Since the 32bit PCI hole -depends on the number of cold-plugged PCI devices -and other factors, it is very possible is too small -to hotplug PCI devices with large BARs. - -Fix it by reserving 2G for I4400FX chipset -in order to comply with older Win32 Guest OSes -and 32G for Q35 chipset. - -Even if the new defaults of pci-hole64-size will appear in -"info qtree" also for older machines, the property was -not implemented so no changes will be visible to guests. - -Note this is a regression since prev QEMU versions had -some range reserved for 64bit PCI hotplug. - -Reviewed-by: Laszlo Ersek -Reviewed-by: Gerd Hoffmann -Signed-off-by: Marcel Apfelbaum -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 9fa99d2519cbf71f871e46871df12cb446dc1c3e) -Signed-off-by: Marcel Apfelbaum ---- - hw/i386/pc.c | 22 ++++++++++++++++++++++ - hw/pci-host/piix.c | 32 ++++++++++++++++++++++++++++++-- - hw/pci-host/q35.c | 42 +++++++++++++++++++++++++++++++++++++++--- - include/hw/i386/pc.h | 12 +++++++++++- - include/hw/pci-host/q35.h | 1 + - 5 files changed, 103 insertions(+), 6 deletions(-) - -diff --git a/hw/i386/pc.c b/hw/i386/pc.c -index 83df57f..f37d60a 100644 ---- a/hw/i386/pc.c -+++ b/hw/i386/pc.c -@@ -1482,6 +1482,28 @@ void pc_memory_init(PCMachineState *pcms, - pcms->ioapic_as = &address_space_memory; - } - -+/* -+ * The 64bit pci hole starts after "above 4G RAM" and -+ * potentially the space reserved for memory hotplug. -+ */ -+uint64_t pc_pci_hole64_start(void) -+{ -+ PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); -+ PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); -+ uint64_t hole64_start = 0; -+ -+ if (pcmc->has_reserved_memory && pcms->hotplug_memory.base) { -+ hole64_start = pcms->hotplug_memory.base; -+ if (!pcmc->broken_reserved_end) { -+ hole64_start += memory_region_size(&pcms->hotplug_memory.mr); -+ } -+ } else { -+ hole64_start = 0x100000000ULL + pcms->above_4g_mem_size; -+ } -+ -+ return ROUND_UP(hole64_start, 1ULL << 30); -+} -+ - qemu_irq pc_allocate_cpu_irq(void) - { - return qemu_allocate_irq(pic_irq_request, NULL, 0); -diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c -index 68c3922..dc37bdf 100644 ---- a/hw/pci-host/piix.c -+++ b/hw/pci-host/piix.c -@@ -50,6 +50,7 @@ typedef struct I440FXState { - PCIHostState parent_obj; - Range pci_hole; - uint64_t pci_hole64_size; -+ bool pci_hole64_fix; - uint32_t short_root_bus; - } I440FXState; - -@@ -112,6 +113,9 @@ struct PCII440FXState { - #define I440FX_PAM_SIZE 7 - #define I440FX_SMRAM 0x72 - -+/* Keep it 2G to comply with older win32 guests */ -+#define I440FX_PCI_HOST_HOLE64_SIZE_DEFAULT (1ULL << 31) -+ - /* Older coreboot versions (4.0 and older) read a config register that doesn't - * exist in real hardware, to get the RAM size from QEMU. - */ -@@ -238,29 +242,52 @@ static void i440fx_pcihost_get_pci_hole_end(Object *obj, Visitor *v, - visit_type_uint32(v, name, &value, errp); - } - -+/* -+ * The 64bit PCI hole start is set by the Guest firmware -+ * as the address of the first 64bit PCI MEM resource. -+ * If no PCI device has resources on the 64bit area, -+ * the 64bit PCI hole will start after "over 4G RAM" and the -+ * reserved space for memory hotplug if any. -+ */ - static void i440fx_pcihost_get_pci_hole64_start(Object *obj, Visitor *v, - const char *name, - void *opaque, Error **errp) - { - PCIHostState *h = PCI_HOST_BRIDGE(obj); -+ I440FXState *s = I440FX_PCI_HOST_BRIDGE(obj); - Range w64; - uint64_t value; - - pci_bus_get_w64_range(h->bus, &w64); - value = range_is_empty(&w64) ? 0 : range_lob(&w64); -+ if (!value && s->pci_hole64_fix) { -+ value = pc_pci_hole64_start(); -+ } - visit_type_uint64(v, name, &value, errp); - } - -+/* -+ * The 64bit PCI hole end is set by the Guest firmware -+ * as the address of the last 64bit PCI MEM resource. -+ * Then it is expanded to the PCI_HOST_PROP_PCI_HOLE64_SIZE -+ * that can be configured by the user. -+ */ - static void i440fx_pcihost_get_pci_hole64_end(Object *obj, Visitor *v, - const char *name, void *opaque, - Error **errp) - { - PCIHostState *h = PCI_HOST_BRIDGE(obj); -+ I440FXState *s = I440FX_PCI_HOST_BRIDGE(obj); -+ uint64_t hole64_start = pc_pci_hole64_start(); - Range w64; -- uint64_t value; -+ uint64_t value, hole64_end; - - pci_bus_get_w64_range(h->bus, &w64); - value = range_is_empty(&w64) ? 0 : range_upb(&w64) + 1; -+ hole64_end = ROUND_UP(hole64_start + s->pci_hole64_size, 1ULL << 30); -+ if (s->pci_hole64_fix && value < hole64_end) { -+ value = hole64_end; -+ } - visit_type_uint64(v, name, &value, errp); - } - -@@ -863,8 +890,9 @@ static const char *i440fx_pcihost_root_bus_path(PCIHostState *host_bridge, - - static Property i440fx_props[] = { - DEFINE_PROP_SIZE(PCI_HOST_PROP_PCI_HOLE64_SIZE, I440FXState, -- pci_hole64_size, DEFAULT_PCI_HOLE64_SIZE), -+ pci_hole64_size, I440FX_PCI_HOST_HOLE64_SIZE_DEFAULT), - DEFINE_PROP_UINT32("short_root_bus", I440FXState, short_root_bus, 0), -+ DEFINE_PROP_BOOL("x-pci-hole64-fix", I440FXState, pci_hole64_fix, true), - DEFINE_PROP_END_OF_LIST(), - }; - -diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c -index 9cd07ce..d7cc898 100644 ---- a/hw/pci-host/q35.c -+++ b/hw/pci-host/q35.c -@@ -37,6 +37,8 @@ - * Q35 host - */ - -+#define Q35_PCI_HOST_HOLE64_SIZE_DEFAULT (1ULL << 35) -+ - static void q35_host_realize(DeviceState *dev, Error **errp) - { - PCIHostState *pci = PCI_HOST_BRIDGE(dev); -@@ -99,29 +101,52 @@ static void q35_host_get_pci_hole_end(Object *obj, Visitor *v, - visit_type_uint32(v, name, &value, errp); - } - -+/* -+ * The 64bit PCI hole start is set by the Guest firmware -+ * as the address of the first 64bit PCI MEM resource. -+ * If no PCI device has resources on the 64bit area, -+ * the 64bit PCI hole will start after "over 4G RAM" and the -+ * reserved space for memory hotplug if any. -+ */ - static void q35_host_get_pci_hole64_start(Object *obj, Visitor *v, - const char *name, void *opaque, - Error **errp) - { - PCIHostState *h = PCI_HOST_BRIDGE(obj); -+ Q35PCIHost *s = Q35_HOST_DEVICE(obj); - Range w64; - uint64_t value; - - pci_bus_get_w64_range(h->bus, &w64); - value = range_is_empty(&w64) ? 0 : range_lob(&w64); -+ if (!value && s->pci_hole64_fix) { -+ value = pc_pci_hole64_start(); -+ } - visit_type_uint64(v, name, &value, errp); - } - -+/* -+ * The 64bit PCI hole end is set by the Guest firmware -+ * as the address of the last 64bit PCI MEM resource. -+ * Then it is expanded to the PCI_HOST_PROP_PCI_HOLE64_SIZE -+ * that can be configured by the user. -+ */ - static void q35_host_get_pci_hole64_end(Object *obj, Visitor *v, - const char *name, void *opaque, - Error **errp) - { - PCIHostState *h = PCI_HOST_BRIDGE(obj); -+ Q35PCIHost *s = Q35_HOST_DEVICE(obj); -+ uint64_t hole64_start = pc_pci_hole64_start(); - Range w64; -- uint64_t value; -+ uint64_t value, hole64_end; - - pci_bus_get_w64_range(h->bus, &w64); - value = range_is_empty(&w64) ? 0 : range_upb(&w64) + 1; -+ hole64_end = ROUND_UP(hole64_start + s->mch.pci_hole64_size, 1ULL << 30); -+ if (s->pci_hole64_fix && value < hole64_end) { -+ value = hole64_end; -+ } - visit_type_uint64(v, name, &value, errp); - } - -@@ -133,16 +158,25 @@ static void q35_host_get_mmcfg_size(Object *obj, Visitor *v, const char *name, - visit_type_uint64(v, name, &e->size, errp); - } - -+/* -+ * NOTE: setting defaults for the mch.* fields in this table -+ * doesn't work, because mch is a separate QOM object that is -+ * zeroed by the object_initialize(&s->mch, ...) call inside -+ * q35_host_initfn(). The default values for those -+ * properties need to be initialized manually by -+ * q35_host_initfn() after the object_initialize() call. -+ */ - static Property q35_host_props[] = { - DEFINE_PROP_UINT64(PCIE_HOST_MCFG_BASE, Q35PCIHost, parent_obj.base_addr, - MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT), - DEFINE_PROP_SIZE(PCI_HOST_PROP_PCI_HOLE64_SIZE, Q35PCIHost, -- mch.pci_hole64_size, DEFAULT_PCI_HOLE64_SIZE), -+ mch.pci_hole64_size, Q35_PCI_HOST_HOLE64_SIZE_DEFAULT), - DEFINE_PROP_UINT32("short_root_bus", Q35PCIHost, mch.short_root_bus, 0), - DEFINE_PROP_SIZE(PCI_HOST_BELOW_4G_MEM_SIZE, Q35PCIHost, - mch.below_4g_mem_size, 0), - DEFINE_PROP_SIZE(PCI_HOST_ABOVE_4G_MEM_SIZE, Q35PCIHost, - mch.above_4g_mem_size, 0), -+ DEFINE_PROP_BOOL("x-pci-hole64-fix", Q35PCIHost, pci_hole64_fix, true), - DEFINE_PROP_END_OF_LIST(), - }; - -@@ -174,7 +208,9 @@ static void q35_host_initfn(Object *obj) - object_property_add_child(OBJECT(s), "mch", OBJECT(&s->mch), NULL); - qdev_prop_set_int32(DEVICE(&s->mch), "addr", PCI_DEVFN(0, 0)); - qdev_prop_set_bit(DEVICE(&s->mch), "multifunction", false); -- -+ /* mch's object_initialize resets the default value, set it again */ -+ qdev_prop_set_uint64(DEVICE(s), PCI_HOST_PROP_PCI_HOLE64_SIZE, -+ Q35_PCI_HOST_HOLE64_SIZE_DEFAULT); - object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_START, "uint32", - q35_host_get_pci_hole_start, - NULL, NULL, NULL, NULL); -diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h -index 6f65d79..7b46121 100644 ---- a/include/hw/i386/pc.h -+++ b/include/hw/i386/pc.h -@@ -241,7 +241,6 @@ void pc_guest_info_init(PCMachineState *pcms); - #define PCI_HOST_PROP_PCI_HOLE64_SIZE "pci-hole64-size" - #define PCI_HOST_BELOW_4G_MEM_SIZE "below-4g-mem-size" - #define PCI_HOST_ABOVE_4G_MEM_SIZE "above-4g-mem-size" --#define DEFAULT_PCI_HOLE64_SIZE (~0x0ULL) - - - void pc_pci_as_mapping_init(Object *owner, MemoryRegion *system_memory, -@@ -252,6 +251,7 @@ void pc_memory_init(PCMachineState *pcms, - MemoryRegion *system_memory, - MemoryRegion *rom_memory, - MemoryRegion **ram_memory); -+uint64_t pc_pci_hole64_start(void); - qemu_irq pc_allocate_cpu_irq(void); - DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus); - void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, -@@ -1015,6 +1015,16 @@ extern void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id); - .driver = "ICH9-LPC",\ - .property = "__com.redhat_force-rev1-fadt",\ - .value = "on",\ -+ },\ -+ { /* PC_RHEL7_4_COMPAT from PC_COMPAT_2_10 */ \ -+ .driver = "i440FX-pcihost",\ -+ .property = "x-pci-hole64-fix",\ -+ .value = "off",\ -+ },\ -+ { /* PC_RHEL7_4_COMPAT from PC_COMPAT_2_10 */ \ -+ .driver = "q35-pcihost",\ -+ .property = "x-pci-hole64-fix",\ -+ .value = "off",\ - }, - - -diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h -index 58983c0..8f4ddde 100644 ---- a/include/hw/pci-host/q35.h -+++ b/include/hw/pci-host/q35.h -@@ -68,6 +68,7 @@ typedef struct Q35PCIHost { - PCIExpressHost parent_obj; - /*< public >*/ - -+ bool pci_hole64_fix; - MCHPCIState mch; - } Q35PCIHost; - --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-pci-host-gpex-Implement-PCI-INTx-routing.patch b/SOURCES/kvm-hw-pci-host-gpex-Implement-PCI-INTx-routing.patch deleted file mode 100644 index 4199089..0000000 --- a/SOURCES/kvm-hw-pci-host-gpex-Implement-PCI-INTx-routing.patch +++ /dev/null @@ -1,67 +0,0 @@ -From aeb5a8995d3eb533fb870f0493c7844679062610 Mon Sep 17 00:00:00 2001 -From: Auger Eric -Date: Mon, 6 Nov 2017 17:08:44 +0100 -Subject: [PATCH 8/9] hw/pci-host/gpex: Implement PCI INTx routing - -RH-Author: Auger Eric -Message-id: <1509988125-30275-4-git-send-email-eric.auger@redhat.com> -Patchwork-id: 77510 -O-Subject: [RHV7.5 qemu-kvm-ma PATCH 3/4] hw/pci-host/gpex: Implement PCI INTx routing -Bugzilla: 1460957 -RH-Acked-by: Alex Williamson -RH-Acked-by: Laurent Vivier -RH-Acked-by: Miroslav Rezanina - -From: Pranavkumar Sawargaonkar - -Now we are able to retrieve the gsi from the INTx pin, let's -enable intx_to_irq routing. From that point on, irqfd becomes -usable along with INTx when assigning a PCIe device. - -Signed-off-by: Pranavkumar Sawargaonkar -Signed-off-by: Tushar Jagad -Signed-off-by: Eric Auger -Reviewed-by: Andrew Jones -Tested-by: Feng Kan -Message-id: 1505296004-6798-4-git-send-email-eric.auger@redhat.com -Signed-off-by: Peter Maydell -(cherry picked from commit d464814ae729f3200234ff74d5f050ddad4f1f20) -Signed-off-by: Eric Auger -Signed-off-by: Miroslav Rezanina ---- - hw/pci-host/gpex.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/hw/pci-host/gpex.c b/hw/pci-host/gpex.c -index d6cf621..4090793 100644 ---- a/hw/pci-host/gpex.c -+++ b/hw/pci-host/gpex.c -@@ -53,6 +53,17 @@ int gpex_set_irq_num(GPEXHost *s, int index, int gsi) - return 0; - } - -+static PCIINTxRoute gpex_route_intx_pin_to_irq(void *opaque, int pin) -+{ -+ PCIINTxRoute route; -+ GPEXHost *s = opaque; -+ -+ route.mode = PCI_INTX_ENABLED; -+ route.irq = s->irq_num[pin]; -+ -+ return route; -+} -+ - static void gpex_host_realize(DeviceState *dev, Error **errp) - { - PCIHostState *pci = PCI_HOST_BRIDGE(dev); -@@ -77,6 +88,7 @@ static void gpex_host_realize(DeviceState *dev, Error **errp) - &s->io_ioport, 0, 4, TYPE_PCIE_BUS); - - qdev_set_parent_bus(DEVICE(&s->gpex_root), BUS(pci->bus)); -+ pci_bus_set_route_irq_fn(pci->bus, gpex_route_intx_pin_to_irq); - qdev_init_nofail(DEVICE(&s->gpex_root)); - } - --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-pci-host-gpex-Improve-INTX-to-gsi-routing-error-c.patch b/SOURCES/kvm-hw-pci-host-gpex-Improve-INTX-to-gsi-routing-error-c.patch deleted file mode 100644 index 65674d3..0000000 --- a/SOURCES/kvm-hw-pci-host-gpex-Improve-INTX-to-gsi-routing-error-c.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 8c777547f451a6d93ae258bbc794be6752af05c4 Mon Sep 17 00:00:00 2001 -From: Auger Eric -Date: Mon, 6 Nov 2017 17:08:45 +0100 -Subject: [PATCH 9/9] hw/pci-host/gpex: Improve INTX to gsi routing error - checking - -RH-Author: Auger Eric -Message-id: <1509988125-30275-5-git-send-email-eric.auger@redhat.com> -Patchwork-id: 77511 -O-Subject: [RHV7.5 qemu-kvm-ma PATCH 4/4] hw/pci-host/gpex: Improve INTX to gsi routing error checking -Bugzilla: 1460957 -RH-Acked-by: Alex Williamson -RH-Acked-by: Laurent Vivier -RH-Acked-by: Miroslav Rezanina - -We exposed gpex_set_irq_num() for machines to set the INTx to -GSI routing. However if the machine forgets to call that -function we currently do not check the association was properly -done. Let's initialize gsi values to -1 and if this value is -found in gpex_route_intx_pin_to_irq, set the routing mode as -disabled. - -Signed-off-by: Eric Auger -Message-id: 1508776211-22175-1-git-send-email-eric.auger@redhat.com -Reviewed-by: Peter Maydell -Signed-off-by: Peter Maydell -(cherry picked from commit 168df2dea701bbf3118bdfea7794369dfa694d3d) -Signed-off-by: Eric Auger -Signed-off-by: Miroslav Rezanina ---- - hw/pci-host/gpex.c | 10 ++++++++-- - 1 file changed, 8 insertions(+), 2 deletions(-) - -diff --git a/hw/pci-host/gpex.c b/hw/pci-host/gpex.c -index 4090793..edf305b 100644 ---- a/hw/pci-host/gpex.c -+++ b/hw/pci-host/gpex.c -@@ -57,9 +57,14 @@ static PCIINTxRoute gpex_route_intx_pin_to_irq(void *opaque, int pin) - { - PCIINTxRoute route; - GPEXHost *s = opaque; -+ int gsi = s->irq_num[pin]; - -- route.mode = PCI_INTX_ENABLED; -- route.irq = s->irq_num[pin]; -+ route.irq = gsi; -+ if (gsi < 0) { -+ route.mode = PCI_INTX_DISABLED; -+ } else { -+ route.mode = PCI_INTX_ENABLED; -+ } - - return route; - } -@@ -81,6 +86,7 @@ static void gpex_host_realize(DeviceState *dev, Error **errp) - sysbus_init_mmio(sbd, &s->io_ioport); - for (i = 0; i < GPEX_NUM_IRQS; i++) { - sysbus_init_irq(sbd, &s->irq[i]); -+ s->irq_num[i] = -1; - } - - pci->bus = pci_register_bus(dev, "pcie.0", gpex_set_irq, --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-pci-host-gpex-Set-INTx-index-gsi-mapping.patch b/SOURCES/kvm-hw-pci-host-gpex-Set-INTx-index-gsi-mapping.patch deleted file mode 100644 index c285ac9..0000000 --- a/SOURCES/kvm-hw-pci-host-gpex-Set-INTx-index-gsi-mapping.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 1cd93911c6a461bbe8585b9d4e2d76ba42abead3 Mon Sep 17 00:00:00 2001 -From: Auger Eric -Date: Mon, 6 Nov 2017 17:08:42 +0100 -Subject: [PATCH 6/9] hw/pci-host/gpex: Set INTx index/gsi mapping - -RH-Author: Auger Eric -Message-id: <1509988125-30275-2-git-send-email-eric.auger@redhat.com> -Patchwork-id: 77509 -O-Subject: [RHV7.5 qemu-kvm-ma PATCH 1/4] hw/pci-host/gpex: Set INTx index/gsi mapping -Bugzilla: 1460957 -RH-Acked-by: Alex Williamson -RH-Acked-by: Laurent Vivier -RH-Acked-by: Miroslav Rezanina - -From: Pranavkumar Sawargaonkar - -To implement INTx to gsi routing we need to pass the gpex host -bridge the gsi associated to each INTx index. Let's introduce -irq_num array and gpex_set_irq_num setter function. - -Signed-off-by: Pranavkumar Sawargaonkar -Signed-off-by: Tushar Jagad -Signed-off-by: Eric Auger -Tested-by: Feng Kan -Reviewed-by: Andrew Jones -Message-id: 1505296004-6798-2-git-send-email-eric.auger@redhat.com -Signed-off-by: Peter Maydell -(cherry picked from commit 70bfdce6a1263fd06144ecc1c3727c44e562d89b) -Signed-off-by: Eric Auger -Signed-off-by: Miroslav Rezanina ---- - hw/pci-host/gpex.c | 10 ++++++++++ - include/hw/pci-host/gpex.h | 3 +++ - 2 files changed, 13 insertions(+) - -diff --git a/hw/pci-host/gpex.c b/hw/pci-host/gpex.c -index 59f3132..d6cf621 100644 ---- a/hw/pci-host/gpex.c -+++ b/hw/pci-host/gpex.c -@@ -43,6 +43,16 @@ static void gpex_set_irq(void *opaque, int irq_num, int level) - qemu_set_irq(s->irq[irq_num], level); - } - -+int gpex_set_irq_num(GPEXHost *s, int index, int gsi) -+{ -+ if (index >= GPEX_NUM_IRQS) { -+ return -EINVAL; -+ } -+ -+ s->irq_num[index] = gsi; -+ return 0; -+} -+ - static void gpex_host_realize(DeviceState *dev, Error **errp) - { - PCIHostState *pci = PCI_HOST_BRIDGE(dev); -diff --git a/include/hw/pci-host/gpex.h b/include/hw/pci-host/gpex.h -index 68c9348..aef38b8 100644 ---- a/include/hw/pci-host/gpex.h -+++ b/include/hw/pci-host/gpex.h -@@ -51,6 +51,9 @@ typedef struct GPEXHost { - MemoryRegion io_ioport; - MemoryRegion io_mmio; - qemu_irq irq[GPEX_NUM_IRQS]; -+ int irq_num[GPEX_NUM_IRQS]; - } GPEXHost; - -+int gpex_set_irq_num(GPEXHost *s, int index, int gsi); -+ - #endif /* HW_GPEX_H */ --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-pci-host-q35-Remove-redundant-downstream-user_cre.patch b/SOURCES/kvm-hw-pci-host-q35-Remove-redundant-downstream-user_cre.patch deleted file mode 100644 index 6ddb54b..0000000 --- a/SOURCES/kvm-hw-pci-host-q35-Remove-redundant-downstream-user_cre.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 35474b23b1f30a940333ea5c76ff85080ff4410c Mon Sep 17 00:00:00 2001 -From: Thomas Huth -Date: Thu, 19 Oct 2017 10:16:48 +0200 -Subject: [PATCH 66/69] hw/pci-host/q35: Remove redundant downstream - user_creatable = false - -RH-Author: Thomas Huth -Message-id: <1508408209-5712-3-git-send-email-thuth@redhat.com> -Patchwork-id: 77374 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 2/3] hw/pci-host/q35: Remove redundant downstream user_creatable = false -Bugzilla: 1503998 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Cornelia Huck -RH-Acked-by: Eduardo Habkost - -The q35_host_class_init() function already sets user_creatable = false -in the upstream code, so there is no need to do this with a downstream -patch again. - -Signed-off-by: Thomas Huth -Signed-off-by: Miroslav Rezanina ---- - hw/pci-host/q35.c | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c -index a91418c..0e472f2 100644 ---- a/hw/pci-host/q35.c -+++ b/hw/pci-host/q35.c -@@ -158,7 +158,6 @@ static void q35_host_class_init(ObjectClass *klass, void *data) - dc->user_creatable = false; - set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); - dc->fw_name = "pci"; -- dc->user_creatable = false; /* RH state preserve */ - } - - static void q35_host_initfn(Object *obj) --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-pci-introduce-bridge-only-vendor-specific-capabil.patch b/SOURCES/kvm-hw-pci-introduce-bridge-only-vendor-specific-capabil.patch deleted file mode 100644 index 0d4e7c4..0000000 --- a/SOURCES/kvm-hw-pci-introduce-bridge-only-vendor-specific-capabil.patch +++ /dev/null @@ -1,128 +0,0 @@ -From 0153864e153e633e3ebfd4d4091971591d098385 Mon Sep 17 00:00:00 2001 -From: Marcel Apfelbaum -Date: Mon, 13 Nov 2017 15:59:39 +0100 -Subject: [PATCH 01/30] hw/pci: introduce bridge-only vendor-specific - capability to provide some hints to firmware - -RH-Author: Marcel Apfelbaum -Message-id: <20171113155940.50793-2-marcel@redhat.com> -Patchwork-id: 77662 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 1/2] hw/pci: introduce bridge-only vendor-specific capability to provide some hints to firmware -Bugzilla: 1437113 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Michael S. Tsirkin -RH-Acked-by: Gerd Hoffmann - -From: Aleksandr Bezzubikov - -On PCI init PCI bridges may need some extra info about bus number, -IO, memory and prefetchable memory to reserve. QEMU can provide this -with a special vendor-specific PCI capability. - -Signed-off-by: Aleksandr Bezzubikov -Reviewed-by: Marcel Apfelbaum -Tested-by: Marcel Apfelbaum -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 70e1ee59bb9490d9ac529e96820a03b346086ca1) -Signed-off-by: Marcel Apfelbaum -Signed-off-by: Miroslav Rezanina ---- - hw/pci/pci_bridge.c | 46 +++++++++++++++++++++++++++++++++++++++++++++ - include/hw/pci/pci_bridge.h | 25 ++++++++++++++++++++++++ - 2 files changed, 71 insertions(+) - -diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c -index 720119b..17feae5 100644 ---- a/hw/pci/pci_bridge.c -+++ b/hw/pci/pci_bridge.c -@@ -408,6 +408,52 @@ void pci_bridge_map_irq(PCIBridge *br, const char* bus_name, - br->bus_name = bus_name; - } - -+ -+int pci_bridge_qemu_reserve_cap_init(PCIDevice *dev, int cap_offset, -+ uint32_t bus_reserve, uint64_t io_reserve, -+ uint32_t mem_non_pref_reserve, -+ uint32_t mem_pref_32_reserve, -+ uint64_t mem_pref_64_reserve, -+ Error **errp) -+{ -+ if (mem_pref_32_reserve != (uint32_t)-1 && -+ mem_pref_64_reserve != (uint64_t)-1) { -+ error_setg(errp, -+ "PCI resource reserve cap: PREF32 and PREF64 conflict"); -+ return -EINVAL; -+ } -+ -+ if (bus_reserve == (uint32_t)-1 && -+ io_reserve == (uint64_t)-1 && -+ mem_non_pref_reserve == (uint32_t)-1 && -+ mem_pref_32_reserve == (uint32_t)-1 && -+ mem_pref_64_reserve == (uint64_t)-1) { -+ return 0; -+ } -+ -+ size_t cap_len = sizeof(PCIBridgeQemuCap); -+ PCIBridgeQemuCap cap = { -+ .len = cap_len, -+ .type = REDHAT_PCI_CAP_RESOURCE_RESERVE, -+ .bus_res = bus_reserve, -+ .io = io_reserve, -+ .mem = mem_non_pref_reserve, -+ .mem_pref_32 = mem_pref_32_reserve, -+ .mem_pref_64 = mem_pref_64_reserve -+ }; -+ -+ int offset = pci_add_capability(dev, PCI_CAP_ID_VNDR, -+ cap_offset, cap_len, errp); -+ if (offset < 0) { -+ return offset; -+ } -+ -+ memcpy(dev->config + offset + PCI_CAP_FLAGS, -+ (char *)&cap + PCI_CAP_FLAGS, -+ cap_len - PCI_CAP_FLAGS); -+ return 0; -+} -+ - static const TypeInfo pci_bridge_type_info = { - .name = TYPE_PCI_BRIDGE, - .parent = TYPE_PCI_DEVICE, -diff --git a/include/hw/pci/pci_bridge.h b/include/hw/pci/pci_bridge.h -index ff7cbaa..1acadc2 100644 ---- a/include/hw/pci/pci_bridge.h -+++ b/include/hw/pci/pci_bridge.h -@@ -67,4 +67,29 @@ void pci_bridge_map_irq(PCIBridge *br, const char* bus_name, - #define PCI_BRIDGE_CTL_DISCARD_STATUS 0x400 /* Discard timer status */ - #define PCI_BRIDGE_CTL_DISCARD_SERR 0x800 /* Discard timer SERR# enable */ - -+typedef struct PCIBridgeQemuCap { -+ uint8_t id; /* Standard PCI capability header field */ -+ uint8_t next; /* Standard PCI capability header field */ -+ uint8_t len; /* Standard PCI vendor-specific capability header field */ -+ uint8_t type; /* Red Hat vendor-specific capability type. -+ Types are defined with REDHAT_PCI_CAP_ prefix */ -+ -+ uint32_t bus_res; /* Minimum number of buses to reserve */ -+ uint64_t io; /* IO space to reserve */ -+ uint32_t mem; /* Non-prefetchable memory to reserve */ -+ /* At most one of the following two fields may be set to a value -+ * different from -1 */ -+ uint32_t mem_pref_32; /* Prefetchable memory to reserve (32-bit MMIO) */ -+ uint64_t mem_pref_64; /* Prefetchable memory to reserve (64-bit MMIO) */ -+} PCIBridgeQemuCap; -+ -+#define REDHAT_PCI_CAP_RESOURCE_RESERVE 1 -+ -+int pci_bridge_qemu_reserve_cap_init(PCIDevice *dev, int cap_offset, -+ uint32_t bus_reserve, uint64_t io_reserve, -+ uint32_t mem_non_pref_reserve, -+ uint32_t mem_pref_32_reserve, -+ uint64_t mem_pref_64_reserve, -+ Error **errp); -+ - #endif /* QEMU_PCI_BRIDGE_H */ --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-ppc-CAS-reset-on-early-device-hotplug.patch b/SOURCES/kvm-hw-ppc-CAS-reset-on-early-device-hotplug.patch deleted file mode 100644 index e91a1e0..0000000 --- a/SOURCES/kvm-hw-ppc-CAS-reset-on-early-device-hotplug.patch +++ /dev/null @@ -1,157 +0,0 @@ -From b6e63f25b4569d9e7c48862f3363b7002feec76f Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Wed, 4 Oct 2017 05:40:13 +0200 -Subject: [PATCH 06/34] hw/ppc: CAS reset on early device hotplug - -RH-Author: David Gibson -Message-id: <20171004054014.14159-4-dgibson@redhat.com> -Patchwork-id: 76801 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 3/4] hw/ppc: CAS reset on early device hotplug -Bugzilla: 1448344 -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth -RH-Acked-by: Miroslav Rezanina - -From: Daniel Henrique Barboza - -This patch is a follow up on the discussions made in patch -"hw/ppc: disable hotplug before CAS is completed" that can be -found at [1]. - -At this moment, we do not support CPU/memory hotplug in early -boot stages, before CAS. When a hotplug occurs, the event is logged -in an internal RTAS event log queue and an IRQ pulse is fired. In -regular conditions, the guest handles the interrupt by executing -check_exception, fetching the generated hotplug event and enabling -the device for use. - -In early boot, this IRQ isn't caught (SLOF does not handle hotplug -events), leaving the event in the rtas event log queue. If the guest -executes check_exception due to another hotplug event, the re-assertion -of the IRQ ends up de-queuing the first hotplug event as well. In short, -a device hotplugged before CAS is considered coldplugged by SLOF. -This leads to device misbehavior and, in some cases, guest kernel -Ooops when trying to unplug the device. - -A proper fix would be to turn every device hotplugged before CAS -as a colplugged device. This is not trivial to do with the current -code base though - the FDT is written in the guest memory at -ppc_spapr_reset and can't be retrieved without adding extra state -(fdt_size for example) that will need to managed and migrated. Adding -the hotplugged DT in the middle of CAS negotiation via the updated DT -tree works with CPU devs, but panics the guest kernel at boot. Additional -analysis would be necessary for LMBs and PCI devices. There are -questions to be made in QEMU/SLOF/kernel level about how we can make -this change in a sustainable way. - -With Linux guests, a fix would be the kernel executing check_exception -at boot time, de-queueing the events that happened in early boot and -processing them. However, even if/when the newer kernels start -fetching these events at boot time, we need to take care of older -kernels that won't be doing that. - -This patch works around the situation by issuing a CAS reset if a hotplugged -device is detected during CAS: - -- the DRC conditions that warrant a CAS reset is the same as those that -triggers a DRC migration - the DRC must have a device attached and -the DRC state is not equal to its ready_state. With that in mind, this -patch makes use of 'spapr_drc_needed' to determine if a CAS reset -is needed. - -- In the middle of CAS negotiations, the function -'spapr_hotplugged_dev_before_cas' goes through all the DRCs to see -if there are any DRC that requires a reset, using spapr_drc_needed. If -that happens, returns '1' in 'spapr_h_cas_compose_response' which will set -spapr->cas_reboot to true, causing the machine to reboot. - -No changes are made for coldplug devices. - -[1] http://lists.nongnu.org/archive/html/qemu-devel/2017-08/msg02855.html - -Signed-off-by: Daniel Henrique Barboza -Signed-off-by: David Gibson -(cherry picked from commit 10f12e6450407b18b4d5a6b50d3852dcfd7fff75) - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr.c | 26 +++++++++++++++++++++++++- - hw/ppc/spapr_drc.c | 2 +- - include/hw/ppc/spapr_drc.h | 1 + - 3 files changed, 27 insertions(+), 2 deletions(-) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index a419aa7..d3db051 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -790,6 +790,26 @@ out: - return ret; - } - -+static bool spapr_hotplugged_dev_before_cas(void) -+{ -+ Object *drc_container, *obj; -+ ObjectProperty *prop; -+ ObjectPropertyIterator iter; -+ -+ drc_container = container_get(object_get_root(), "/dr-connector"); -+ object_property_iter_init(&iter, drc_container); -+ while ((prop = object_property_iter_next(&iter))) { -+ if (!strstart(prop->type, "link<", NULL)) { -+ continue; -+ } -+ obj = object_property_get_link(drc_container, prop->name, NULL); -+ if (spapr_drc_needed(obj)) { -+ return true; -+ } -+ } -+ return false; -+} -+ - int spapr_h_cas_compose_response(sPAPRMachineState *spapr, - target_ulong addr, target_ulong size, - sPAPROptionVector *ov5_updates) -@@ -797,9 +817,13 @@ int spapr_h_cas_compose_response(sPAPRMachineState *spapr, - void *fdt, *fdt_skel; - sPAPRDeviceTreeUpdateHeader hdr = { .version_id = 1 }; - -+ if (spapr_hotplugged_dev_before_cas()) { -+ return 1; -+ } -+ - size -= sizeof(hdr); - -- /* Create sceleton */ -+ /* Create skeleton */ - fdt_skel = g_malloc0(size); - _FDT((fdt_create(fdt_skel, size))); - _FDT((fdt_begin_node(fdt_skel, ""))); -diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c -index 031ba7c..85c999d 100644 ---- a/hw/ppc/spapr_drc.c -+++ b/hw/ppc/spapr_drc.c -@@ -460,7 +460,7 @@ static void drc_reset(void *opaque) - spapr_drc_reset(SPAPR_DR_CONNECTOR(opaque)); - } - --static bool spapr_drc_needed(void *opaque) -+bool spapr_drc_needed(void *opaque) - { - sPAPRDRConnector *drc = (sPAPRDRConnector *)opaque; - sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); -diff --git a/include/hw/ppc/spapr_drc.h b/include/hw/ppc/spapr_drc.h -index a7958d0..f8d9f5b 100644 ---- a/include/hw/ppc/spapr_drc.h -+++ b/include/hw/ppc/spapr_drc.h -@@ -257,6 +257,7 @@ int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner, - void spapr_drc_attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt, - int fdt_start_offset, Error **errp); - void spapr_drc_detach(sPAPRDRConnector *drc); -+bool spapr_drc_needed(void *opaque); - - static inline bool spapr_drc_unplug_requested(sPAPRDRConnector *drc) - { --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-ppc-clear-pending_events-on-machine-reset.patch b/SOURCES/kvm-hw-ppc-clear-pending_events-on-machine-reset.patch deleted file mode 100644 index a4be089..0000000 --- a/SOURCES/kvm-hw-ppc-clear-pending_events-on-machine-reset.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 32a2cf9dfe251696b1d26b70723c5014e7ecbf45 Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Wed, 4 Oct 2017 05:40:12 +0200 -Subject: [PATCH 05/34] hw/ppc: clear pending_events on machine reset - -RH-Author: David Gibson -Message-id: <20171004054014.14159-3-dgibson@redhat.com> -Patchwork-id: 76803 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 2/4] hw/ppc: clear pending_events on machine reset -Bugzilla: 1448344 -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth -RH-Acked-by: Miroslav Rezanina - -From: Daniel Henrique Barboza - -The sPAPR machine isn't clearing up the pending events QTAILQ on -machine reboot. This allows for unprocessed hotplug/epow events -to persist in the queue after reset and, when reasserting the IRQs in -check_exception later on, these will be being processed by the OS. - -This patch implements a new function called 'spapr_clear_pending_events' -that clears up the pending_events QTAILQ. This helper is then called -inside ppc_spapr_reset to clear up the events queue, preventing -old/deprecated events from persisting after a reset. - -Signed-off-by: Daniel Henrique Barboza -Signed-off-by: David Gibson -(cherry picked from commit 56258174238eb25df629a53a96e1ac16a32dc7d4) - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr.c | 1 + - hw/ppc/spapr_events.c | 11 +++++++++++ - include/hw/ppc/spapr.h | 1 + - 3 files changed, 13 insertions(+) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 8d1cfcf..a419aa7 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -1393,6 +1393,7 @@ static void ppc_spapr_reset(void) - } - - qemu_devices_reset(); -+ spapr_clear_pending_events(spapr); - - /* - * We place the device tree and RTAS just below either the top of the RMA, -diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c -index f952b78..66b8164 100644 ---- a/hw/ppc/spapr_events.c -+++ b/hw/ppc/spapr_events.c -@@ -700,6 +700,17 @@ static void event_scan(PowerPCCPU *cpu, sPAPRMachineState *spapr, - rtas_st(rets, 0, RTAS_OUT_NO_ERRORS_FOUND); - } - -+void spapr_clear_pending_events(sPAPRMachineState *spapr) -+{ -+ sPAPREventLogEntry *entry = NULL; -+ -+ QTAILQ_FOREACH(entry, &spapr->pending_events, next) { -+ QTAILQ_REMOVE(&spapr->pending_events, entry, next); -+ g_free(entry->extended_log); -+ g_free(entry); -+ } -+} -+ - void spapr_events_init(sPAPRMachineState *spapr) - { - QTAILQ_INIT(&spapr->pending_events); -diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h -index 2a303a7..5d161ec 100644 ---- a/include/hw/ppc/spapr.h -+++ b/include/hw/ppc/spapr.h -@@ -662,6 +662,7 @@ void spapr_cpu_parse_features(sPAPRMachineState *spapr); - int spapr_hpt_shift_for_ramsize(uint64_t ramsize); - void spapr_reallocate_hpt(sPAPRMachineState *spapr, int shift, - Error **errp); -+void spapr_clear_pending_events(sPAPRMachineState *spapr); - - /* CPU and LMB DRC release callbacks. */ - void spapr_core_release(DeviceState *dev); --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-ppc-spapr-Fix-virtio-scsi-bootindex-handling-for-.patch b/SOURCES/kvm-hw-ppc-spapr-Fix-virtio-scsi-bootindex-handling-for-.patch deleted file mode 100644 index 8e3c9d4..0000000 --- a/SOURCES/kvm-hw-ppc-spapr-Fix-virtio-scsi-bootindex-handling-for-.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 8a285115ee19166f22024326063d330706639914 Mon Sep 17 00:00:00 2001 -From: Thomas Huth -Date: Thu, 23 Nov 2017 17:50:30 +0100 -Subject: [PATCH 4/7] hw/ppc/spapr: Fix virtio-scsi bootindex handling for LUNs - >= 256 - -RH-Author: Thomas Huth -Message-id: <1511459430-7395-2-git-send-email-thuth@redhat.com> -Patchwork-id: 77832 -O-Subject: [RHEL-7.5 qemu-kvm-ma PATCH 1/1] hw/ppc/spapr: Fix virtio-scsi bootindex handling for LUNs >= 256 -Bugzilla: 1515393 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Laurent Vivier -RH-Acked-by: Laszlo Ersek - -LUNs >= 256 have to be encoded with the so-called "flat space -addressing method" for virtio-scsi, where an additional bit has to -be set. SLOF already took care of this with the following commit: - - https://git.qemu.org/?p=SLOF.git;a=commitdiff;h=f72a37713fea47da - (see https://bugzilla.redhat.com/show_bug.cgi?id=1431584 for details) - -But QEMU does not use this encoding yet for device tree paths -that have to be handed over to SLOF to deal with the "bootindex" -property, so SLOF currently fails to boot from virtio-scsi devices -with LUNs >= 256 in the right boot order. Fix it by using the bit -to indicate the "flat space addressing method" for LUNs >= 256. - -Signed-off-by: Thomas Huth -Signed-off-by: David Gibson -(cherry picked from commit bac658d1a4dc9dd637b2eb5006abda137071f17f) -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 96df3a7..2065f09 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -2628,6 +2628,10 @@ static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus, - * swap 0100 or 10 << or 20 << ( target lun-id -- srplun ) - */ - unsigned id = 0x1000000 | (d->id << 16) | d->lun; -+ if (d->lun >= 256) { -+ /* Use the LUN "flat space addressing method" */ -+ id |= 0x4000; -+ } - return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev), - (uint64_t)id << 32); - } else if (usb) { --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-ppc-spapr.c-abort-unplug_request-if-previous-unpl.patch b/SOURCES/kvm-hw-ppc-spapr.c-abort-unplug_request-if-previous-unpl.patch deleted file mode 100644 index 47d45c4..0000000 --- a/SOURCES/kvm-hw-ppc-spapr.c-abort-unplug_request-if-previous-unpl.patch +++ /dev/null @@ -1,103 +0,0 @@ -From 351d24dd01468e63230c68aa27adfebbaf052f3e Mon Sep 17 00:00:00 2001 -From: Serhii Popovych -Date: Thu, 11 Jan 2018 10:37:46 +0100 -Subject: [PATCH 05/12] hw/ppc/spapr.c: abort unplug_request if previous unplug - isn't done - -RH-Author: Serhii Popovych -Message-id: <1515667066-41734-1-git-send-email-spopovyc@redhat.com> -Patchwork-id: 78547 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH] hw/ppc/spapr.c: abort unplug_request if previous unplug isn't done -Bugzilla: 1528173 -RH-Acked-by: Laurent Vivier -RH-Acked-by: David Gibson -RH-Acked-by: Thomas Huth - -From: Daniel Henrique Barboza - -LMB removal is completed only when the spapr_lmb_release callback -is called after all DRCs of the dimm are detached. During this -time, it is possible that a unplug request for the same dimm -arrives, trying to detach DRCs that were detached by the guest -in the first unplug_request. - -BQL doesn't help in this case - the lock will prevent any concurrent -removal from happening until the end of spapr_memory_unplug_request -only. What happens is that the second unplug_request ends up calling -spapr_drc_detach in a DRC that were detached already, causing an -assert error in spapr_drc_detach (e.g -https://bugs.launchpad.net/qemu/+bug/1718118). - -spapr_lmb_release uses a structure called sPAPRDIMMState, stored in the -spapr->pending_dimm_unplugs QTAIL, to track how many LMB DRCs are left -to be detached by the guest. When there are no more DRCs left, this -structure is deleted and the pc-dimm unplug handler is called to -finish the process. - -This patch reuses the sPAPRDIMMState to allow unplug_request to know -if there is an ongoing unplug process for a given dimm, aborting the -unplug request in this case, by doing the following changes: - -- in spapr_lmb_release callback, move the dimm state removal to the -end, after pc-dimm unplug handler. With this change we can check for -the existence of the dimm state to see if the unplug process is -done. - -- use spapr_pending_dimm_unplugs_find in spapr_memory_unplug_request -to check if the dimm state exists. If positive, there is an unplug -operation already in progress for this dimm, meaning that we should -abort it and warn the user about it. - -Fixes: https://bugs.launchpad.net/qemu/+bug/1718118 -Signed-off-by: Daniel Henrique Barboza -Signed-off-by: David Gibson -(cherry picked from commit 2a129767ebb13ffc29dad6a8e8e6eec06dc38b25) -Signed-off-by: Serhii Popovych -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr.c | 16 ++++++++++++++-- - 1 file changed, 14 insertions(+), 2 deletions(-) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index d7fac62..e276632 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -3070,14 +3070,13 @@ void spapr_lmb_release(DeviceState *dev) - return; - } - -- spapr_pending_dimm_unplugs_remove(spapr, ds); -- - /* - * Now that all the LMBs have been removed by the guest, call the - * pc-dimm unplug handler to cleanup up the pc-dimm device. - */ - pc_dimm_memory_unplug(dev, &spapr->hotplug_memory, mr); - object_unparent(OBJECT(dev)); -+ spapr_pending_dimm_unplugs_remove(spapr, ds); - } - - static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev, -@@ -3106,6 +3105,19 @@ static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev, - goto out; - } - -+ /* -+ * An existing pending dimm state for this DIMM means that there is an -+ * unplug operation in progress, waiting for the spapr_lmb_release -+ * callback to complete the job (BQL can't cover that far). In this case, -+ * bail out to avoid detaching DRCs that were already released. -+ */ -+ if (spapr_pending_dimm_unplugs_find(spapr, dimm)) { -+ error_setg(&local_err, -+ "Memory unplug already in progress for device %s", -+ dev->id); -+ goto out; -+ } -+ - spapr_pending_dimm_unplugs_add(spapr, nr_lmbs, dimm); - - addr = addr_start; --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-ppc-spapr_caps-Rework-spapr_caps-to-use-uint8-int.patch b/SOURCES/kvm-hw-ppc-spapr_caps-Rework-spapr_caps-to-use-uint8-int.patch deleted file mode 100644 index 67bd478..0000000 --- a/SOURCES/kvm-hw-ppc-spapr_caps-Rework-spapr_caps-to-use-uint8-int.patch +++ /dev/null @@ -1,719 +0,0 @@ -From dde06ffd66bbc8aa9232dd2c0b849c074d9fcd06 Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Fri, 19 Jan 2018 02:34:41 +0100 -Subject: [PATCH 13/21] hw/ppc/spapr_caps: Rework spapr_caps to use uint8 - internal representation - -RH-Author: David Gibson -Message-id: <20180119023442.28577-7-dgibson@redhat.com> -Patchwork-id: 78674 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 6/7] hw/ppc/spapr_caps: Rework spapr_caps to use uint8 internal representation -Bugzilla: 1523414 -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth -RH-Acked-by: Miroslav Rezanina - -From: Suraj Jitindar Singh - -Currently spapr_caps are tied to boolean values (on or off). This patch -reworks the caps so that they can have any uint8 value. This allows more -capabilities with various values to be represented in the same way -internally. Capabilities are numbered in ascending order. The internal -representation of capability values is an array of uint8s in the -sPAPRMachineState, indexed by capability number. - -Capabilities can have their own name, description, options, getter and -setter functions, type and allow functions. They also each have their own -section in the migration stream. Capabilities are only migrated if they -were explictly set on the command line, with the assumption that -otherwise the default will match. - -On migration we ensure that the capability value on the destination -is greater than or equal to the capability value from the source. So -long at this remains the case then the migration is considered -compatible and allowed to continue. - -This patch implements generic getter and setter functions for boolean -capabilities. It also converts the existings cap-htm, cap-vsx and -cap-dfp capabilities to this new format. - -Signed-off-by: David Gibson -(cherry picked from commit 4e5fe3688e23d61b45cc549ff1322aff8f50ef45) -Signed-off-by: Miroslav Rezanina - -Conflicts: - hw/ppc/spapr.c - include/hw/ppc/spapr.h - -Some trivial contextual conflicts. Also conflicts due to difference -between upstream and downstream machine type versions. Converted to -apply to relevant downstream versions. - -Again needed adjustment to the pre_save function because its return -type has been changed upstream, but not downstream. - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1523414 - -Signed-off-by: David Gibson ---- - hw/ppc/spapr.c | 38 ++++-- - hw/ppc/spapr_caps.c | 321 +++++++++++++++++++++++++------------------------ - include/hw/ppc/spapr.h | 45 +++---- - 3 files changed, 218 insertions(+), 186 deletions(-) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 41cb2fa..66227c3 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -320,7 +320,7 @@ static void spapr_populate_pa_features(sPAPRMachineState *spapr, - */ - pa_features[3] |= 0x20; - } -- if (spapr_has_cap(spapr, SPAPR_CAP_HTM) && pa_size > 24) { -+ if ((spapr_get_cap(spapr, SPAPR_CAP_HTM) != 0) && pa_size > 24) { - pa_features[24] |= 0x80; /* Transactional memory support */ - } - if (legacy_guest && pa_size > 40) { -@@ -566,7 +566,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, - * - * Only CPUs for which we create core types in spapr_cpu_core.c - * are possible, and all of those have VMX */ -- if (spapr_has_cap(spapr, SPAPR_CAP_VSX)) { -+ if (spapr_get_cap(spapr, SPAPR_CAP_VSX) != 0) { - _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 2))); - } else { - _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 1))); -@@ -575,7 +575,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, - /* Advertise DFP (Decimal Floating Point) if available - * 0 / no property == no DFP - * 1 == DFP available */ -- if (spapr_has_cap(spapr, SPAPR_CAP_DFP)) { -+ if (spapr_get_cap(spapr, SPAPR_CAP_DFP) != 0) { - _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1))); - } - -@@ -1544,6 +1544,18 @@ static bool spapr_vga_init(PCIBus *pci_bus, Error **errp) - } - } - -+static int spapr_pre_load(void *opaque) -+{ -+ int rc; -+ -+ rc = spapr_caps_pre_load(opaque); -+ if (rc) { -+ return rc; -+ } -+ -+ return 0; -+} -+ - static int spapr_post_load(void *opaque, int version_id) - { - sPAPRMachineState *spapr = (sPAPRMachineState *)opaque; -@@ -1585,6 +1597,11 @@ static int spapr_post_load(void *opaque, int version_id) - return err; - } - -+static void spapr_pre_save(void *opaque) -+{ -+ spapr_caps_pre_save(opaque); -+} -+ - static bool version_before_3(void *opaque, int version_id) - { - return version_id < 3; -@@ -1705,7 +1722,9 @@ static const VMStateDescription vmstate_spapr = { - .name = "spapr", - .version_id = 3, - .minimum_version_id = 1, -+ .pre_load = spapr_pre_load, - .post_load = spapr_post_load, -+ .pre_save = spapr_pre_save, - .fields = (VMStateField[]) { - /* used to be @next_irq */ - VMSTATE_UNUSED_BUFFER(version_before_3, 0, 4), -@@ -1720,7 +1739,9 @@ static const VMStateDescription vmstate_spapr = { - &vmstate_spapr_ov5_cas, - &vmstate_spapr_patb_entry, - &vmstate_spapr_pending_events, -- &vmstate_spapr_caps, -+ &vmstate_spapr_cap_htm, -+ &vmstate_spapr_cap_vsx, -+ &vmstate_spapr_cap_dfp, - NULL - } - }; -@@ -2279,8 +2300,6 @@ static void ppc_spapr_init(MachineState *machine) - char *filename; - Error *resize_hpt_err = NULL; - -- spapr_caps_validate(spapr, &error_fatal); -- - msi_nonbroken = true; - - QLIST_INIT(&spapr->phbs); -@@ -3650,7 +3669,9 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) - mc->numa_mem_align_shift = 28; - smc->has_power9_support = true; - -- smc->default_caps = spapr_caps(SPAPR_CAP_VSX | SPAPR_CAP_DFP); -+ smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF; -+ smc->default_caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_ON; -+ smc->default_caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_ON; - spapr_caps_add_properties(smc, &error_abort); - } - -@@ -4056,8 +4077,7 @@ static void spapr_machine_rhel740_class_options(MachineClass *mc) - smc->has_power9_support = false; - smc->pre_2_10_has_unused_icps = true; - smc->resize_hpt_default = SPAPR_RESIZE_HPT_DISABLED; -- smc->default_caps = spapr_caps(SPAPR_CAP_HTM | SPAPR_CAP_VSX -- | SPAPR_CAP_DFP); -+ smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_ON; - } - - DEFINE_SPAPR_MACHINE(rhel740, "rhel7.4.0", false); -diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c -index 2b67ac2..f95a785 100644 ---- a/hw/ppc/spapr_caps.c -+++ b/hw/ppc/spapr_caps.c -@@ -35,18 +35,51 @@ - typedef struct sPAPRCapabilityInfo { - const char *name; - const char *description; -- uint64_t flag; -+ const char *options; /* valid capability values */ -+ int index; - -+ /* Getter and Setter Function Pointers */ -+ ObjectPropertyAccessor *get; -+ ObjectPropertyAccessor *set; -+ const char *type; - /* Make sure the virtual hardware can support this capability */ -- void (*allow)(sPAPRMachineState *spapr, Error **errp); -- -- /* If possible, tell the virtual hardware not to allow the cap to -- * be used at all */ -- void (*disallow)(sPAPRMachineState *spapr, Error **errp); -+ void (*apply)(sPAPRMachineState *spapr, uint8_t val, Error **errp); - } sPAPRCapabilityInfo; - --static void cap_htm_allow(sPAPRMachineState *spapr, Error **errp) -+static void spapr_cap_get_bool(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ sPAPRCapabilityInfo *cap = opaque; -+ sPAPRMachineState *spapr = SPAPR_MACHINE(obj); -+ bool value = spapr_get_cap(spapr, cap->index) == SPAPR_CAP_ON; -+ -+ visit_type_bool(v, name, &value, errp); -+} -+ -+static void spapr_cap_set_bool(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ sPAPRCapabilityInfo *cap = opaque; -+ sPAPRMachineState *spapr = SPAPR_MACHINE(obj); -+ bool value; -+ Error *local_err = NULL; -+ -+ visit_type_bool(v, name, &value, &local_err); -+ if (local_err) { -+ error_propagate(errp, local_err); -+ return; -+ } -+ -+ spapr->cmd_line_caps[cap->index] = true; -+ spapr->eff.caps[cap->index] = value ? SPAPR_CAP_ON : SPAPR_CAP_OFF; -+} -+ -+static void cap_htm_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp) - { -+ if (!val) { -+ /* TODO: We don't support disabling htm yet */ -+ return; -+ } - if (tcg_enabled()) { - error_setg(errp, - "No Transactional Memory support in TCG, try cap-htm=off"); -@@ -57,11 +90,15 @@ static void cap_htm_allow(sPAPRMachineState *spapr, Error **errp) - } - } - --static void cap_vsx_allow(sPAPRMachineState *spapr, Error **errp) -+static void cap_vsx_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp) - { - PowerPCCPU *cpu = POWERPC_CPU(first_cpu); - CPUPPCState *env = &cpu->env; - -+ if (!val) { -+ /* TODO: We don't support disabling vsx yet */ -+ return; -+ } - /* Allowable CPUs in spapr_cpu_core.c should already have gotten - * rid of anything that doesn't do VMX */ - g_assert(env->insns_flags & PPC_ALTIVEC); -@@ -70,37 +107,51 @@ static void cap_vsx_allow(sPAPRMachineState *spapr, Error **errp) - } - } - --static void cap_dfp_allow(sPAPRMachineState *spapr, Error **errp) -+static void cap_dfp_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp) - { - PowerPCCPU *cpu = POWERPC_CPU(first_cpu); - CPUPPCState *env = &cpu->env; - -+ if (!val) { -+ /* TODO: We don't support disabling dfp yet */ -+ return; -+ } - if (!(env->insns_flags2 & PPC2_DFP)) { - error_setg(errp, "DFP support not available, try cap-dfp=off"); - } - } - --static sPAPRCapabilityInfo capability_table[] = { -- { -+ -+sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = { -+ [SPAPR_CAP_HTM] = { - .name = "htm", - .description = "Allow Hardware Transactional Memory (HTM)", -- .flag = SPAPR_CAP_HTM, -- .allow = cap_htm_allow, -- /* TODO: add cap_htm_disallow */ -+ .options = "", -+ .index = SPAPR_CAP_HTM, -+ .get = spapr_cap_get_bool, -+ .set = spapr_cap_set_bool, -+ .type = "bool", -+ .apply = cap_htm_apply, - }, -- { -+ [SPAPR_CAP_VSX] = { - .name = "vsx", - .description = "Allow Vector Scalar Extensions (VSX)", -- .flag = SPAPR_CAP_VSX, -- .allow = cap_vsx_allow, -- /* TODO: add cap_vsx_disallow */ -+ .options = "", -+ .index = SPAPR_CAP_VSX, -+ .get = spapr_cap_get_bool, -+ .set = spapr_cap_set_bool, -+ .type = "bool", -+ .apply = cap_vsx_apply, - }, -- { -+ [SPAPR_CAP_DFP] = { - .name = "dfp", - .description = "Allow Decimal Floating Point (DFP)", -- .flag = SPAPR_CAP_DFP, -- .allow = cap_dfp_allow, -- /* TODO: add cap_dfp_disallow */ -+ .options = "", -+ .index = SPAPR_CAP_DFP, -+ .get = spapr_cap_get_bool, -+ .set = spapr_cap_set_bool, -+ .type = "bool", -+ .apply = cap_dfp_apply, - }, - }; - -@@ -115,23 +166,33 @@ static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr, - - if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07, - 0, spapr->max_compat_pvr)) { -- caps.mask &= ~SPAPR_CAP_HTM; -+ caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF; - } - - if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06, - 0, spapr->max_compat_pvr)) { -- caps.mask &= ~SPAPR_CAP_VSX; -- caps.mask &= ~SPAPR_CAP_DFP; -+ caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_OFF; -+ caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_OFF; - } - - return caps; - } - --static bool spapr_caps_needed(void *opaque) -+int spapr_caps_pre_load(void *opaque) - { - sPAPRMachineState *spapr = opaque; - -- return (spapr->forced_caps.mask != 0) || (spapr->forbidden_caps.mask != 0); -+ /* Set to default so we can tell if this came in with the migration */ -+ spapr->mig = spapr->def; -+ return 0; -+} -+ -+int spapr_caps_pre_save(void *opaque) -+{ -+ sPAPRMachineState *spapr = opaque; -+ -+ spapr->mig = spapr->eff; -+ return 0; - } - - /* This has to be called from the top-level spapr post_load, not the -@@ -140,175 +201,121 @@ static bool spapr_caps_needed(void *opaque) - * caps on the destination */ - int spapr_caps_post_migration(sPAPRMachineState *spapr) - { -- uint64_t allcaps = 0; - int i; - bool ok = true; -- sPAPRCapabilities dstcaps = spapr->effective_caps; -+ sPAPRCapabilities dstcaps = spapr->eff; - sPAPRCapabilities srccaps; - - srccaps = default_caps_with_cpu(spapr, first_cpu); -- srccaps.mask |= spapr->mig_forced_caps.mask; -- srccaps.mask &= ~spapr->mig_forbidden_caps.mask; -+ for (i = 0; i < SPAPR_CAP_NUM; i++) { -+ /* If not default value then assume came in with the migration */ -+ if (spapr->mig.caps[i] != spapr->def.caps[i]) { -+ srccaps.caps[i] = spapr->mig.caps[i]; -+ } -+ } - -- for (i = 0; i < ARRAY_SIZE(capability_table); i++) { -+ for (i = 0; i < SPAPR_CAP_NUM; i++) { - sPAPRCapabilityInfo *info = &capability_table[i]; - -- allcaps |= info->flag; -- -- if ((srccaps.mask & info->flag) && !(dstcaps.mask & info->flag)) { -- error_report("cap-%s=on in incoming stream, but off in destination", -- info->name); -+ if (srccaps.caps[i] > dstcaps.caps[i]) { -+ error_report("cap-%s higher level (%d) in incoming stream than on destination (%d)", -+ info->name, srccaps.caps[i], dstcaps.caps[i]); - ok = false; - } - -- if (!(srccaps.mask & info->flag) && (dstcaps.mask & info->flag)) { -- warn_report("cap-%s=off in incoming stream, but on in destination", -- info->name); -+ if (srccaps.caps[i] < dstcaps.caps[i]) { -+ warn_report("cap-%s lower level (%d) in incoming stream than on destination (%d)", -+ info->name, srccaps.caps[i], dstcaps.caps[i]); - } - } - -- if (spapr->mig_forced_caps.mask & ~allcaps) { -- error_report( -- "Unknown capabilities 0x%"PRIx64" enabled in incoming stream", -- spapr->mig_forced_caps.mask & ~allcaps); -- ok = false; -- } -- if (spapr->mig_forbidden_caps.mask & ~allcaps) { -- warn_report( -- "Unknown capabilities 0x%"PRIx64" disabled in incoming stream", -- spapr->mig_forbidden_caps.mask & ~allcaps); -- } -- - return ok ? 0 : -EINVAL; - } - --static void spapr_caps_pre_save(void *opaque) -+static bool spapr_cap_htm_needed(void *opaque) - { - sPAPRMachineState *spapr = opaque; - -- spapr->mig_forced_caps = spapr->forced_caps; -- spapr->mig_forbidden_caps = spapr->forbidden_caps; -+ return spapr->cmd_line_caps[SPAPR_CAP_HTM] && -+ (spapr->eff.caps[SPAPR_CAP_HTM] != spapr->def.caps[SPAPR_CAP_HTM]); - } - --static int spapr_caps_pre_load(void *opaque) -+const VMStateDescription vmstate_spapr_cap_htm = { -+ .name = "spapr/cap/htm", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .needed = spapr_cap_htm_needed, -+ .fields = (VMStateField[]) { -+ VMSTATE_UINT8(mig.caps[SPAPR_CAP_HTM], sPAPRMachineState), -+ VMSTATE_END_OF_LIST() -+ }, -+}; -+ -+static bool spapr_cap_vsx_needed(void *opaque) - { - sPAPRMachineState *spapr = opaque; - -- spapr->mig_forced_caps = spapr_caps(0); -- spapr->mig_forbidden_caps = spapr_caps(0); -- return 0; -+ return spapr->cmd_line_caps[SPAPR_CAP_VSX] && -+ (spapr->eff.caps[SPAPR_CAP_VSX] != spapr->def.caps[SPAPR_CAP_VSX]); - } - --const VMStateDescription vmstate_spapr_caps = { -- .name = "spapr/caps", -+const VMStateDescription vmstate_spapr_cap_vsx = { -+ .name = "spapr/cap/vsx", - .version_id = 1, - .minimum_version_id = 1, -- .needed = spapr_caps_needed, -- .pre_save = spapr_caps_pre_save, -- .pre_load = spapr_caps_pre_load, -+ .needed = spapr_cap_vsx_needed, - .fields = (VMStateField[]) { -- VMSTATE_UINT64(mig_forced_caps.mask, sPAPRMachineState), -- VMSTATE_UINT64(mig_forbidden_caps.mask, sPAPRMachineState), -+ VMSTATE_UINT8(mig.caps[SPAPR_CAP_VSX], sPAPRMachineState), - VMSTATE_END_OF_LIST() - }, - }; - --void spapr_caps_reset(sPAPRMachineState *spapr) --{ -- Error *local_err = NULL; -- sPAPRCapabilities caps; -- int i; -- -- /* First compute the actual set of caps we're running with.. */ -- caps = default_caps_with_cpu(spapr, first_cpu); -- -- /* Remove unnecessary forced/forbidden bits (this will help us -- * with migration) */ -- spapr->forced_caps.mask &= ~caps.mask; -- spapr->forbidden_caps.mask &= caps.mask; -- -- caps.mask |= spapr->forced_caps.mask; -- caps.mask &= ~spapr->forbidden_caps.mask; -- -- spapr->effective_caps = caps; -- -- /* .. then apply those caps to the virtual hardware */ -- -- for (i = 0; i < ARRAY_SIZE(capability_table); i++) { -- sPAPRCapabilityInfo *info = &capability_table[i]; -- -- if (spapr->effective_caps.mask & info->flag) { -- /* Failure to allow a cap is fatal - if the guest doesn't -- * have it, we'll be supplying an incorrect environment */ -- if (info->allow) { -- info->allow(spapr, &error_fatal); -- } -- } else { -- /* Failure to enforce a cap is only a warning. The guest -- * shouldn't be using it, since it's not advertised, so it -- * doesn't get to complain about weird behaviour if it -- * goes ahead anyway */ -- if (info->disallow) { -- info->disallow(spapr, &local_err); -- } -- if (local_err) { -- warn_report_err(local_err); -- local_err = NULL; -- } -- } -- } --} -- --static void spapr_cap_get(Object *obj, Visitor *v, const char *name, -- void *opaque, Error **errp) -+static bool spapr_cap_dfp_needed(void *opaque) - { -- sPAPRCapabilityInfo *cap = opaque; -- sPAPRMachineState *spapr = SPAPR_MACHINE(obj); -- bool value = spapr_has_cap(spapr, cap->flag); -- -- /* TODO: Could this get called before effective_caps is finalized -- * in spapr_caps_reset()? */ -+ sPAPRMachineState *spapr = opaque; - -- visit_type_bool(v, name, &value, errp); -+ return spapr->cmd_line_caps[SPAPR_CAP_DFP] && -+ (spapr->eff.caps[SPAPR_CAP_DFP] != spapr->def.caps[SPAPR_CAP_DFP]); - } - --static void spapr_cap_set(Object *obj, Visitor *v, const char *name, -- void *opaque, Error **errp) --{ -- sPAPRCapabilityInfo *cap = opaque; -- sPAPRMachineState *spapr = SPAPR_MACHINE(obj); -- bool value; -- Error *local_err = NULL; -- -- visit_type_bool(v, name, &value, &local_err); -- if (local_err) { -- error_propagate(errp, local_err); -- return; -- } -- -- if (value) { -- spapr->forced_caps.mask |= cap->flag; -- } else { -- spapr->forbidden_caps.mask |= cap->flag; -- } --} -+const VMStateDescription vmstate_spapr_cap_dfp = { -+ .name = "spapr/cap/dfp", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .needed = spapr_cap_dfp_needed, -+ .fields = (VMStateField[]) { -+ VMSTATE_UINT8(mig.caps[SPAPR_CAP_DFP], sPAPRMachineState), -+ VMSTATE_END_OF_LIST() -+ }, -+}; - --void spapr_caps_validate(sPAPRMachineState *spapr, Error **errp) -+void spapr_caps_reset(sPAPRMachineState *spapr) - { -- uint64_t allcaps = 0; -+ sPAPRCapabilities default_caps; - int i; - -- for (i = 0; i < ARRAY_SIZE(capability_table); i++) { -- g_assert((allcaps & capability_table[i].flag) == 0); -- allcaps |= capability_table[i].flag; -+ /* First compute the actual set of caps we're running with.. */ -+ default_caps = default_caps_with_cpu(spapr, first_cpu); -+ -+ for (i = 0; i < SPAPR_CAP_NUM; i++) { -+ /* Store the defaults */ -+ spapr->def.caps[i] = default_caps.caps[i]; -+ /* If not set on the command line then apply the default value */ -+ if (!spapr->cmd_line_caps[i]) { -+ spapr->eff.caps[i] = default_caps.caps[i]; -+ } - } - -- g_assert((spapr->forced_caps.mask & ~allcaps) == 0); -- g_assert((spapr->forbidden_caps.mask & ~allcaps) == 0); -+ /* .. then apply those caps to the virtual hardware */ -+ -+ for (i = 0; i < SPAPR_CAP_NUM; i++) { -+ sPAPRCapabilityInfo *info = &capability_table[i]; - -- if (spapr->forced_caps.mask & spapr->forbidden_caps.mask) { -- error_setg(errp, "Some sPAPR capabilities set both on and off"); -- return; -+ /* -+ * If the apply function can't set the desired level and thinks it's -+ * fatal, it should cause that. -+ */ -+ info->apply(spapr, spapr->eff.caps[i], &error_fatal); - } - } - -@@ -321,17 +328,19 @@ void spapr_caps_add_properties(sPAPRMachineClass *smc, Error **errp) - for (i = 0; i < ARRAY_SIZE(capability_table); i++) { - sPAPRCapabilityInfo *cap = &capability_table[i]; - const char *name = g_strdup_printf("cap-%s", cap->name); -+ char *desc; - -- object_class_property_add(klass, name, "bool", -- spapr_cap_get, spapr_cap_set, NULL, -- cap, &local_err); -+ object_class_property_add(klass, name, cap->type, -+ cap->get, cap->set, -+ NULL, cap, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - -- object_class_property_set_description(klass, name, cap->description, -- &local_err); -+ desc = g_strdup_printf("%s%s", cap->description, cap->options); -+ object_class_property_set_description(klass, name, desc, &local_err); -+ g_free(desc); - if (local_err) { - error_propagate(errp, local_err); - return; -diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h -index df767c3..7156a70 100644 ---- a/include/hw/ppc/spapr.h -+++ b/include/hw/ppc/spapr.h -@@ -54,20 +54,25 @@ typedef enum { - * Capabilities - */ - --/* These bits go in the migration stream, so they can't be reassigned */ -- - /* Hardware Transactional Memory */ --#define SPAPR_CAP_HTM 0x0000000000000001ULL -- -+#define SPAPR_CAP_HTM 0x00 - /* Vector Scalar Extensions */ --#define SPAPR_CAP_VSX 0x0000000000000002ULL -- -+#define SPAPR_CAP_VSX 0x01 - /* Decimal Floating Point */ --#define SPAPR_CAP_DFP 0x0000000000000004ULL -+#define SPAPR_CAP_DFP 0x02 -+/* Num Caps */ -+#define SPAPR_CAP_NUM (SPAPR_CAP_DFP + 1) -+ -+/* -+ * Capability Values -+ */ -+/* Bool Caps */ -+#define SPAPR_CAP_OFF 0x00 -+#define SPAPR_CAP_ON 0x01 - - typedef struct sPAPRCapabilities sPAPRCapabilities; - struct sPAPRCapabilities { -- uint64_t mask; -+ uint8_t caps[SPAPR_CAP_NUM]; - }; - - /** -@@ -151,9 +156,8 @@ struct sPAPRMachineState { - - const char *icp_type; - -- sPAPRCapabilities forced_caps, forbidden_caps; -- sPAPRCapabilities mig_forced_caps, mig_forbidden_caps; -- sPAPRCapabilities effective_caps; -+ bool cmd_line_caps[SPAPR_CAP_NUM]; -+ sPAPRCapabilities def, eff, mig; - }; - - #define H_SUCCESS 0 -@@ -732,24 +736,23 @@ void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg); - - #define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift)) - -+ -+int spapr_caps_pre_load(void *opaque); -+int spapr_caps_pre_save(void *opaque); -+ - /* - * Handling of optional capabilities - */ --extern const VMStateDescription vmstate_spapr_caps; -- --static inline sPAPRCapabilities spapr_caps(uint64_t mask) --{ -- sPAPRCapabilities caps = { mask }; -- return caps; --} -+extern const VMStateDescription vmstate_spapr_cap_htm; -+extern const VMStateDescription vmstate_spapr_cap_vsx; -+extern const VMStateDescription vmstate_spapr_cap_dfp; - --static inline bool spapr_has_cap(sPAPRMachineState *spapr, uint64_t cap) -+static inline uint8_t spapr_get_cap(sPAPRMachineState *spapr, int cap) - { -- return !!(spapr->effective_caps.mask & cap); -+ return spapr->eff.caps[cap]; - } - - void spapr_caps_reset(sPAPRMachineState *spapr); --void spapr_caps_validate(sPAPRMachineState *spapr, Error **errp); - void spapr_caps_add_properties(sPAPRMachineClass *smc, Error **errp); - int spapr_caps_post_migration(sPAPRMachineState *spapr); - --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-ppc-spapr_drc.c-change-spapr_drc_needed-to-use-dr.patch b/SOURCES/kvm-hw-ppc-spapr_drc.c-change-spapr_drc_needed-to-use-dr.patch deleted file mode 100644 index ee261c3..0000000 --- a/SOURCES/kvm-hw-ppc-spapr_drc.c-change-spapr_drc_needed-to-use-dr.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 6984d8d007ed94067b37af90b1e20a0aad76a205 Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Wed, 4 Oct 2017 05:40:11 +0200 -Subject: [PATCH 04/34] hw/ppc/spapr_drc.c: change spapr_drc_needed to use - drc->dev - -RH-Author: David Gibson -Message-id: <20171004054014.14159-2-dgibson@redhat.com> -Patchwork-id: 76799 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 1/4] hw/ppc/spapr_drc.c: change spapr_drc_needed to use drc->dev -Bugzilla: 1448344 -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth -RH-Acked-by: Miroslav Rezanina - -From: Daniel Henrique Barboza - -This patch makes a small fix in 'spapr_drc_needed' to change how we detect -if a DRC has a device attached. Previously it used dr_entity_sense for this, -which works for physical DRCs. - -However, for logical DRCs, it didn't cover the case where a logical DRC has -a drc->dev but the state is LOGICAL_UNUSABLE (e.g. a hotplugged CPU before -CAS). In this case, the dr_entity_sense of this DRC returns UNUSABLE and the -code was considering that there were no dev attached, making spapr_drc_needed -return 'false' when in fact we would like to migrate the DRC. - -Changing it to check for drc->dev instead works for all DRC types. - -Signed-off-by: Daniel Henrique Barboza -Signed-off-by: David Gibson -(cherry picked from commit c618e300eb2276996e7004100686768cf1445128) - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr_drc.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c -index 605697d..031ba7c 100644 ---- a/hw/ppc/spapr_drc.c -+++ b/hw/ppc/spapr_drc.c -@@ -464,10 +464,9 @@ static bool spapr_drc_needed(void *opaque) - { - sPAPRDRConnector *drc = (sPAPRDRConnector *)opaque; - sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); -- sPAPRDREntitySense value = drck->dr_entity_sense(drc); - - /* If no dev is plugged in there is no need to migrate the DRC state */ -- if (value != SPAPR_DR_ENTITY_SENSE_PRESENT) { -+ if (!drc->dev) { - return false; - } - --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-s390x-Mark-the-sclpquiesce-device-with-user_creat.patch b/SOURCES/kvm-hw-s390x-Mark-the-sclpquiesce-device-with-user_creat.patch deleted file mode 100644 index f9f86fb..0000000 --- a/SOURCES/kvm-hw-s390x-Mark-the-sclpquiesce-device-with-user_creat.patch +++ /dev/null @@ -1,54 +0,0 @@ -From b4f105203964676facfa604594dcae3e43ee7aa0 Mon Sep 17 00:00:00 2001 -From: Thomas Huth -Date: Mon, 9 Oct 2017 12:32:45 +0200 -Subject: [PATCH 26/34] hw/s390x: Mark the "sclpquiesce" device with - user_creatable = false - -RH-Author: Thomas Huth -Message-id: <1507552368-9245-10-git-send-email-thuth@redhat.com> -Patchwork-id: 77026 -O-Subject: [RHEL-7.5 qemu-kvm-ma PATCH 09/12] hw/s390x: Mark the "sclpquiesce" device with user_creatable = false -Bugzilla: 1492033 -RH-Acked-by: Cornelia Huck -RH-Acked-by: David Gibson -RH-Acked-by: Miroslav Rezanina - -The "sclpquiesce" device is just an internal device that should not be -created by the user directly. Though it currently does not seem to cause -any obvious trouble when the user instantiates an additional device, let's -better mark it with user_creatable = false to avoid unexpected behavior, -e.g. because the quiesce notifier gets registered multiple times. - -Signed-off-by: Thomas Huth -Message-Id: <1507193105-15627-1-git-send-email-thuth@redhat.com> -Reviewed-by: Halil Pasic -Reviewed-by: Claudio Imbrenda -Signed-off-by: Cornelia Huck -(cherry picked from commit b923ab3112ed5ab47c2ff35776f17ab54c60d651) -Signed-off-by: Miroslav Rezanina ---- - hw/s390x/sclpquiesce.c | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/hw/s390x/sclpquiesce.c b/hw/s390x/sclpquiesce.c -index 762cb18..0241643 100644 ---- a/hw/s390x/sclpquiesce.c -+++ b/hw/s390x/sclpquiesce.c -@@ -118,8 +118,13 @@ static void quiesce_class_init(ObjectClass *klass, void *data) - dc->reset = quiesce_reset; - dc->vmsd = &vmstate_sclpquiesce; - set_bit(DEVICE_CATEGORY_MISC, dc->categories); -- k->init = quiesce_init; -+ /* -+ * Reason: This is just an internal device - the notifier should -+ * not be registered multiple times in quiesce_init() -+ */ -+ dc->user_creatable = false; - -+ k->init = quiesce_init; - k->get_send_mask = send_mask; - k->get_receive_mask = receive_mask; - k->can_handle_event = can_handle_event; --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-scsi-support-SCSI-2-passthrough-without-PI.patch b/SOURCES/kvm-hw-scsi-support-SCSI-2-passthrough-without-PI.patch deleted file mode 100644 index fc7874c..0000000 --- a/SOURCES/kvm-hw-scsi-support-SCSI-2-passthrough-without-PI.patch +++ /dev/null @@ -1,137 +0,0 @@ -From 968575c7d427c476522e8bfef0aeb3a0bc09fb4a Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Mon, 25 Jun 2018 04:18:24 +0200 -Subject: [PATCH 2/3] hw/scsi: support SCSI-2 passthrough without PI - -RH-Author: David Gibson -Message-id: <20180625041824.5072-3-dgibson@redhat.com> -Patchwork-id: 81030 -O-Subject: [RHEL-7.5.z qemu-kvm-ma PATCH 2/2] hw/scsi: support SCSI-2 passthrough without PI -Bugzilla: 1593193 -RH-Acked-by: Laurent Vivier -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Laszlo Ersek - -From: Daniel Henrique Barboza - -QEMU SCSI code makes assumptions about how the PROTECT and BYTCHK -works in the protocol, denying support for PI (Protection -Information) in case the guest OS requests it. However, in SCSI versions 2 -and older, there is no PI concept in the protocol. - -This means that when dealing with such devices: - -- there is no PROTECT bit in byte 5 of the standard INQUIRY response. The -whole byte is marked as "Reserved"; - -- there is no RDPROTECT in byte 2 of READ. We have 'Logical Unit Number' -in this field instead; - -- there is no VRPROTECT in byte 2 of VERIFY. We have 'Logical Unit Number' -in this field instead. This also means that the BYTCHK bit in this case -is not related to PI. - -Since QEMU does not consider these changes, a SCSI passthrough using -a SCSI-2 device will not work. It will mistake these fields with -PI information and return Illegal Request SCSI SENSE thinking -that the driver is asking for PI support. - -This patch fixes it by adding a new attribute called 'scsi_version' -that is read from the standard INQUIRY response of passthrough -devices. This allows for a version verification before applying -conditions related to PI that doesn't apply for older versions. - -Reported-by: Dac Nguyen -Signed-off-by: Daniel Henrique Barboza -Message-Id: <20180327211451.14647-1-danielhb@linux.vnet.ibm.com> -Signed-off-by: Paolo Bonzini -(cherry picked from commit 29e560f00e2bc1b5731c8276031aaf192de55d9d) - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - hw/scsi/scsi-disk.c | 2 +- - hw/scsi/scsi-generic.c | 47 ++++++++++++++++++++++++++++++++++++----------- - 2 files changed, 37 insertions(+), 12 deletions(-) - -diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c -index f906ffb..d89e4f0 100644 ---- a/hw/scsi/scsi-disk.c -+++ b/hw/scsi/scsi-disk.c -@@ -3011,7 +3011,7 @@ static Property scsi_block_properties[] = { - DEFINE_PROP_BOOL("share-rw", SCSIDiskState, qdev.conf.share_rw, false), - DEFINE_PROP_UINT16("rotation_rate", SCSIDiskState, rotation_rate, 0), - DEFINE_PROP_INT32("scsi_version", SCSIDiskState, qdev.default_scsi_version, -- 5), -+ -1), - DEFINE_PROP_END_OF_LIST(), - }; - -diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c -index fe11efe..e38829a 100644 ---- a/hw/scsi/scsi-generic.c -+++ b/hw/scsi/scsi-generic.c -@@ -194,17 +194,40 @@ static void scsi_read_complete(void * opaque, int ret) - r->buf[3] |= 0x80; - } - } -- if (s->type == TYPE_DISK && -- r->req.cmd.buf[0] == INQUIRY && -- r->req.cmd.buf[2] == 0xb0) { -- uint32_t max_transfer = -- blk_get_max_transfer(s->conf.blk) / s->blocksize; -- -- assert(max_transfer); -- stl_be_p(&r->buf[8], max_transfer); -- /* Also take care of the opt xfer len. */ -- stl_be_p(&r->buf[12], -- MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12]))); -+ if (r->req.cmd.buf[0] == INQUIRY) { -+ /* -+ * EVPD set to zero returns the standard INQUIRY data. -+ * -+ * Check if scsi_version is unset (-1) to avoid re-defining it -+ * each time an INQUIRY with standard data is received. -+ * scsi_version is initialized with -1 in scsi_generic_reset -+ * and scsi_disk_reset, making sure that we'll set the -+ * scsi_version after a reset. If the version field of the -+ * INQUIRY response somehow changes after a guest reboot, -+ * we'll be able to keep track of it. -+ * -+ * On SCSI-2 and older, first 3 bits of byte 2 is the -+ * ANSI-approved version, while on later versions the -+ * whole byte 2 contains the version. Check if we're dealing -+ * with a newer version and, in that case, assign the -+ * whole byte. -+ */ -+ if (s->scsi_version == -1 && !(r->req.cmd.buf[1] & 0x01)) { -+ s->scsi_version = r->buf[2] & 0x07; -+ if (s->scsi_version > 2) { -+ s->scsi_version = r->buf[2]; -+ } -+ } -+ if (s->type == TYPE_DISK && r->req.cmd.buf[2] == 0xb0) { -+ uint32_t max_transfer = -+ blk_get_max_transfer(s->conf.blk) / s->blocksize; -+ -+ assert(max_transfer); -+ stl_be_p(&r->buf[8], max_transfer); -+ /* Also take care of the opt xfer len. */ -+ stl_be_p(&r->buf[12], -+ MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12]))); -+ } - } - scsi_req_data(&r->req, len); - scsi_req_unref(&r->req); -@@ -552,6 +575,8 @@ static void scsi_generic_realize(SCSIDevice *s, Error **errp) - - DPRINTF("block size %d\n", s->blocksize); - -+ /* Only used by scsi-block, but initialize it nevertheless to be clean. */ -+ s->default_scsi_version = -1; - scsi_generic_read_device_identification(s); - } - --- -1.8.3.1 - diff --git a/SOURCES/kvm-hw-usb-dev-smartcard-reader-Handle-64-B-USB-packets.patch b/SOURCES/kvm-hw-usb-dev-smartcard-reader-Handle-64-B-USB-packets.patch new file mode 100644 index 0000000..0e288b3 --- /dev/null +++ b/SOURCES/kvm-hw-usb-dev-smartcard-reader-Handle-64-B-USB-packets.patch @@ -0,0 +1,97 @@ +From a05d849be393110a4efacb148197434c095e06e2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Thu, 16 Aug 2018 10:41:54 +0200 +Subject: [PATCH 3/5] hw/usb/dev-smartcard-reader: Handle 64 B USB packets +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Marc-André Lureau +Message-id: <20180816104154.18782-1-marcandre.lureau@redhat.com> +Patchwork-id: 81855 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH] hw/usb/dev-smartcard-reader: Handle 64 B USB packets +Bugzilla: 1589147 +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Igor Mammedov +RH-Acked-by: Miroslav Rezanina + +From: Jakub Jelen + +The current code was not correctly handling 64 B (Max USB 1.1 payload size) +packets and therefore preventing some of the messages from smart card to +pass through to the guest. + +If the smart card in host responded with 34 B of data in APDU layer, the +CCID headers added up to 64 B. The packet was send, but not correctly +committed per USB specification (8.5.3.2 Variable-length Data Stage): + +> When all of the data structure is returned to the host, the function +> should indicate that the Data stage is ended by returning a packet +> that is shorter than the MaxPacketSize for the pipe. If the data +> structure is an exact multiple of wMaxPacketSize for the pipe, the +> function will return a zero-length packet to indicate the end of the +> Data stage. + +This lead the guest applications to timeout while waiting for the rest +of data (the emulation layer is answering with NAK until the timeout). + +This patch is checking the current maximum packet size and if the +payload of this size is detected, the message buffer is not yet released. +With the next call, the empty buffer is sent and the message buffer +is finally released. + +Signed-off-by: Jakub Jelen +Message-id: 20180516115544.3897-2-jjelen@redhat.com +Signed-off-by: Gerd Hoffmann + +(cherry picked from commit 8030dca376fa1bc4d8a6be7628196578f8783ab3) + +Signed-off-by: Marc-André Lureau +Signed-off-by: Miroslav Rezanina +--- + hw/usb/dev-smartcard-reader.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c +index e646805..214d3e9 100644 +--- a/hw/usb/dev-smartcard-reader.c ++++ b/hw/usb/dev-smartcard-reader.c +@@ -1064,7 +1064,8 @@ err: + return; + } + +-static void ccid_bulk_in_copy_to_guest(USBCCIDState *s, USBPacket *p) ++static void ccid_bulk_in_copy_to_guest(USBCCIDState *s, USBPacket *p, ++ unsigned int max_packet_size) + { + int len = 0; + +@@ -1072,10 +1073,13 @@ static void ccid_bulk_in_copy_to_guest(USBCCIDState *s, USBPacket *p) + if (s->current_bulk_in != NULL) { + len = MIN(s->current_bulk_in->len - s->current_bulk_in->pos, + p->iov.size); +- usb_packet_copy(p, s->current_bulk_in->data + +- s->current_bulk_in->pos, len); ++ if (len) { ++ usb_packet_copy(p, s->current_bulk_in->data + ++ s->current_bulk_in->pos, len); ++ } + s->current_bulk_in->pos += len; +- if (s->current_bulk_in->pos == s->current_bulk_in->len) { ++ if (s->current_bulk_in->pos == s->current_bulk_in->len ++ && len != max_packet_size) { + ccid_bulk_in_release(s); + } + } else { +@@ -1107,7 +1111,7 @@ static void ccid_handle_data(USBDevice *dev, USBPacket *p) + case USB_TOKEN_IN: + switch (p->ep->nr) { + case CCID_BULK_IN_EP: +- ccid_bulk_in_copy_to_guest(s, p); ++ ccid_bulk_in_copy_to_guest(s, p, dev->ep_ctl.max_packet_size); + break; + case CCID_INT_IN_EP: + if (s->notify_slot_change) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-i386-Add-cache-information-in-X86CPUDefinition.patch b/SOURCES/kvm-i386-Add-cache-information-in-X86CPUDefinition.patch new file mode 100644 index 0000000..8c56680 --- /dev/null +++ b/SOURCES/kvm-i386-Add-cache-information-in-X86CPUDefinition.patch @@ -0,0 +1,71 @@ +From 0636bd2be78ee1df4a6a661e568ef02175f23127 Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Tue, 3 Jul 2018 17:23:48 +0200 +Subject: [PATCH 03/89] i386: Add cache information in X86CPUDefinition + +RH-Author: Eduardo Habkost +Message-id: <20180703172356.21038-3-ehabkost@redhat.com> +Patchwork-id: 81211 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v3 02/10] i386: Add cache information in X86CPUDefinition +Bugzilla: 1481253 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Igor Mammedov +RH-Acked-by: Miroslav Rezanina + +From: Babu Moger + +Add cache information in X86CPUDefinition and CPUX86State. + +Signed-off-by: Babu Moger +Tested-by: Geoffrey McRae +Reviewed-by: Eduardo Habkost +Message-Id: <20180510204148.11687-3-babu.moger@amd.com> +Signed-off-by: Eduardo Habkost +(cherry picked from commit 6aaeb05492ef668f415324f43e7d875c0f1e90b3) +Signed-off-by: Eduardo Habkost +Signed-off-by: Miroslav Rezanina +--- + target/i386/cpu.c | 1 + + target/i386/cpu.h | 7 +++++++ + 2 files changed, 8 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 9a5a164..7e81e08 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -1105,6 +1105,7 @@ struct X86CPUDefinition { + int stepping; + FeatureWordArray features; + const char *model_id; ++ CPUCaches *cache_info; + }; + + static X86CPUDefinition builtin_x86_defs[] = { +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index a0e4eeb..912aa34 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -1098,6 +1098,12 @@ typedef struct CPUCacheInfo { + } CPUCacheInfo; + + ++typedef struct CPUCaches { ++ CPUCacheInfo l1d_cache; ++ CPUCacheInfo l1i_cache; ++ CPUCacheInfo l2_cache; ++ CPUCacheInfo l3_cache; ++} CPUCaches; + + typedef struct CPUX86State { + /* standard registers */ +@@ -1285,6 +1291,7 @@ typedef struct CPUX86State { + /* Features that were explicitly enabled/disabled */ + FeatureWordArray user_features; + uint32_t cpuid_model[12]; ++ CPUCaches *cache_info; + + /* MTRRs */ + uint64_t mtrr_fixed[11]; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-i386-Add-new-property-to-control-cache-info.patch b/SOURCES/kvm-i386-Add-new-property-to-control-cache-info.patch new file mode 100644 index 0000000..24308e3 --- /dev/null +++ b/SOURCES/kvm-i386-Add-new-property-to-control-cache-info.patch @@ -0,0 +1,287 @@ +From 64b860ac7db707ef2a29d957b794c831637315a6 Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Tue, 3 Jul 2018 17:23:50 +0200 +Subject: [PATCH 05/89] i386: Add new property to control cache info + +RH-Author: Eduardo Habkost +Message-id: <20180703172356.21038-5-ehabkost@redhat.com> +Patchwork-id: 81212 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v3 04/10] i386: Add new property to control cache info +Bugzilla: 1481253 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Igor Mammedov +RH-Acked-by: Miroslav Rezanina + +From: Babu Moger + +The property legacy-cache will be used to control the cache information. +If user passes "-cpu legacy-cache" then older information will +be displayed even if the hardware supports new information. Otherwise +use the statically loaded cache definitions if available. + +Renamed the previous cache structures to legacy_*. If there is any change in +the cache information, then it needs to be initialized in builtin_x86_defs. + +Signed-off-by: Babu Moger +Tested-by: Geoffrey McRae +Message-Id: <20180514164156.27034-3-babu.moger@amd.com> +Reviewed-by: Eduardo Habkost +Signed-off-by: Eduardo Habkost +(cherry picked from commit ab8f992e3e63e91be257e4e343d386dae7be4bcb) +Signed-off-by: Eduardo Habkost +Signed-off-by: Miroslav Rezanina +--- + include/hw/i386/pc.h | 4 +++ + target/i386/cpu.c | 97 ++++++++++++++++++++++++++++++++++++++-------------- + target/i386/cpu.h | 5 +++ + 3 files changed, 80 insertions(+), 26 deletions(-) + +diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h +index d5a0827..3ff55c6 100644 +--- a/include/hw/i386/pc.h ++++ b/include/hw/i386/pc.h +@@ -979,6 +979,10 @@ extern void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id); + .driver = "Skylake-Server" "-" TYPE_X86_CPU,\ + .property = "clflushopt",\ + .value = "off",\ ++ },{ /* PC_RHEL7_5_COMPAT from PC_COMPAT_2_12 */ \ ++ .driver = TYPE_X86_CPU,\ ++ .property = "legacy-cache",\ ++ .value = "on",\ + }, + + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 23eb47d..3426130 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -336,10 +336,14 @@ static void encode_cache_cpuid80000006(CPUCacheInfo *l2, + } + } + +-/* Definitions of the hardcoded cache entries we expose: */ ++/* ++ * Definitions of the hardcoded cache entries we expose: ++ * These are legacy cache values. If there is a need to change any ++ * of these values please use builtin_x86_defs ++ */ + + /* L1 data cache: */ +-static CPUCacheInfo l1d_cache = { ++static CPUCacheInfo legacy_l1d_cache = { + .type = DCACHE, + .level = 1, + .size = 32 * KiB, +@@ -352,7 +356,7 @@ static CPUCacheInfo l1d_cache = { + }; + + /*FIXME: CPUID leaf 0x80000005 is inconsistent with leaves 2 & 4 */ +-static CPUCacheInfo l1d_cache_amd = { ++static CPUCacheInfo legacy_l1d_cache_amd = { + .type = DCACHE, + .level = 1, + .size = 64 * KiB, +@@ -366,7 +370,7 @@ static CPUCacheInfo l1d_cache_amd = { + }; + + /* L1 instruction cache: */ +-static CPUCacheInfo l1i_cache = { ++static CPUCacheInfo legacy_l1i_cache = { + .type = ICACHE, + .level = 1, + .size = 32 * KiB, +@@ -379,7 +383,7 @@ static CPUCacheInfo l1i_cache = { + }; + + /*FIXME: CPUID leaf 0x80000005 is inconsistent with leaves 2 & 4 */ +-static CPUCacheInfo l1i_cache_amd = { ++static CPUCacheInfo legacy_l1i_cache_amd = { + .type = ICACHE, + .level = 1, + .size = 64 * KiB, +@@ -393,7 +397,7 @@ static CPUCacheInfo l1i_cache_amd = { + }; + + /* Level 2 unified cache: */ +-static CPUCacheInfo l2_cache = { ++static CPUCacheInfo legacy_l2_cache = { + .type = UNIFIED_CACHE, + .level = 2, + .size = 4 * MiB, +@@ -406,7 +410,7 @@ static CPUCacheInfo l2_cache = { + }; + + /*FIXME: CPUID leaf 2 descriptor is inconsistent with CPUID leaf 4 */ +-static CPUCacheInfo l2_cache_cpuid2 = { ++static CPUCacheInfo legacy_l2_cache_cpuid2 = { + .type = UNIFIED_CACHE, + .level = 2, + .size = 2 * MiB, +@@ -416,7 +420,7 @@ static CPUCacheInfo l2_cache_cpuid2 = { + + + /*FIXME: CPUID leaf 0x80000006 is inconsistent with leaves 2 & 4 */ +-static CPUCacheInfo l2_cache_amd = { ++static CPUCacheInfo legacy_l2_cache_amd = { + .type = UNIFIED_CACHE, + .level = 2, + .size = 512 * KiB, +@@ -428,7 +432,7 @@ static CPUCacheInfo l2_cache_amd = { + }; + + /* Level 3 unified cache: */ +-static CPUCacheInfo l3_cache = { ++static CPUCacheInfo legacy_l3_cache = { + .type = UNIFIED_CACHE, + .level = 3, + .size = 16 * MiB, +@@ -3321,6 +3325,10 @@ static void x86_cpu_load_def(X86CPU *cpu, X86CPUDefinition *def, Error **errp) + env->features[w] = def->features[w]; + } + ++ /* Store Cache information from the X86CPUDefinition if available */ ++ env->cache_info = def->cache_info; ++ cpu->legacy_cache = def->cache_info ? 0 : 1; ++ + /* Special cases not set in the X86CPUDefinition structs: */ + /* TODO: in-kernel irqchip for hvf */ + if (kvm_enabled()) { +@@ -3670,11 +3678,21 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + if (!cpu->enable_l3_cache) { + *ecx = 0; + } else { +- *ecx = cpuid2_cache_descriptor(&l3_cache); ++ if (env->cache_info && !cpu->legacy_cache) { ++ *ecx = cpuid2_cache_descriptor(&env->cache_info->l3_cache); ++ } else { ++ *ecx = cpuid2_cache_descriptor(&legacy_l3_cache); ++ } ++ } ++ if (env->cache_info && !cpu->legacy_cache) { ++ *edx = (cpuid2_cache_descriptor(&env->cache_info->l1d_cache) << 16) | ++ (cpuid2_cache_descriptor(&env->cache_info->l1i_cache) << 8) | ++ (cpuid2_cache_descriptor(&env->cache_info->l2_cache)); ++ } else { ++ *edx = (cpuid2_cache_descriptor(&legacy_l1d_cache) << 16) | ++ (cpuid2_cache_descriptor(&legacy_l1i_cache) << 8) | ++ (cpuid2_cache_descriptor(&legacy_l2_cache_cpuid2)); + } +- *edx = (cpuid2_cache_descriptor(&l1d_cache) << 16) | +- (cpuid2_cache_descriptor(&l1i_cache) << 8) | +- (cpuid2_cache_descriptor(&l2_cache_cpuid2)); + break; + case 4: + /* cache info: needed for Core compatibility */ +@@ -3687,27 +3705,35 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + } + } else { + *eax = 0; ++ CPUCacheInfo *l1d, *l1i, *l2, *l3; ++ if (env->cache_info && !cpu->legacy_cache) { ++ l1d = &env->cache_info->l1d_cache; ++ l1i = &env->cache_info->l1i_cache; ++ l2 = &env->cache_info->l2_cache; ++ l3 = &env->cache_info->l3_cache; ++ } else { ++ l1d = &legacy_l1d_cache; ++ l1i = &legacy_l1i_cache; ++ l2 = &legacy_l2_cache; ++ l3 = &legacy_l3_cache; ++ } + switch (count) { + case 0: /* L1 dcache info */ +- encode_cache_cpuid4(&l1d_cache, +- 1, cs->nr_cores, ++ encode_cache_cpuid4(l1d, 1, cs->nr_cores, + eax, ebx, ecx, edx); + break; + case 1: /* L1 icache info */ +- encode_cache_cpuid4(&l1i_cache, +- 1, cs->nr_cores, ++ encode_cache_cpuid4(l1i, 1, cs->nr_cores, + eax, ebx, ecx, edx); + break; + case 2: /* L2 cache info */ +- encode_cache_cpuid4(&l2_cache, +- cs->nr_threads, cs->nr_cores, ++ encode_cache_cpuid4(l2, cs->nr_threads, cs->nr_cores, + eax, ebx, ecx, edx); + break; + case 3: /* L3 cache info */ + pkg_offset = apicid_pkg_offset(cs->nr_cores, cs->nr_threads); + if (cpu->enable_l3_cache) { +- encode_cache_cpuid4(&l3_cache, +- (1 << pkg_offset), cs->nr_cores, ++ encode_cache_cpuid4(l3, (1 << pkg_offset), cs->nr_cores, + eax, ebx, ecx, edx); + break; + } +@@ -3920,8 +3946,13 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + (L1_ITLB_2M_ASSOC << 8) | (L1_ITLB_2M_ENTRIES); + *ebx = (L1_DTLB_4K_ASSOC << 24) | (L1_DTLB_4K_ENTRIES << 16) | \ + (L1_ITLB_4K_ASSOC << 8) | (L1_ITLB_4K_ENTRIES); +- *ecx = encode_cache_cpuid80000005(&l1d_cache_amd); +- *edx = encode_cache_cpuid80000005(&l1i_cache_amd); ++ if (env->cache_info && !cpu->legacy_cache) { ++ *ecx = encode_cache_cpuid80000005(&env->cache_info->l1d_cache); ++ *edx = encode_cache_cpuid80000005(&env->cache_info->l1i_cache); ++ } else { ++ *ecx = encode_cache_cpuid80000005(&legacy_l1d_cache_amd); ++ *edx = encode_cache_cpuid80000005(&legacy_l1i_cache_amd); ++ } + break; + case 0x80000006: + /* cache info (L2 cache) */ +@@ -3937,9 +3968,17 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + (L2_DTLB_4K_ENTRIES << 16) | \ + (AMD_ENC_ASSOC(L2_ITLB_4K_ASSOC) << 12) | \ + (L2_ITLB_4K_ENTRIES); +- encode_cache_cpuid80000006(&l2_cache_amd, +- cpu->enable_l3_cache ? &l3_cache : NULL, +- ecx, edx); ++ if (env->cache_info && !cpu->legacy_cache) { ++ encode_cache_cpuid80000006(&env->cache_info->l2_cache, ++ cpu->enable_l3_cache ? ++ &env->cache_info->l3_cache : NULL, ++ ecx, edx); ++ } else { ++ encode_cache_cpuid80000006(&legacy_l2_cache_amd, ++ cpu->enable_l3_cache ? ++ &legacy_l3_cache : NULL, ++ ecx, edx); ++ } + break; + case 0x80000007: + *eax = 0; +@@ -5119,6 +5158,12 @@ static Property x86_cpu_properties[] = { + false), + DEFINE_PROP_BOOL("vmware-cpuid-freq", X86CPU, vmware_cpuid_freq, true), + DEFINE_PROP_BOOL("tcg-cpuid", X86CPU, expose_tcg, true), ++ /* ++ * lecacy_cache defaults to CPU model being chosen. This is set in ++ * x86_cpu_load_def based on cache_info which is initialized in ++ * builtin_x86_defs ++ */ ++ DEFINE_PROP_BOOL("legacy-cache", X86CPU, legacy_cache, false), + + /* + * From "Requirements for Implementing the Microsoft +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 912aa34..b01b0c1 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -1397,6 +1397,11 @@ struct X86CPU { + */ + bool enable_l3_cache; + ++ /* Compatibility bits for old machine types. ++ * If true present the old cache topology information ++ */ ++ bool legacy_cache; ++ + /* Compatibility bits for old machine types: */ + bool enable_cpuid_0xb; + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-i386-Add-support-for-CPUID_8000_001E-for-AMD.patch b/SOURCES/kvm-i386-Add-support-for-CPUID_8000_001E-for-AMD.patch new file mode 100644 index 0000000..4aa1886 --- /dev/null +++ b/SOURCES/kvm-i386-Add-support-for-CPUID_8000_001E-for-AMD.patch @@ -0,0 +1,137 @@ +From 31d4822f7d25e9438de3dc7d689cfe3dd5544cc7 Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Tue, 3 Jul 2018 17:23:53 +0200 +Subject: [PATCH 08/89] i386: Add support for CPUID_8000_001E for AMD + +RH-Author: Eduardo Habkost +Message-id: <20180703172356.21038-8-ehabkost@redhat.com> +Patchwork-id: 81217 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v3 07/10] i386: Add support for CPUID_8000_001E for AMD +Bugzilla: 1481253 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Igor Mammedov +RH-Acked-by: Miroslav Rezanina + +From: Babu Moger + +Add support for cpuid leaf CPUID_8000_001E. Build the config that closely +match the underlying hardware. Please refer to the Processor Programming +Reference (PPR) for AMD Family 17h Model for more details. + +Signed-off-by: Babu Moger +Message-Id: <1528498581-131037-2-git-send-email-babu.moger@amd.com> +Signed-off-by: Eduardo Habkost +(cherry picked from commit ed78467a214595a63af7800a073a03ffe37cd7db) +Signed-off-by: Eduardo Habkost +Signed-off-by: Miroslav Rezanina +--- + target/i386/cpu.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 86 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 57f74c6..643d3b1 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -429,6 +429,87 @@ static void encode_cache_cpuid8000001d(CPUCacheInfo *cache, CPUState *cs, + (cache->complex_indexing ? CACHE_COMPLEX_IDX : 0); + } + ++/* Data structure to hold the configuration info for a given core index */ ++struct core_topology { ++ /* core complex id of the current core index */ ++ int ccx_id; ++ /* ++ * Adjusted core index for this core in the topology ++ * This can be 0,1,2,3 with max 4 cores in a core complex ++ */ ++ int core_id; ++ /* Node id for this core index */ ++ int node_id; ++ /* Number of nodes in this config */ ++ int num_nodes; ++}; ++ ++/* ++ * Build the configuration closely match the EPYC hardware. Using the EPYC ++ * hardware configuration values (MAX_CCX, MAX_CORES_IN_CCX, MAX_CORES_IN_NODE) ++ * right now. This could change in future. ++ * nr_cores : Total number of cores in the config ++ * core_id : Core index of the current CPU ++ * topo : Data structure to hold all the config info for this core index ++ */ ++static void build_core_topology(int nr_cores, int core_id, ++ struct core_topology *topo) ++{ ++ int nodes, cores_in_ccx; ++ ++ /* First get the number of nodes required */ ++ nodes = nodes_in_socket(nr_cores); ++ ++ cores_in_ccx = cores_in_core_complex(nr_cores); ++ ++ topo->node_id = core_id / (cores_in_ccx * MAX_CCX); ++ topo->ccx_id = (core_id % (cores_in_ccx * MAX_CCX)) / cores_in_ccx; ++ topo->core_id = core_id % cores_in_ccx; ++ topo->num_nodes = nodes; ++} ++ ++/* Encode cache info for CPUID[8000001E] */ ++static void encode_topo_cpuid8000001e(CPUState *cs, X86CPU *cpu, ++ uint32_t *eax, uint32_t *ebx, ++ uint32_t *ecx, uint32_t *edx) ++{ ++ struct core_topology topo = {0}; ++ ++ build_core_topology(cs->nr_cores, cpu->core_id, &topo); ++ *eax = cpu->apic_id; ++ /* ++ * CPUID_Fn8000001E_EBX ++ * 31:16 Reserved ++ * 15:8 Threads per core (The number of threads per core is ++ * Threads per core + 1) ++ * 7:0 Core id (see bit decoding below) ++ * SMT: ++ * 4:3 node id ++ * 2 Core complex id ++ * 1:0 Core id ++ * Non SMT: ++ * 5:4 node id ++ * 3 Core complex id ++ * 1:0 Core id ++ */ ++ if (cs->nr_threads - 1) { ++ *ebx = ((cs->nr_threads - 1) << 8) | (topo.node_id << 3) | ++ (topo.ccx_id << 2) | topo.core_id; ++ } else { ++ *ebx = (topo.node_id << 4) | (topo.ccx_id << 3) | topo.core_id; ++ } ++ /* ++ * CPUID_Fn8000001E_ECX ++ * 31:11 Reserved ++ * 10:8 Nodes per processor (Nodes per processor is number of nodes + 1) ++ * 7:0 Node id (see bit decoding below) ++ * 2 Socket id ++ * 1:0 Node id ++ */ ++ *ecx = ((topo.num_nodes - 1) << 8) | (cpu->socket_id << 2) | topo.node_id; ++ *edx = 0; ++} ++ + /* + * Definitions of the hardcoded cache entries we expose: + * These are legacy cache values. If there is a need to change any +@@ -4105,6 +4186,11 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + break; + } + break; ++ case 0x8000001E: ++ assert(cpu->core_id <= 255); ++ encode_topo_cpuid8000001e(cs, cpu, ++ eax, ebx, ecx, edx); ++ break; + case 0xC0000000: + *eax = env->cpuid_xlevel2; + *ebx = 0; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-i386-Allow-TOPOEXT-to-be-enabled-on-older-kernels.patch b/SOURCES/kvm-i386-Allow-TOPOEXT-to-be-enabled-on-older-kernels.patch new file mode 100644 index 0000000..17b0876 --- /dev/null +++ b/SOURCES/kvm-i386-Allow-TOPOEXT-to-be-enabled-on-older-kernels.patch @@ -0,0 +1,53 @@ +From 499c2933a848699a80edd44308e1c4f7497a8a66 Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Thu, 26 Jul 2018 15:25:35 +0200 +Subject: [PATCH 10/15] i386: Allow TOPOEXT to be enabled on older kernels + +RH-Author: Eduardo Habkost +Message-id: <20180726152535.4493-2-ehabkost@redhat.com> +Patchwork-id: 81513 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/1] i386: Allow TOPOEXT to be enabled on older kernels +Bugzilla: 1608698 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Igor Mammedov + +From: Babu Moger + +Enabling TOPOEXT feature might cause compatibility issues if +older kernels does not set this feature. Lets set this feature +unconditionally. + +Signed-off-by: Babu Moger +Message-Id: <1528939107-17193-2-git-send-email-babu.moger@amd.com> +[ehabkost: rewrite comment and commit message] +Signed-off-by: Eduardo Habkost +(cherry picked from commit f98bbd8304112187cafc3e636c31b2a3865d2717) +Signed-off-by: Eduardo Habkost + +Signed-off-by: Miroslav Rezanina +--- + target/i386/kvm.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/target/i386/kvm.c b/target/i386/kvm.c +index 447215b..00f2141 100644 +--- a/target/i386/kvm.c ++++ b/target/i386/kvm.c +@@ -372,6 +372,13 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function, + if (host_tsx_blacklisted()) { + ret &= ~(CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_HLE); + } ++ } else if (function == 0x80000001 && reg == R_ECX) { ++ /* ++ * It's safe to enable TOPOEXT even if it's not returned by ++ * GET_SUPPORTED_CPUID. Unconditionally enabling TOPOEXT here allows ++ * us to keep CPU models including TOPOEXT runnable on older kernels. ++ */ ++ ret |= CPUID_EXT3_TOPOEXT; + } else if (function == 0x80000001 && reg == R_EDX) { + /* On Intel, kvm returns cpuid according to the Intel spec, + * so add missing bits according to the AMD spec: +-- +1.8.3.1 + diff --git a/SOURCES/kvm-i386-Clean-up-cache-CPUID-code.patch b/SOURCES/kvm-i386-Clean-up-cache-CPUID-code.patch new file mode 100644 index 0000000..93e20b1 --- /dev/null +++ b/SOURCES/kvm-i386-Clean-up-cache-CPUID-code.patch @@ -0,0 +1,280 @@ +From 98205e71073c36234048b60feedc1ce142902572 Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Tue, 3 Jul 2018 17:23:51 +0200 +Subject: [PATCH 06/89] i386: Clean up cache CPUID code + +RH-Author: Eduardo Habkost +Message-id: <20180703172356.21038-6-ehabkost@redhat.com> +Patchwork-id: 81215 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v3 05/10] i386: Clean up cache CPUID code +Bugzilla: 1481253 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Igor Mammedov +RH-Acked-by: Miroslav Rezanina + +Always initialize CPUCaches structs with cache information, even +if legacy_cache=true. Use different CPUCaches struct for +CPUID[2], CPUID[4], and the AMD CPUID leaves. + +This will simplify a lot the logic inside cpu_x86_cpuid(). + +Signed-off-by: Eduardo Habkost +Signed-off-by: Babu Moger +Message-Id: <1527176614-26271-2-git-send-email-babu.moger@amd.com> +Signed-off-by: Eduardo Habkost +(cherry picked from commit a9f27ea9adc8c695197bd08f2e938ef7b4183f07) +Signed-off-by: Eduardo Habkost +Signed-off-by: Miroslav Rezanina +--- + target/i386/cpu.c | 117 +++++++++++++++++++++++++++--------------------------- + target/i386/cpu.h | 14 ++++--- + 2 files changed, 67 insertions(+), 64 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 3426130..41d0b72 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -1113,7 +1113,7 @@ struct X86CPUDefinition { + }; + + static CPUCaches epyc_cache_info = { +- .l1d_cache = { ++ .l1d_cache = &(CPUCacheInfo) { + .type = DCACHE, + .level = 1, + .size = 32 * KiB, +@@ -1125,7 +1125,7 @@ static CPUCaches epyc_cache_info = { + .self_init = 1, + .no_invd_sharing = true, + }, +- .l1i_cache = { ++ .l1i_cache = &(CPUCacheInfo) { + .type = ICACHE, + .level = 1, + .size = 64 * KiB, +@@ -1137,7 +1137,7 @@ static CPUCaches epyc_cache_info = { + .self_init = 1, + .no_invd_sharing = true, + }, +- .l2_cache = { ++ .l2_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, + .level = 2, + .size = 512 * KiB, +@@ -1147,7 +1147,7 @@ static CPUCaches epyc_cache_info = { + .sets = 1024, + .lines_per_tag = 1, + }, +- .l3_cache = { ++ .l3_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, + .level = 3, + .size = 8 * MiB, +@@ -3325,9 +3325,8 @@ static void x86_cpu_load_def(X86CPU *cpu, X86CPUDefinition *def, Error **errp) + env->features[w] = def->features[w]; + } + +- /* Store Cache information from the X86CPUDefinition if available */ +- env->cache_info = def->cache_info; +- cpu->legacy_cache = def->cache_info ? 0 : 1; ++ /* legacy-cache defaults to 'off' if CPU model provides cache info */ ++ cpu->legacy_cache = !def->cache_info; + + /* Special cases not set in the X86CPUDefinition structs: */ + /* TODO: in-kernel irqchip for hvf */ +@@ -3678,21 +3677,11 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + if (!cpu->enable_l3_cache) { + *ecx = 0; + } else { +- if (env->cache_info && !cpu->legacy_cache) { +- *ecx = cpuid2_cache_descriptor(&env->cache_info->l3_cache); +- } else { +- *ecx = cpuid2_cache_descriptor(&legacy_l3_cache); +- } +- } +- if (env->cache_info && !cpu->legacy_cache) { +- *edx = (cpuid2_cache_descriptor(&env->cache_info->l1d_cache) << 16) | +- (cpuid2_cache_descriptor(&env->cache_info->l1i_cache) << 8) | +- (cpuid2_cache_descriptor(&env->cache_info->l2_cache)); +- } else { +- *edx = (cpuid2_cache_descriptor(&legacy_l1d_cache) << 16) | +- (cpuid2_cache_descriptor(&legacy_l1i_cache) << 8) | +- (cpuid2_cache_descriptor(&legacy_l2_cache_cpuid2)); ++ *ecx = cpuid2_cache_descriptor(env->cache_info_cpuid2.l3_cache); + } ++ *edx = (cpuid2_cache_descriptor(env->cache_info_cpuid2.l1d_cache) << 16) | ++ (cpuid2_cache_descriptor(env->cache_info_cpuid2.l1i_cache) << 8) | ++ (cpuid2_cache_descriptor(env->cache_info_cpuid2.l2_cache)); + break; + case 4: + /* cache info: needed for Core compatibility */ +@@ -3705,35 +3694,27 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + } + } else { + *eax = 0; +- CPUCacheInfo *l1d, *l1i, *l2, *l3; +- if (env->cache_info && !cpu->legacy_cache) { +- l1d = &env->cache_info->l1d_cache; +- l1i = &env->cache_info->l1i_cache; +- l2 = &env->cache_info->l2_cache; +- l3 = &env->cache_info->l3_cache; +- } else { +- l1d = &legacy_l1d_cache; +- l1i = &legacy_l1i_cache; +- l2 = &legacy_l2_cache; +- l3 = &legacy_l3_cache; +- } + switch (count) { + case 0: /* L1 dcache info */ +- encode_cache_cpuid4(l1d, 1, cs->nr_cores, ++ encode_cache_cpuid4(env->cache_info_cpuid4.l1d_cache, ++ 1, cs->nr_cores, + eax, ebx, ecx, edx); + break; + case 1: /* L1 icache info */ +- encode_cache_cpuid4(l1i, 1, cs->nr_cores, ++ encode_cache_cpuid4(env->cache_info_cpuid4.l1i_cache, ++ 1, cs->nr_cores, + eax, ebx, ecx, edx); + break; + case 2: /* L2 cache info */ +- encode_cache_cpuid4(l2, cs->nr_threads, cs->nr_cores, ++ encode_cache_cpuid4(env->cache_info_cpuid4.l2_cache, ++ cs->nr_threads, cs->nr_cores, + eax, ebx, ecx, edx); + break; + case 3: /* L3 cache info */ + pkg_offset = apicid_pkg_offset(cs->nr_cores, cs->nr_threads); + if (cpu->enable_l3_cache) { +- encode_cache_cpuid4(l3, (1 << pkg_offset), cs->nr_cores, ++ encode_cache_cpuid4(env->cache_info_cpuid4.l3_cache, ++ (1 << pkg_offset), cs->nr_cores, + eax, ebx, ecx, edx); + break; + } +@@ -3946,13 +3927,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + (L1_ITLB_2M_ASSOC << 8) | (L1_ITLB_2M_ENTRIES); + *ebx = (L1_DTLB_4K_ASSOC << 24) | (L1_DTLB_4K_ENTRIES << 16) | \ + (L1_ITLB_4K_ASSOC << 8) | (L1_ITLB_4K_ENTRIES); +- if (env->cache_info && !cpu->legacy_cache) { +- *ecx = encode_cache_cpuid80000005(&env->cache_info->l1d_cache); +- *edx = encode_cache_cpuid80000005(&env->cache_info->l1i_cache); +- } else { +- *ecx = encode_cache_cpuid80000005(&legacy_l1d_cache_amd); +- *edx = encode_cache_cpuid80000005(&legacy_l1i_cache_amd); +- } ++ *ecx = encode_cache_cpuid80000005(env->cache_info_amd.l1d_cache); ++ *edx = encode_cache_cpuid80000005(env->cache_info_amd.l1i_cache); + break; + case 0x80000006: + /* cache info (L2 cache) */ +@@ -3968,17 +3944,10 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + (L2_DTLB_4K_ENTRIES << 16) | \ + (AMD_ENC_ASSOC(L2_ITLB_4K_ASSOC) << 12) | \ + (L2_ITLB_4K_ENTRIES); +- if (env->cache_info && !cpu->legacy_cache) { +- encode_cache_cpuid80000006(&env->cache_info->l2_cache, +- cpu->enable_l3_cache ? +- &env->cache_info->l3_cache : NULL, +- ecx, edx); +- } else { +- encode_cache_cpuid80000006(&legacy_l2_cache_amd, +- cpu->enable_l3_cache ? +- &legacy_l3_cache : NULL, +- ecx, edx); +- } ++ encode_cache_cpuid80000006(env->cache_info_amd.l2_cache, ++ cpu->enable_l3_cache ? ++ env->cache_info_amd.l3_cache : NULL, ++ ecx, edx); + break; + case 0x80000007: + *eax = 0; +@@ -4675,6 +4644,37 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) + cpu->phys_bits = 32; + } + } ++ ++ /* Cache information initialization */ ++ if (!cpu->legacy_cache) { ++ if (!xcc->cpu_def || !xcc->cpu_def->cache_info) { ++ char *name = x86_cpu_class_get_model_name(xcc); ++ error_setg(errp, ++ "CPU model '%s' doesn't support legacy-cache=off", name); ++ g_free(name); ++ return; ++ } ++ env->cache_info_cpuid2 = env->cache_info_cpuid4 = env->cache_info_amd = ++ *xcc->cpu_def->cache_info; ++ } else { ++ /* Build legacy cache information */ ++ env->cache_info_cpuid2.l1d_cache = &legacy_l1d_cache; ++ env->cache_info_cpuid2.l1i_cache = &legacy_l1i_cache; ++ env->cache_info_cpuid2.l2_cache = &legacy_l2_cache_cpuid2; ++ env->cache_info_cpuid2.l3_cache = &legacy_l3_cache; ++ ++ env->cache_info_cpuid4.l1d_cache = &legacy_l1d_cache; ++ env->cache_info_cpuid4.l1i_cache = &legacy_l1i_cache; ++ env->cache_info_cpuid4.l2_cache = &legacy_l2_cache; ++ env->cache_info_cpuid4.l3_cache = &legacy_l3_cache; ++ ++ env->cache_info_amd.l1d_cache = &legacy_l1d_cache_amd; ++ env->cache_info_amd.l1i_cache = &legacy_l1i_cache_amd; ++ env->cache_info_amd.l2_cache = &legacy_l2_cache_amd; ++ env->cache_info_amd.l3_cache = &legacy_l3_cache; ++ } ++ ++ + cpu_exec_realizefn(cs, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); +@@ -5159,11 +5159,10 @@ static Property x86_cpu_properties[] = { + DEFINE_PROP_BOOL("vmware-cpuid-freq", X86CPU, vmware_cpuid_freq, true), + DEFINE_PROP_BOOL("tcg-cpuid", X86CPU, expose_tcg, true), + /* +- * lecacy_cache defaults to CPU model being chosen. This is set in +- * x86_cpu_load_def based on cache_info which is initialized in +- * builtin_x86_defs ++ * lecacy_cache defaults to true unless the CPU model provides its ++ * own cache information (see x86_cpu_load_def()). + */ +- DEFINE_PROP_BOOL("legacy-cache", X86CPU, legacy_cache, false), ++ DEFINE_PROP_BOOL("legacy-cache", X86CPU, legacy_cache, true), + + /* + * From "Requirements for Implementing the Microsoft +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index b01b0c1..c80c461 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -1099,10 +1099,10 @@ typedef struct CPUCacheInfo { + + + typedef struct CPUCaches { +- CPUCacheInfo l1d_cache; +- CPUCacheInfo l1i_cache; +- CPUCacheInfo l2_cache; +- CPUCacheInfo l3_cache; ++ CPUCacheInfo *l1d_cache; ++ CPUCacheInfo *l1i_cache; ++ CPUCacheInfo *l2_cache; ++ CPUCacheInfo *l3_cache; + } CPUCaches; + + typedef struct CPUX86State { +@@ -1291,7 +1291,11 @@ typedef struct CPUX86State { + /* Features that were explicitly enabled/disabled */ + FeatureWordArray user_features; + uint32_t cpuid_model[12]; +- CPUCaches *cache_info; ++ /* Cache information for CPUID. When legacy-cache=on, the cache data ++ * on each CPUID leaf will be different, because we keep compatibility ++ * with old QEMU versions. ++ */ ++ CPUCaches cache_info_cpuid2, cache_info_cpuid4, cache_info_amd; + + /* MTRRs */ + uint64_t mtrr_fixed[11]; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-i386-Define-the-Virt-SSBD-MSR-and-handling-of-it-CVE.patch b/SOURCES/kvm-i386-Define-the-Virt-SSBD-MSR-and-handling-of-it-CVE.patch new file mode 100644 index 0000000..86e1324 --- /dev/null +++ b/SOURCES/kvm-i386-Define-the-Virt-SSBD-MSR-and-handling-of-it-CVE.patch @@ -0,0 +1,164 @@ +From 72fa5081eba5db48161c5edfdc75b5246a5cf455 Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Wed, 13 Jun 2018 18:08:11 +0200 +Subject: [PATCH 04/57] i386: Define the Virt SSBD MSR and handling of it + (CVE-2018-3639) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Eduardo Habkost +Message-id: <20180613180812.28169-2-ehabkost@redhat.com> +Patchwork-id: 80677 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/2] i386: Define the Virt SSBD MSR and handling of it (CVE-2018-3639) +Bugzilla: 1574216 +RH-Acked-by: Igor Mammedov +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: Laurent Vivier + +From: Konrad Rzeszutek Wilk + +"Some AMD processors only support a non-architectural means of enabling +speculative store bypass disable (SSBD). To allow a simplified view of +this to a guest, an architectural definition has been created through a new +CPUID bit, 0x80000008_EBX[25], and a new MSR, 0xc001011f. With this, a +hypervisor can virtualize the existence of this definition and provide an +architectural method for using SSBD to a guest. + +Add the new CPUID feature, the new MSR and update the existing SSBD +support to use this MSR when present." (from x86/speculation: Add virtualized +speculative store bypass disable support in Linux). + +Backport conflicts: + * target-i386/machine.c: trivial conflict with vmstate_xsave section + +Signed-off-by: Konrad Rzeszutek Wilk +Reviewed-by: Daniel P. Berrangé +Signed-off-by: Daniel P. Berrangé +Message-Id: <20180521215424.13520-4-berrange@redhat.com> +Signed-off-by: Eduardo Habkost +(cherry picked from commit cfeea0c021db6234c154dbc723730e81553924ff) +Signed-off-by: Eduardo Habkost +Signed-off-by: Miroslav Rezanina +--- + target/i386/cpu.h | 2 ++ + target/i386/kvm.c | 16 ++++++++++++++-- + target/i386/machine.c | 20 ++++++++++++++++++++ + 3 files changed, 36 insertions(+), 2 deletions(-) + +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 0c7a3d6..9aebe64 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -351,6 +351,7 @@ typedef enum X86Seg { + #define MSR_IA32_FEATURE_CONTROL 0x0000003a + #define MSR_TSC_ADJUST 0x0000003b + #define MSR_IA32_SPEC_CTRL 0x48 ++#define MSR_VIRT_SSBD 0xc001011f + #define MSR_IA32_TSCDEADLINE 0x6e0 + + #define FEATURE_CONTROL_LOCKED (1<<0) +@@ -1150,6 +1151,7 @@ typedef struct CPUX86State { + uint32_t pkru; + + uint64_t spec_ctrl; ++ uint64_t virt_ssbd; + + /* End of state preserved by INIT (dummy marker). */ + struct {} end_init_save; +diff --git a/target/i386/kvm.c b/target/i386/kvm.c +index 6c49954..19e6aa3 100644 +--- a/target/i386/kvm.c ++++ b/target/i386/kvm.c +@@ -92,6 +92,7 @@ static bool has_msr_hv_stimer; + static bool has_msr_hv_frequencies; + static bool has_msr_xss; + static bool has_msr_spec_ctrl; ++static bool has_msr_virt_ssbd; + static bool has_msr_smi_count; + + static uint32_t has_architectural_pmu_version; +@@ -1218,6 +1219,9 @@ static int kvm_get_supported_msrs(KVMState *s) + case MSR_IA32_SPEC_CTRL: + has_msr_spec_ctrl = true; + break; ++ case MSR_VIRT_SSBD: ++ has_msr_virt_ssbd = true; ++ break; + } + } + } +@@ -1706,6 +1710,10 @@ static int kvm_put_msrs(X86CPU *cpu, int level) + if (has_msr_spec_ctrl) { + kvm_msr_entry_add(cpu, MSR_IA32_SPEC_CTRL, env->spec_ctrl); + } ++ if (has_msr_virt_ssbd) { ++ kvm_msr_entry_add(cpu, MSR_VIRT_SSBD, env->virt_ssbd); ++ } ++ + #ifdef TARGET_X86_64 + if (lm_capable_kernel) { + kvm_msr_entry_add(cpu, MSR_CSTAR, env->cstar); +@@ -2077,8 +2085,9 @@ static int kvm_get_msrs(X86CPU *cpu) + if (has_msr_spec_ctrl) { + kvm_msr_entry_add(cpu, MSR_IA32_SPEC_CTRL, 0); + } +- +- ++ if (has_msr_virt_ssbd) { ++ kvm_msr_entry_add(cpu, MSR_VIRT_SSBD, 0); ++ } + if (!env->tsc_valid) { + kvm_msr_entry_add(cpu, MSR_IA32_TSC, 0); + env->tsc_valid = !runstate_is_running(); +@@ -2444,6 +2453,9 @@ static int kvm_get_msrs(X86CPU *cpu) + case MSR_IA32_SPEC_CTRL: + env->spec_ctrl = msrs[i].data; + break; ++ case MSR_VIRT_SSBD: ++ env->virt_ssbd = msrs[i].data; ++ break; + case MSR_IA32_RTIT_CTL: + env->msr_rtit_ctrl = msrs[i].data; + break; +diff --git a/target/i386/machine.c b/target/i386/machine.c +index f86abe7..9e7256a 100644 +--- a/target/i386/machine.c ++++ b/target/i386/machine.c +@@ -916,6 +916,25 @@ static const VMStateDescription vmstate_xsave ={ + } + }; + ++static bool virt_ssbd_needed(void *opaque) ++{ ++ X86CPU *cpu = opaque; ++ CPUX86State *env = &cpu->env; ++ ++ return env->virt_ssbd != 0; ++} ++ ++static const VMStateDescription vmstate_msr_virt_ssbd = { ++ .name = "cpu/virt_ssbd", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .needed = virt_ssbd_needed, ++ .fields = (VMStateField[]){ ++ VMSTATE_UINT64(env.virt_ssbd, X86CPU), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ + VMStateDescription vmstate_x86_cpu = { + .name = "cpu", + .version_id = 12, +@@ -1039,6 +1058,7 @@ VMStateDescription vmstate_x86_cpu = { + &vmstate_mcg_ext_ctl, + &vmstate_msr_intel_pt, + &vmstate_xsave, ++ &vmstate_msr_virt_ssbd, + NULL + } + }; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-i386-Disable-TOPOEXT-by-default-on-cpu-host.patch b/SOURCES/kvm-i386-Disable-TOPOEXT-by-default-on-cpu-host.patch new file mode 100644 index 0000000..3352318 --- /dev/null +++ b/SOURCES/kvm-i386-Disable-TOPOEXT-by-default-on-cpu-host.patch @@ -0,0 +1,57 @@ +From ed04f30927017781f0aa6aa5f9bd734320f4a330 Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Tue, 21 Aug 2018 18:53:11 +0200 +Subject: [PATCH 4/5] i386: Disable TOPOEXT by default on "-cpu host" + +RH-Author: Eduardo Habkost +Message-id: <20180821185311.27865-1-ehabkost@redhat.com> +Patchwork-id: 81903 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH] i386: Disable TOPOEXT by default on "-cpu host" +Bugzilla: 1613277 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Igor Mammedov +RH-Acked-by: Miroslav Rezanina + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1613277 +Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=17980585 + +Enabling TOPOEXT is always allowed, but it can't be enabled +blindly by "-cpu host" because it may make guests crash if the +rest of the cache topology information isn't provided or isn't +consistent. + +This addresses the bug reported at: +https://bugzilla.redhat.com/show_bug.cgi?id=1613277 + +Signed-off-by: Eduardo Habkost +Message-Id: <20180809221852.15285-1-ehabkost@redhat.com> +Tested-by: Richard W.M. Jones +Reviewed-by: Babu Moger +Signed-off-by: Eduardo Habkost +(cherry picked from commit 7210a02c58572b2686a3a8d610c6628f87864aed) +Signed-off-by: Eduardo Habkost +Signed-off-by: Miroslav Rezanina +--- + target/i386/cpu.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index eabe4ea..e6ad66c 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -852,6 +852,12 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + }, + .cpuid_eax = 0x80000001, .cpuid_reg = R_ECX, + .tcg_features = TCG_EXT3_FEATURES, ++ /* ++ * TOPOEXT is always allowed but can't be enabled blindly by ++ * "-cpu host", as it requires consistent cache topology info ++ * to be provided so it doesn't confuse guests. ++ */ ++ .no_autoenable_flags = CPUID_EXT3_TOPOEXT, + }, + [FEAT_C000_0001_EDX] = { + .feat_names = { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-i386-Enable-TOPOEXT-feature-on-AMD-EPYC-CPU.patch b/SOURCES/kvm-i386-Enable-TOPOEXT-feature-on-AMD-EPYC-CPU.patch new file mode 100644 index 0000000..ef70673 --- /dev/null +++ b/SOURCES/kvm-i386-Enable-TOPOEXT-feature-on-AMD-EPYC-CPU.patch @@ -0,0 +1,111 @@ +From 2f039646554d29873f39b867cfe80d044f2c56b4 Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Tue, 3 Jul 2018 17:23:55 +0200 +Subject: [PATCH 10/89] i386: Enable TOPOEXT feature on AMD EPYC CPU + +RH-Author: Eduardo Habkost +Message-id: <20180703172356.21038-10-ehabkost@redhat.com> +Patchwork-id: 81219 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v3 09/10] i386: Enable TOPOEXT feature on AMD EPYC CPU +Bugzilla: 1481253 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Igor Mammedov +RH-Acked-by: Miroslav Rezanina + +From: Babu Moger + +Enable TOPOEXT feature on EPYC CPU. This is required to support +hyperthreading on VM guests. Also extend xlevel to 0x8000001E. + +Disable topoext on PC_COMPAT_2_12 and keep xlevel 0x8000000a. + +Signed-off-by: Babu Moger +Message-Id: <1529443919-67509-3-git-send-email-babu.moger@amd.com> +[ehabkost: Added EPYC-IBPB.xlevel to PC_COMPAT_2_12] +Signed-off-by: Eduardo Habkost +(cherry picked from commit e00516475c270dcb6705753da96063f95699abf2) +[ehabkost: moved compat code to PC_RHEL75_COMPAT] +[ehabkost: fixed typo on EPYC-IBPB compat entry] +Signed-off-by: Eduardo Habkost +--- +Changes v2 -> v3: +* Removed duplicate TYPE_X86_CPU.legacy-cache=on entry from + PC_RHEL7_5_COMPAT (caught by Laurent Vivier) + +Changes v1 -> v2: +* Fixed typo on EPYC-IBPB compat entry + +Signed-off-by: Miroslav Rezanina +--- + include/hw/i386/pc.h | 12 ++++++++++++ + target/i386/cpu.c | 10 ++++++---- + 2 files changed, 18 insertions(+), 4 deletions(-) + +diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h +index 3ff55c6..88e5a92 100644 +--- a/include/hw/i386/pc.h ++++ b/include/hw/i386/pc.h +@@ -983,6 +983,18 @@ extern void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id); + .driver = TYPE_X86_CPU,\ + .property = "legacy-cache",\ + .value = "on",\ ++ },{ /* PC_RHEL7_5_COMPAT from PC_COMPAT_2_12 */ \ ++ .driver = TYPE_X86_CPU,\ ++ .property = "topoext",\ ++ .value = "off",\ ++ },{ /* PC_RHEL7_5_COMPAT from PC_COMPAT_2_12 */ \ ++ .driver = "EPYC-" TYPE_X86_CPU,\ ++ .property = "xlevel",\ ++ .value = stringify(0x8000000a),\ ++ },{ /* PC_RHEL7_5_COMPAT from PC_COMPAT_2_12 */ \ ++ .driver = "EPYC-IBPB-" TYPE_X86_CPU,\ ++ .property = "xlevel",\ ++ .value = stringify(0x8000000a),\ + }, + + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index ef43ea0..5d5d7e6 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -2562,7 +2562,8 @@ static X86CPUDefinition builtin_x86_defs[] = { + .features[FEAT_8000_0001_ECX] = + CPUID_EXT3_OSVW | CPUID_EXT3_3DNOWPREFETCH | + CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | +- CPUID_EXT3_CR8LEG | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM, ++ CPUID_EXT3_CR8LEG | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM | ++ CPUID_EXT3_TOPOEXT, + .features[FEAT_7_0_EBX] = + CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_AVX2 | + CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_RDSEED | +@@ -2577,7 +2578,7 @@ static X86CPUDefinition builtin_x86_defs[] = { + CPUID_XSAVE_XGETBV1, + .features[FEAT_6_EAX] = + CPUID_6_EAX_ARAT, +- .xlevel = 0x8000000A, ++ .xlevel = 0x8000001E, + .model_id = "AMD EPYC Processor", + .cache_info = &epyc_cache_info, + }, +@@ -2607,7 +2608,8 @@ static X86CPUDefinition builtin_x86_defs[] = { + .features[FEAT_8000_0001_ECX] = + CPUID_EXT3_OSVW | CPUID_EXT3_3DNOWPREFETCH | + CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | +- CPUID_EXT3_CR8LEG | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM, ++ CPUID_EXT3_CR8LEG | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM | ++ CPUID_EXT3_TOPOEXT, + .features[FEAT_8000_0008_EBX] = + CPUID_8000_0008_EBX_IBPB, + .features[FEAT_7_0_EBX] = +@@ -2624,7 +2626,7 @@ static X86CPUDefinition builtin_x86_defs[] = { + CPUID_XSAVE_XGETBV1, + .features[FEAT_6_EAX] = + CPUID_6_EAX_ARAT, +- .xlevel = 0x8000000A, ++ .xlevel = 0x8000001E, + .model_id = "AMD EPYC Processor (with IBPB)", + .cache_info = &epyc_cache_info, + }, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-i386-Fix-arch_query_cpu_model_expansion-leak.patch b/SOURCES/kvm-i386-Fix-arch_query_cpu_model_expansion-leak.patch new file mode 100644 index 0000000..238f27e --- /dev/null +++ b/SOURCES/kvm-i386-Fix-arch_query_cpu_model_expansion-leak.patch @@ -0,0 +1,87 @@ +From c8edc3f99b203feb6795d2d727c9b46058bcf3bd Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 31 Aug 2018 14:24:59 +0200 +Subject: [PATCH 08/29] i386: Fix arch_query_cpu_model_expansion() leak + +RH-Author: Markus Armbruster +Message-id: <20180831142459.18567-3-armbru@redhat.com> +Patchwork-id: 81985 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 2/2] i386: Fix arch_query_cpu_model_expansion() leak +Bugzilla: 1624390 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: Auger Eric + +From: Eduardo Habkost + +Reported by Coverity: + +Error: RESOURCE_LEAK (CWE-772): [#def439] +qemu-2.12.0/target/i386/cpu.c:3179: alloc_fn: Storage is returned from allocation function "qdict_new". +qemu-2.12.0/qobject/qdict.c:34:5: alloc_fn: Storage is returned from allocation function "g_malloc0". +qemu-2.12.0/qobject/qdict.c:34:5: var_assign: Assigning: "qdict" = "g_malloc0(4120UL)". +qemu-2.12.0/qobject/qdict.c:37:5: return_alloc: Returning allocated memory "qdict". +qemu-2.12.0/target/i386/cpu.c:3179: var_assign: Assigning: "props" = storage returned from "qdict_new()". +qemu-2.12.0/target/i386/cpu.c:3217: leaked_storage: Variable "props" going out of scope leaks the storage it points to. + +This was introduced by commit b8097deb359b ("i386: Improve +query-cpu-model-expansion full mode"). + +The leak is only theoretical: if ret->model->props is set to +props, the qapi_free_CpuModelExpansionInfo() call will free props +too in case of errors. The only way for this to not happen is if +we enter the default branch of the switch statement, which would +never happen because all CpuModelExpansionType values are being +handled. + +It's still worth to change this to make the allocation logic +easier to follow and make the Coverity error go away. To make +everything simpler, initialize ret->model and ret->model->props +earlier in the function. + +While at it, remove redundant check for !prop because prop is +always initialized at the beginning of the function. + +Fixes: b8097deb359bbbd92592b9670adfe9e245b2d0bd +Signed-off-by: Eduardo Habkost +Message-Id: <20180816183509.8231-1-ehabkost@redhat.com> +Signed-off-by: Paolo Bonzini +(cherry picked from commit e38bf612477fca62b205ebd909b1372a7e45a8c0) +Signed-off-by: Miroslav Rezanina +--- + target/i386/cpu.c | 9 +++------ + 1 file changed, 3 insertions(+), 6 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index e317aaf..6b5acdf 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -3733,6 +3733,9 @@ arch_query_cpu_model_expansion(CpuModelExpansionType type, + } + + props = qdict_new(); ++ ret->model = g_new0(CpuModelInfo, 1); ++ ret->model->props = QOBJECT(props); ++ ret->model->has_props = true; + + switch (type) { + case CPU_MODEL_EXPANSION_TYPE_STATIC: +@@ -3753,15 +3756,9 @@ arch_query_cpu_model_expansion(CpuModelExpansionType type, + goto out; + } + +- if (!props) { +- props = qdict_new(); +- } + x86_cpu_to_dict(xc, props); + +- ret->model = g_new0(CpuModelInfo, 1); + ret->model->name = g_strdup(base_name); +- ret->model->props = QOBJECT(props); +- ret->model->has_props = true; + + out: + object_unref(OBJECT(xc)); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-i386-Fix-up-the-Node-id-for-CPUID_8000_001E.patch b/SOURCES/kvm-i386-Fix-up-the-Node-id-for-CPUID_8000_001E.patch new file mode 100644 index 0000000..03c2003 --- /dev/null +++ b/SOURCES/kvm-i386-Fix-up-the-Node-id-for-CPUID_8000_001E.patch @@ -0,0 +1,88 @@ +From 7d5a7d6926805c069903bef845d43912cf718410 Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Tue, 3 Jul 2018 17:23:54 +0200 +Subject: [PATCH 09/89] i386: Fix up the Node id for CPUID_8000_001E + +RH-Author: Eduardo Habkost +Message-id: <20180703172356.21038-9-ehabkost@redhat.com> +Patchwork-id: 81218 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v3 08/10] i386: Fix up the Node id for CPUID_8000_001E +Bugzilla: 1481253 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Igor Mammedov +RH-Acked-by: Miroslav Rezanina + +From: Babu Moger + +This is part of topoext support. To keep the compatibility, it is better +we support all the combination of nr_cores and nr_threads currently +supported. By allowing more nr_cores and nr_threads, we might end up with +more nodes than we can actually support with the real hardware. We need to +fix up the node id to make this work. We can achieve this by shifting the +socket_id bits left to address more nodes. + +Signed-off-by: Babu Moger +Message-Id: <1529443919-67509-2-git-send-email-babu.moger@amd.com> +Reviewed-by: Eduardo Habkost +Signed-off-by: Eduardo Habkost +(cherry picked from commit 631be32155dbafa1fe886f2488127956c9120ba6) +Signed-off-by: Eduardo Habkost +Signed-off-by: Miroslav Rezanina +--- + target/i386/cpu.c | 26 +++++++++++++++++++++++++- + 1 file changed, 25 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 643d3b1..ef43ea0 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -19,6 +19,7 @@ + + #include "qemu/osdep.h" + #include "qemu/cutils.h" ++#include "qemu/bitops.h" + + #include "cpu.h" + #include "exec/exec-all.h" +@@ -474,6 +475,8 @@ static void encode_topo_cpuid8000001e(CPUState *cs, X86CPU *cpu, + uint32_t *ecx, uint32_t *edx) + { + struct core_topology topo = {0}; ++ unsigned long nodes; ++ int shift; + + build_core_topology(cs->nr_cores, cpu->core_id, &topo); + *eax = cpu->apic_id; +@@ -506,7 +509,28 @@ static void encode_topo_cpuid8000001e(CPUState *cs, X86CPU *cpu, + * 2 Socket id + * 1:0 Node id + */ +- *ecx = ((topo.num_nodes - 1) << 8) | (cpu->socket_id << 2) | topo.node_id; ++ if (topo.num_nodes <= 4) { ++ *ecx = ((topo.num_nodes - 1) << 8) | (cpu->socket_id << 2) | ++ topo.node_id; ++ } else { ++ /* ++ * Node id fix up. Actual hardware supports up to 4 nodes. But with ++ * more than 32 cores, we may end up with more than 4 nodes. ++ * Node id is a combination of socket id and node id. Only requirement ++ * here is that this number should be unique accross the system. ++ * Shift the socket id to accommodate more nodes. We dont expect both ++ * socket id and node id to be big number at the same time. This is not ++ * an ideal config but we need to to support it. Max nodes we can have ++ * is 32 (255/8) with 8 cores per node and 255 max cores. We only need ++ * 5 bits for nodes. Find the left most set bit to represent the total ++ * number of nodes. find_last_bit returns last set bit(0 based). Left ++ * shift(+1) the socket id to represent all the nodes. ++ */ ++ nodes = topo.num_nodes - 1; ++ shift = find_last_bit(&nodes, 8); ++ *ecx = ((topo.num_nodes - 1) << 8) | (cpu->socket_id << (shift + 1)) | ++ topo.node_id; ++ } + *edx = 0; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-i386-Helpers-to-encode-cache-information-consistentl.patch b/SOURCES/kvm-i386-Helpers-to-encode-cache-information-consistentl.patch new file mode 100644 index 0000000..0a369cf --- /dev/null +++ b/SOURCES/kvm-i386-Helpers-to-encode-cache-information-consistentl.patch @@ -0,0 +1,687 @@ +From 4e90b977aecdc26df8cda57ee38e2a8159685b1f Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Tue, 3 Jul 2018 17:23:47 +0200 +Subject: [PATCH 02/89] i386: Helpers to encode cache information consistently + +RH-Author: Eduardo Habkost +Message-id: <20180703172356.21038-2-ehabkost@redhat.com> +Patchwork-id: 81210 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v3 01/10] i386: Helpers to encode cache information consistently +Bugzilla: 1481253 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Igor Mammedov +RH-Acked-by: Miroslav Rezanina + +Instead of having a collection of macros that need to be used in +complex expressions to build CPUID data, define a CPUCacheInfo +struct that can hold information about a given cache. Helper +functions will take a CPUCacheInfo struct as input to encode +CPUID leaves for a cache. + +This will help us ensure consistency between cache information +CPUID leaves, and make the existing inconsistencies in CPUID info +more visible. + +Signed-off-by: Eduardo Habkost +Signed-off-by: Babu Moger +Tested-by: Geoffrey McRae +Message-Id: <20180510204148.11687-2-babu.moger@amd.com> +Signed-off-by: Eduardo Habkost +(cherry picked from commit 7e3482f824809e1f6ffeb5bb8103ba27a7d1a52a) +Signed-off-by: Eduardo Habkost +Signed-off-by: Miroslav Rezanina +--- + target/i386/cpu.c | 495 ++++++++++++++++++++++++++++++++++++++++-------------- + target/i386/cpu.h | 53 ++++++ + 2 files changed, 424 insertions(+), 124 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 5d60d76..9a5a164 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -56,33 +56,240 @@ + + #include "disas/capstone.h" + ++/* Helpers for building CPUID[2] descriptors: */ ++ ++struct CPUID2CacheDescriptorInfo { ++ enum CacheType type; ++ int level; ++ int size; ++ int line_size; ++ int associativity; ++}; + +-/* Cache topology CPUID constants: */ ++#define KiB 1024 ++#define MiB (1024 * 1024) + +-/* CPUID Leaf 2 Descriptors */ ++/* ++ * Known CPUID 2 cache descriptors. ++ * From Intel SDM Volume 2A, CPUID instruction ++ */ ++struct CPUID2CacheDescriptorInfo cpuid2_cache_descriptors[] = { ++ [0x06] = { .level = 1, .type = ICACHE, .size = 8 * KiB, ++ .associativity = 4, .line_size = 32, }, ++ [0x08] = { .level = 1, .type = ICACHE, .size = 16 * KiB, ++ .associativity = 4, .line_size = 32, }, ++ [0x09] = { .level = 1, .type = ICACHE, .size = 32 * KiB, ++ .associativity = 4, .line_size = 64, }, ++ [0x0A] = { .level = 1, .type = DCACHE, .size = 8 * KiB, ++ .associativity = 2, .line_size = 32, }, ++ [0x0C] = { .level = 1, .type = DCACHE, .size = 16 * KiB, ++ .associativity = 4, .line_size = 32, }, ++ [0x0D] = { .level = 1, .type = DCACHE, .size = 16 * KiB, ++ .associativity = 4, .line_size = 64, }, ++ [0x0E] = { .level = 1, .type = DCACHE, .size = 24 * KiB, ++ .associativity = 6, .line_size = 64, }, ++ [0x1D] = { .level = 2, .type = UNIFIED_CACHE, .size = 128 * KiB, ++ .associativity = 2, .line_size = 64, }, ++ [0x21] = { .level = 2, .type = UNIFIED_CACHE, .size = 256 * KiB, ++ .associativity = 8, .line_size = 64, }, ++ /* lines per sector is not supported cpuid2_cache_descriptor(), ++ * so descriptors 0x22, 0x23 are not included ++ */ ++ [0x24] = { .level = 2, .type = UNIFIED_CACHE, .size = 1 * MiB, ++ .associativity = 16, .line_size = 64, }, ++ /* lines per sector is not supported cpuid2_cache_descriptor(), ++ * so descriptors 0x25, 0x20 are not included ++ */ ++ [0x2C] = { .level = 1, .type = DCACHE, .size = 32 * KiB, ++ .associativity = 8, .line_size = 64, }, ++ [0x30] = { .level = 1, .type = ICACHE, .size = 32 * KiB, ++ .associativity = 8, .line_size = 64, }, ++ [0x41] = { .level = 2, .type = UNIFIED_CACHE, .size = 128 * KiB, ++ .associativity = 4, .line_size = 32, }, ++ [0x42] = { .level = 2, .type = UNIFIED_CACHE, .size = 256 * KiB, ++ .associativity = 4, .line_size = 32, }, ++ [0x43] = { .level = 2, .type = UNIFIED_CACHE, .size = 512 * KiB, ++ .associativity = 4, .line_size = 32, }, ++ [0x44] = { .level = 2, .type = UNIFIED_CACHE, .size = 1 * MiB, ++ .associativity = 4, .line_size = 32, }, ++ [0x45] = { .level = 2, .type = UNIFIED_CACHE, .size = 2 * MiB, ++ .associativity = 4, .line_size = 32, }, ++ [0x46] = { .level = 3, .type = UNIFIED_CACHE, .size = 4 * MiB, ++ .associativity = 4, .line_size = 64, }, ++ [0x47] = { .level = 3, .type = UNIFIED_CACHE, .size = 8 * MiB, ++ .associativity = 8, .line_size = 64, }, ++ [0x48] = { .level = 2, .type = UNIFIED_CACHE, .size = 3 * MiB, ++ .associativity = 12, .line_size = 64, }, ++ /* Descriptor 0x49 depends on CPU family/model, so it is not included */ ++ [0x4A] = { .level = 3, .type = UNIFIED_CACHE, .size = 6 * MiB, ++ .associativity = 12, .line_size = 64, }, ++ [0x4B] = { .level = 3, .type = UNIFIED_CACHE, .size = 8 * MiB, ++ .associativity = 16, .line_size = 64, }, ++ [0x4C] = { .level = 3, .type = UNIFIED_CACHE, .size = 12 * MiB, ++ .associativity = 12, .line_size = 64, }, ++ [0x4D] = { .level = 3, .type = UNIFIED_CACHE, .size = 16 * MiB, ++ .associativity = 16, .line_size = 64, }, ++ [0x4E] = { .level = 2, .type = UNIFIED_CACHE, .size = 6 * MiB, ++ .associativity = 24, .line_size = 64, }, ++ [0x60] = { .level = 1, .type = DCACHE, .size = 16 * KiB, ++ .associativity = 8, .line_size = 64, }, ++ [0x66] = { .level = 1, .type = DCACHE, .size = 8 * KiB, ++ .associativity = 4, .line_size = 64, }, ++ [0x67] = { .level = 1, .type = DCACHE, .size = 16 * KiB, ++ .associativity = 4, .line_size = 64, }, ++ [0x68] = { .level = 1, .type = DCACHE, .size = 32 * KiB, ++ .associativity = 4, .line_size = 64, }, ++ [0x78] = { .level = 2, .type = UNIFIED_CACHE, .size = 1 * MiB, ++ .associativity = 4, .line_size = 64, }, ++ /* lines per sector is not supported cpuid2_cache_descriptor(), ++ * so descriptors 0x79, 0x7A, 0x7B, 0x7C are not included. ++ */ ++ [0x7D] = { .level = 2, .type = UNIFIED_CACHE, .size = 2 * MiB, ++ .associativity = 8, .line_size = 64, }, ++ [0x7F] = { .level = 2, .type = UNIFIED_CACHE, .size = 512 * KiB, ++ .associativity = 2, .line_size = 64, }, ++ [0x80] = { .level = 2, .type = UNIFIED_CACHE, .size = 512 * KiB, ++ .associativity = 8, .line_size = 64, }, ++ [0x82] = { .level = 2, .type = UNIFIED_CACHE, .size = 256 * KiB, ++ .associativity = 8, .line_size = 32, }, ++ [0x83] = { .level = 2, .type = UNIFIED_CACHE, .size = 512 * KiB, ++ .associativity = 8, .line_size = 32, }, ++ [0x84] = { .level = 2, .type = UNIFIED_CACHE, .size = 1 * MiB, ++ .associativity = 8, .line_size = 32, }, ++ [0x85] = { .level = 2, .type = UNIFIED_CACHE, .size = 2 * MiB, ++ .associativity = 8, .line_size = 32, }, ++ [0x86] = { .level = 2, .type = UNIFIED_CACHE, .size = 512 * KiB, ++ .associativity = 4, .line_size = 64, }, ++ [0x87] = { .level = 2, .type = UNIFIED_CACHE, .size = 1 * MiB, ++ .associativity = 8, .line_size = 64, }, ++ [0xD0] = { .level = 3, .type = UNIFIED_CACHE, .size = 512 * KiB, ++ .associativity = 4, .line_size = 64, }, ++ [0xD1] = { .level = 3, .type = UNIFIED_CACHE, .size = 1 * MiB, ++ .associativity = 4, .line_size = 64, }, ++ [0xD2] = { .level = 3, .type = UNIFIED_CACHE, .size = 2 * MiB, ++ .associativity = 4, .line_size = 64, }, ++ [0xD6] = { .level = 3, .type = UNIFIED_CACHE, .size = 1 * MiB, ++ .associativity = 8, .line_size = 64, }, ++ [0xD7] = { .level = 3, .type = UNIFIED_CACHE, .size = 2 * MiB, ++ .associativity = 8, .line_size = 64, }, ++ [0xD8] = { .level = 3, .type = UNIFIED_CACHE, .size = 4 * MiB, ++ .associativity = 8, .line_size = 64, }, ++ [0xDC] = { .level = 3, .type = UNIFIED_CACHE, .size = 1.5 * MiB, ++ .associativity = 12, .line_size = 64, }, ++ [0xDD] = { .level = 3, .type = UNIFIED_CACHE, .size = 3 * MiB, ++ .associativity = 12, .line_size = 64, }, ++ [0xDE] = { .level = 3, .type = UNIFIED_CACHE, .size = 6 * MiB, ++ .associativity = 12, .line_size = 64, }, ++ [0xE2] = { .level = 3, .type = UNIFIED_CACHE, .size = 2 * MiB, ++ .associativity = 16, .line_size = 64, }, ++ [0xE3] = { .level = 3, .type = UNIFIED_CACHE, .size = 4 * MiB, ++ .associativity = 16, .line_size = 64, }, ++ [0xE4] = { .level = 3, .type = UNIFIED_CACHE, .size = 8 * MiB, ++ .associativity = 16, .line_size = 64, }, ++ [0xEA] = { .level = 3, .type = UNIFIED_CACHE, .size = 12 * MiB, ++ .associativity = 24, .line_size = 64, }, ++ [0xEB] = { .level = 3, .type = UNIFIED_CACHE, .size = 18 * MiB, ++ .associativity = 24, .line_size = 64, }, ++ [0xEC] = { .level = 3, .type = UNIFIED_CACHE, .size = 24 * MiB, ++ .associativity = 24, .line_size = 64, }, ++}; ++ ++/* ++ * "CPUID leaf 2 does not report cache descriptor information, ++ * use CPUID leaf 4 to query cache parameters" ++ */ ++#define CACHE_DESCRIPTOR_UNAVAILABLE 0xFF + +-#define CPUID_2_L1D_32KB_8WAY_64B 0x2c +-#define CPUID_2_L1I_32KB_8WAY_64B 0x30 +-#define CPUID_2_L2_2MB_8WAY_64B 0x7d +-#define CPUID_2_L3_16MB_16WAY_64B 0x4d ++/* ++ * Return a CPUID 2 cache descriptor for a given cache. ++ * If no known descriptor is found, return CACHE_DESCRIPTOR_UNAVAILABLE ++ */ ++static uint8_t cpuid2_cache_descriptor(CPUCacheInfo *cache) ++{ ++ int i; ++ ++ assert(cache->size > 0); ++ assert(cache->level > 0); ++ assert(cache->line_size > 0); ++ assert(cache->associativity > 0); ++ for (i = 0; i < ARRAY_SIZE(cpuid2_cache_descriptors); i++) { ++ struct CPUID2CacheDescriptorInfo *d = &cpuid2_cache_descriptors[i]; ++ if (d->level == cache->level && d->type == cache->type && ++ d->size == cache->size && d->line_size == cache->line_size && ++ d->associativity == cache->associativity) { ++ return i; ++ } ++ } + ++ return CACHE_DESCRIPTOR_UNAVAILABLE; ++} + + /* CPUID Leaf 4 constants: */ + + /* EAX: */ +-#define CPUID_4_TYPE_DCACHE 1 +-#define CPUID_4_TYPE_ICACHE 2 +-#define CPUID_4_TYPE_UNIFIED 3 ++#define CACHE_TYPE_D 1 ++#define CACHE_TYPE_I 2 ++#define CACHE_TYPE_UNIFIED 3 + +-#define CPUID_4_LEVEL(l) ((l) << 5) ++#define CACHE_LEVEL(l) (l << 5) + +-#define CPUID_4_SELF_INIT_LEVEL (1 << 8) +-#define CPUID_4_FULLY_ASSOC (1 << 9) ++#define CACHE_SELF_INIT_LEVEL (1 << 8) + + /* EDX: */ +-#define CPUID_4_NO_INVD_SHARING (1 << 0) +-#define CPUID_4_INCLUSIVE (1 << 1) +-#define CPUID_4_COMPLEX_IDX (1 << 2) ++#define CACHE_NO_INVD_SHARING (1 << 0) ++#define CACHE_INCLUSIVE (1 << 1) ++#define CACHE_COMPLEX_IDX (1 << 2) ++ ++/* Encode CacheType for CPUID[4].EAX */ ++#define CACHE_TYPE(t) (((t) == DCACHE) ? CACHE_TYPE_D : \ ++ ((t) == ICACHE) ? CACHE_TYPE_I : \ ++ ((t) == UNIFIED_CACHE) ? CACHE_TYPE_UNIFIED : \ ++ 0 /* Invalid value */) ++ ++ ++/* Encode cache info for CPUID[4] */ ++static void encode_cache_cpuid4(CPUCacheInfo *cache, ++ int num_apic_ids, int num_cores, ++ uint32_t *eax, uint32_t *ebx, ++ uint32_t *ecx, uint32_t *edx) ++{ ++ assert(cache->size == cache->line_size * cache->associativity * ++ cache->partitions * cache->sets); ++ ++ assert(num_apic_ids > 0); ++ *eax = CACHE_TYPE(cache->type) | ++ CACHE_LEVEL(cache->level) | ++ (cache->self_init ? CACHE_SELF_INIT_LEVEL : 0) | ++ ((num_cores - 1) << 26) | ++ ((num_apic_ids - 1) << 14); ++ ++ assert(cache->line_size > 0); ++ assert(cache->partitions > 0); ++ assert(cache->associativity > 0); ++ /* We don't implement fully-associative caches */ ++ assert(cache->associativity < cache->sets); ++ *ebx = (cache->line_size - 1) | ++ ((cache->partitions - 1) << 12) | ++ ((cache->associativity - 1) << 22); ++ ++ assert(cache->sets > 0); ++ *ecx = cache->sets - 1; ++ ++ *edx = (cache->no_invd_sharing ? CACHE_NO_INVD_SHARING : 0) | ++ (cache->inclusive ? CACHE_INCLUSIVE : 0) | ++ (cache->complex_indexing ? CACHE_COMPLEX_IDX : 0); ++} ++ ++/* Encode cache info for CPUID[0x80000005].ECX or CPUID[0x80000005].EDX */ ++static uint32_t encode_cache_cpuid80000005(CPUCacheInfo *cache) ++{ ++ assert(cache->size % 1024 == 0); ++ assert(cache->lines_per_tag > 0); ++ assert(cache->associativity > 0); ++ assert(cache->line_size > 0); ++ return ((cache->size / 1024) << 24) | (cache->associativity << 16) | ++ (cache->lines_per_tag << 8) | (cache->line_size); ++} + + #define ASSOC_FULL 0xFF + +@@ -100,57 +307,140 @@ + a == ASSOC_FULL ? 0xF : \ + 0 /* invalid value */) + ++/* ++ * Encode cache info for CPUID[0x80000006].ECX and CPUID[0x80000006].EDX ++ * @l3 can be NULL. ++ */ ++static void encode_cache_cpuid80000006(CPUCacheInfo *l2, ++ CPUCacheInfo *l3, ++ uint32_t *ecx, uint32_t *edx) ++{ ++ assert(l2->size % 1024 == 0); ++ assert(l2->associativity > 0); ++ assert(l2->lines_per_tag > 0); ++ assert(l2->line_size > 0); ++ *ecx = ((l2->size / 1024) << 16) | ++ (AMD_ENC_ASSOC(l2->associativity) << 12) | ++ (l2->lines_per_tag << 8) | (l2->line_size); ++ ++ if (l3) { ++ assert(l3->size % (512 * 1024) == 0); ++ assert(l3->associativity > 0); ++ assert(l3->lines_per_tag > 0); ++ assert(l3->line_size > 0); ++ *edx = ((l3->size / (512 * 1024)) << 18) | ++ (AMD_ENC_ASSOC(l3->associativity) << 12) | ++ (l3->lines_per_tag << 8) | (l3->line_size); ++ } else { ++ *edx = 0; ++ } ++} + + /* Definitions of the hardcoded cache entries we expose: */ + + /* L1 data cache: */ +-#define L1D_LINE_SIZE 64 +-#define L1D_ASSOCIATIVITY 8 +-#define L1D_SETS 64 +-#define L1D_PARTITIONS 1 +-/* Size = LINE_SIZE*ASSOCIATIVITY*SETS*PARTITIONS = 32KiB */ +-#define L1D_DESCRIPTOR CPUID_2_L1D_32KB_8WAY_64B ++static CPUCacheInfo l1d_cache = { ++ .type = DCACHE, ++ .level = 1, ++ .size = 32 * KiB, ++ .self_init = 1, ++ .line_size = 64, ++ .associativity = 8, ++ .sets = 64, ++ .partitions = 1, ++ .no_invd_sharing = true, ++}; ++ + /*FIXME: CPUID leaf 0x80000005 is inconsistent with leaves 2 & 4 */ +-#define L1D_LINES_PER_TAG 1 +-#define L1D_SIZE_KB_AMD 64 +-#define L1D_ASSOCIATIVITY_AMD 2 ++static CPUCacheInfo l1d_cache_amd = { ++ .type = DCACHE, ++ .level = 1, ++ .size = 64 * KiB, ++ .self_init = 1, ++ .line_size = 64, ++ .associativity = 2, ++ .sets = 512, ++ .partitions = 1, ++ .lines_per_tag = 1, ++ .no_invd_sharing = true, ++}; + + /* L1 instruction cache: */ +-#define L1I_LINE_SIZE 64 +-#define L1I_ASSOCIATIVITY 8 +-#define L1I_SETS 64 +-#define L1I_PARTITIONS 1 +-/* Size = LINE_SIZE*ASSOCIATIVITY*SETS*PARTITIONS = 32KiB */ +-#define L1I_DESCRIPTOR CPUID_2_L1I_32KB_8WAY_64B ++static CPUCacheInfo l1i_cache = { ++ .type = ICACHE, ++ .level = 1, ++ .size = 32 * KiB, ++ .self_init = 1, ++ .line_size = 64, ++ .associativity = 8, ++ .sets = 64, ++ .partitions = 1, ++ .no_invd_sharing = true, ++}; ++ + /*FIXME: CPUID leaf 0x80000005 is inconsistent with leaves 2 & 4 */ +-#define L1I_LINES_PER_TAG 1 +-#define L1I_SIZE_KB_AMD 64 +-#define L1I_ASSOCIATIVITY_AMD 2 ++static CPUCacheInfo l1i_cache_amd = { ++ .type = ICACHE, ++ .level = 1, ++ .size = 64 * KiB, ++ .self_init = 1, ++ .line_size = 64, ++ .associativity = 2, ++ .sets = 512, ++ .partitions = 1, ++ .lines_per_tag = 1, ++ .no_invd_sharing = true, ++}; + + /* Level 2 unified cache: */ +-#define L2_LINE_SIZE 64 +-#define L2_ASSOCIATIVITY 16 +-#define L2_SETS 4096 +-#define L2_PARTITIONS 1 +-/* Size = LINE_SIZE*ASSOCIATIVITY*SETS*PARTITIONS = 4MiB */ ++static CPUCacheInfo l2_cache = { ++ .type = UNIFIED_CACHE, ++ .level = 2, ++ .size = 4 * MiB, ++ .self_init = 1, ++ .line_size = 64, ++ .associativity = 16, ++ .sets = 4096, ++ .partitions = 1, ++ .no_invd_sharing = true, ++}; ++ + /*FIXME: CPUID leaf 2 descriptor is inconsistent with CPUID leaf 4 */ +-#define L2_DESCRIPTOR CPUID_2_L2_2MB_8WAY_64B ++static CPUCacheInfo l2_cache_cpuid2 = { ++ .type = UNIFIED_CACHE, ++ .level = 2, ++ .size = 2 * MiB, ++ .line_size = 64, ++ .associativity = 8, ++}; ++ ++ + /*FIXME: CPUID leaf 0x80000006 is inconsistent with leaves 2 & 4 */ +-#define L2_LINES_PER_TAG 1 +-#define L2_SIZE_KB_AMD 512 ++static CPUCacheInfo l2_cache_amd = { ++ .type = UNIFIED_CACHE, ++ .level = 2, ++ .size = 512 * KiB, ++ .line_size = 64, ++ .lines_per_tag = 1, ++ .associativity = 16, ++ .sets = 512, ++ .partitions = 1, ++}; + + /* Level 3 unified cache: */ +-#define L3_SIZE_KB 0 /* disabled */ +-#define L3_ASSOCIATIVITY 0 /* disabled */ +-#define L3_LINES_PER_TAG 0 /* disabled */ +-#define L3_LINE_SIZE 0 /* disabled */ +-#define L3_N_LINE_SIZE 64 +-#define L3_N_ASSOCIATIVITY 16 +-#define L3_N_SETS 16384 +-#define L3_N_PARTITIONS 1 +-#define L3_N_DESCRIPTOR CPUID_2_L3_16MB_16WAY_64B +-#define L3_N_LINES_PER_TAG 1 +-#define L3_N_SIZE_KB_AMD 16384 ++static CPUCacheInfo l3_cache = { ++ .type = UNIFIED_CACHE, ++ .level = 3, ++ .size = 16 * MiB, ++ .line_size = 64, ++ .associativity = 16, ++ .sets = 16384, ++ .partitions = 1, ++ .lines_per_tag = 1, ++ .self_init = true, ++ .inclusive = true, ++ .complex_indexing = true, ++}; + + /* TLB definitions: */ + +@@ -3327,85 +3617,53 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + if (!cpu->enable_l3_cache) { + *ecx = 0; + } else { +- *ecx = L3_N_DESCRIPTOR; ++ *ecx = cpuid2_cache_descriptor(&l3_cache); + } +- *edx = (L1D_DESCRIPTOR << 16) | \ +- (L1I_DESCRIPTOR << 8) | \ +- (L2_DESCRIPTOR); ++ *edx = (cpuid2_cache_descriptor(&l1d_cache) << 16) | ++ (cpuid2_cache_descriptor(&l1i_cache) << 8) | ++ (cpuid2_cache_descriptor(&l2_cache_cpuid2)); + break; + case 4: + /* cache info: needed for Core compatibility */ + if (cpu->cache_info_passthrough) { + host_cpuid(index, count, eax, ebx, ecx, edx); ++ /* QEMU gives out its own APIC IDs, never pass down bits 31..26. */ + *eax &= ~0xFC000000; ++ if ((*eax & 31) && cs->nr_cores > 1) { ++ *eax |= (cs->nr_cores - 1) << 26; ++ } + } else { + *eax = 0; + switch (count) { + case 0: /* L1 dcache info */ +- *eax |= CPUID_4_TYPE_DCACHE | \ +- CPUID_4_LEVEL(1) | \ +- CPUID_4_SELF_INIT_LEVEL; +- *ebx = (L1D_LINE_SIZE - 1) | \ +- ((L1D_PARTITIONS - 1) << 12) | \ +- ((L1D_ASSOCIATIVITY - 1) << 22); +- *ecx = L1D_SETS - 1; +- *edx = CPUID_4_NO_INVD_SHARING; ++ encode_cache_cpuid4(&l1d_cache, ++ 1, cs->nr_cores, ++ eax, ebx, ecx, edx); + break; + case 1: /* L1 icache info */ +- *eax |= CPUID_4_TYPE_ICACHE | \ +- CPUID_4_LEVEL(1) | \ +- CPUID_4_SELF_INIT_LEVEL; +- *ebx = (L1I_LINE_SIZE - 1) | \ +- ((L1I_PARTITIONS - 1) << 12) | \ +- ((L1I_ASSOCIATIVITY - 1) << 22); +- *ecx = L1I_SETS - 1; +- *edx = CPUID_4_NO_INVD_SHARING; ++ encode_cache_cpuid4(&l1i_cache, ++ 1, cs->nr_cores, ++ eax, ebx, ecx, edx); + break; + case 2: /* L2 cache info */ +- *eax |= CPUID_4_TYPE_UNIFIED | \ +- CPUID_4_LEVEL(2) | \ +- CPUID_4_SELF_INIT_LEVEL; +- if (cs->nr_threads > 1) { +- *eax |= (cs->nr_threads - 1) << 14; +- } +- *ebx = (L2_LINE_SIZE - 1) | \ +- ((L2_PARTITIONS - 1) << 12) | \ +- ((L2_ASSOCIATIVITY - 1) << 22); +- *ecx = L2_SETS - 1; +- *edx = CPUID_4_NO_INVD_SHARING; ++ encode_cache_cpuid4(&l2_cache, ++ cs->nr_threads, cs->nr_cores, ++ eax, ebx, ecx, edx); + break; + case 3: /* L3 cache info */ +- if (!cpu->enable_l3_cache) { +- *eax = 0; +- *ebx = 0; +- *ecx = 0; +- *edx = 0; ++ pkg_offset = apicid_pkg_offset(cs->nr_cores, cs->nr_threads); ++ if (cpu->enable_l3_cache) { ++ encode_cache_cpuid4(&l3_cache, ++ (1 << pkg_offset), cs->nr_cores, ++ eax, ebx, ecx, edx); + break; + } +- *eax |= CPUID_4_TYPE_UNIFIED | \ +- CPUID_4_LEVEL(3) | \ +- CPUID_4_SELF_INIT_LEVEL; +- pkg_offset = apicid_pkg_offset(cs->nr_cores, cs->nr_threads); +- *eax |= ((1 << pkg_offset) - 1) << 14; +- *ebx = (L3_N_LINE_SIZE - 1) | \ +- ((L3_N_PARTITIONS - 1) << 12) | \ +- ((L3_N_ASSOCIATIVITY - 1) << 22); +- *ecx = L3_N_SETS - 1; +- *edx = CPUID_4_INCLUSIVE | CPUID_4_COMPLEX_IDX; +- break; ++ /* fall through */ + default: /* end of info */ +- *eax = 0; +- *ebx = 0; +- *ecx = 0; +- *edx = 0; ++ *eax = *ebx = *ecx = *edx = 0; + break; + } + } +- +- /* QEMU gives out its own APIC IDs, never pass down bits 31..26. */ +- if ((*eax & 31) && cs->nr_cores > 1) { +- *eax |= (cs->nr_cores - 1) << 26; +- } + break; + case 5: + /* mwait info: needed for Core compatibility */ +@@ -3609,10 +3867,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + (L1_ITLB_2M_ASSOC << 8) | (L1_ITLB_2M_ENTRIES); + *ebx = (L1_DTLB_4K_ASSOC << 24) | (L1_DTLB_4K_ENTRIES << 16) | \ + (L1_ITLB_4K_ASSOC << 8) | (L1_ITLB_4K_ENTRIES); +- *ecx = (L1D_SIZE_KB_AMD << 24) | (L1D_ASSOCIATIVITY_AMD << 16) | \ +- (L1D_LINES_PER_TAG << 8) | (L1D_LINE_SIZE); +- *edx = (L1I_SIZE_KB_AMD << 24) | (L1I_ASSOCIATIVITY_AMD << 16) | \ +- (L1I_LINES_PER_TAG << 8) | (L1I_LINE_SIZE); ++ *ecx = encode_cache_cpuid80000005(&l1d_cache_amd); ++ *edx = encode_cache_cpuid80000005(&l1i_cache_amd); + break; + case 0x80000006: + /* cache info (L2 cache) */ +@@ -3628,18 +3884,9 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + (L2_DTLB_4K_ENTRIES << 16) | \ + (AMD_ENC_ASSOC(L2_ITLB_4K_ASSOC) << 12) | \ + (L2_ITLB_4K_ENTRIES); +- *ecx = (L2_SIZE_KB_AMD << 16) | \ +- (AMD_ENC_ASSOC(L2_ASSOCIATIVITY) << 12) | \ +- (L2_LINES_PER_TAG << 8) | (L2_LINE_SIZE); +- if (!cpu->enable_l3_cache) { +- *edx = ((L3_SIZE_KB / 512) << 18) | \ +- (AMD_ENC_ASSOC(L3_ASSOCIATIVITY) << 12) | \ +- (L3_LINES_PER_TAG << 8) | (L3_LINE_SIZE); +- } else { +- *edx = ((L3_N_SIZE_KB_AMD / 512) << 18) | \ +- (AMD_ENC_ASSOC(L3_N_ASSOCIATIVITY) << 12) | \ +- (L3_N_LINES_PER_TAG << 8) | (L3_N_LINE_SIZE); +- } ++ encode_cache_cpuid80000006(&l2_cache_amd, ++ cpu->enable_l3_cache ? &l3_cache : NULL, ++ ecx, edx); + break; + case 0x80000007: + *eax = 0; +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 9aebe64..a0e4eeb 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -1046,6 +1046,59 @@ typedef enum TPRAccess { + TPR_ACCESS_WRITE, + } TPRAccess; + ++/* Cache information data structures: */ ++ ++enum CacheType { ++ DCACHE, ++ ICACHE, ++ UNIFIED_CACHE ++}; ++ ++typedef struct CPUCacheInfo { ++ enum CacheType type; ++ uint8_t level; ++ /* Size in bytes */ ++ uint32_t size; ++ /* Line size, in bytes */ ++ uint16_t line_size; ++ /* ++ * Associativity. ++ * Note: representation of fully-associative caches is not implemented ++ */ ++ uint8_t associativity; ++ /* Physical line partitions. CPUID[0x8000001D].EBX, CPUID[4].EBX */ ++ uint8_t partitions; ++ /* Number of sets. CPUID[0x8000001D].ECX, CPUID[4].ECX */ ++ uint32_t sets; ++ /* ++ * Lines per tag. ++ * AMD-specific: CPUID[0x80000005], CPUID[0x80000006]. ++ * (Is this synonym to @partitions?) ++ */ ++ uint8_t lines_per_tag; ++ ++ /* Self-initializing cache */ ++ bool self_init; ++ /* ++ * WBINVD/INVD is not guaranteed to act upon lower level caches of ++ * non-originating threads sharing this cache. ++ * CPUID[4].EDX[bit 0], CPUID[0x8000001D].EDX[bit 0] ++ */ ++ bool no_invd_sharing; ++ /* ++ * Cache is inclusive of lower cache levels. ++ * CPUID[4].EDX[bit 1], CPUID[0x8000001D].EDX[bit 1]. ++ */ ++ bool inclusive; ++ /* ++ * A complex function is used to index the cache, potentially using all ++ * address bits. CPUID[4].EDX[bit 2]. ++ */ ++ bool complex_indexing; ++} CPUCacheInfo; ++ ++ ++ + typedef struct CPUX86State { + /* standard registers */ + target_ulong regs[CPU_NB_REGS]; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-i386-Initialize-cache-information-for-EPYC-family-pr.patch b/SOURCES/kvm-i386-Initialize-cache-information-for-EPYC-family-pr.patch new file mode 100644 index 0000000..0bbbe0b --- /dev/null +++ b/SOURCES/kvm-i386-Initialize-cache-information-for-EPYC-family-pr.patch @@ -0,0 +1,110 @@ +From 28b619943c16c8015899b0808d844fbcea586487 Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Tue, 3 Jul 2018 17:23:49 +0200 +Subject: [PATCH 04/89] i386: Initialize cache information for EPYC family + processors + +RH-Author: Eduardo Habkost +Message-id: <20180703172356.21038-4-ehabkost@redhat.com> +Patchwork-id: 81214 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v3 03/10] i386: Initialize cache information for EPYC family processors +Bugzilla: 1481253 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Igor Mammedov +RH-Acked-by: Miroslav Rezanina + +From: Babu Moger + +Initialize pre-determined cache information for EPYC processors. + +Signed-off-by: Babu Moger +Tested-by: Geoffrey McRae +Message-Id: <20180510204148.11687-5-babu.moger@amd.com> +Signed-off-by: Eduardo Habkost +(cherry picked from commit fe52acd2a054b97765963a42037f2f886545e30c) +Signed-off-by: Eduardo Habkost +Signed-off-by: Miroslav Rezanina +--- + target/i386/cpu.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 52 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 7e81e08..23eb47d 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -1108,6 +1108,56 @@ struct X86CPUDefinition { + CPUCaches *cache_info; + }; + ++static CPUCaches epyc_cache_info = { ++ .l1d_cache = { ++ .type = DCACHE, ++ .level = 1, ++ .size = 32 * KiB, ++ .line_size = 64, ++ .associativity = 8, ++ .partitions = 1, ++ .sets = 64, ++ .lines_per_tag = 1, ++ .self_init = 1, ++ .no_invd_sharing = true, ++ }, ++ .l1i_cache = { ++ .type = ICACHE, ++ .level = 1, ++ .size = 64 * KiB, ++ .line_size = 64, ++ .associativity = 4, ++ .partitions = 1, ++ .sets = 256, ++ .lines_per_tag = 1, ++ .self_init = 1, ++ .no_invd_sharing = true, ++ }, ++ .l2_cache = { ++ .type = UNIFIED_CACHE, ++ .level = 2, ++ .size = 512 * KiB, ++ .line_size = 64, ++ .associativity = 8, ++ .partitions = 1, ++ .sets = 1024, ++ .lines_per_tag = 1, ++ }, ++ .l3_cache = { ++ .type = UNIFIED_CACHE, ++ .level = 3, ++ .size = 8 * MiB, ++ .line_size = 64, ++ .associativity = 16, ++ .partitions = 1, ++ .sets = 8192, ++ .lines_per_tag = 1, ++ .self_init = true, ++ .inclusive = true, ++ .complex_indexing = true, ++ }, ++}; ++ + static X86CPUDefinition builtin_x86_defs[] = { + { + /* qemu64 is the default CPU model for all *-rhel7.* machine-types. +@@ -2327,6 +2377,7 @@ static X86CPUDefinition builtin_x86_defs[] = { + CPUID_6_EAX_ARAT, + .xlevel = 0x8000000A, + .model_id = "AMD EPYC Processor", ++ .cache_info = &epyc_cache_info, + }, + { + .name = "EPYC-IBPB", +@@ -2373,6 +2424,7 @@ static X86CPUDefinition builtin_x86_defs[] = { + CPUID_6_EAX_ARAT, + .xlevel = 0x8000000A, + .model_id = "AMD EPYC Processor (with IBPB)", ++ .cache_info = &epyc_cache_info, + }, + }; + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-i386-Populate-AMD-Processor-Cache-Information-for-cp.patch b/SOURCES/kvm-i386-Populate-AMD-Processor-Cache-Information-for-cp.patch new file mode 100644 index 0000000..0c3e3fb --- /dev/null +++ b/SOURCES/kvm-i386-Populate-AMD-Processor-Cache-Information-for-cp.patch @@ -0,0 +1,212 @@ +From a24dd4151d27389947c011293d6775327268b1c2 Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Tue, 3 Jul 2018 17:23:52 +0200 +Subject: [PATCH 07/89] i386: Populate AMD Processor Cache Information for + cpuid 0x8000001D + +RH-Author: Eduardo Habkost +Message-id: <20180703172356.21038-7-ehabkost@redhat.com> +Patchwork-id: 81216 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v3 06/10] i386: Populate AMD Processor Cache Information for cpuid 0x8000001D +Bugzilla: 1481253 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Igor Mammedov +RH-Acked-by: Miroslav Rezanina + +From: Babu Moger + +Add information for cpuid 0x8000001D leaf. Populate cache topology information +for different cache types (Data Cache, Instruction Cache, L2 and L3) supported +by 0x8000001D leaf. Please refer to the Processor Programming Reference (PPR) +for AMD Family 17h Model for more details. + +Signed-off-by: Babu Moger +Message-Id: <1527176614-26271-3-git-send-email-babu.moger@amd.com> +Reviewed-by: Eduardo Habkost +Signed-off-by: Eduardo Habkost +(cherry picked from commit 8f4202fb1080f86958782b1fca0bf0279f67d136) +Signed-off-by: Eduardo Habkost +Signed-off-by: Miroslav Rezanina +--- + target/i386/cpu.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ + target/i386/kvm.c | 29 ++++++++++++-- + 2 files changed, 143 insertions(+), 3 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 41d0b72..57f74c6 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -337,6 +337,99 @@ static void encode_cache_cpuid80000006(CPUCacheInfo *l2, + } + + /* ++ * Definitions used for building CPUID Leaf 0x8000001D and 0x8000001E ++ * Please refer to the AMD64 Architecture Programmer’s Manual Volume 3. ++ * Define the constants to build the cpu topology. Right now, TOPOEXT ++ * feature is enabled only on EPYC. So, these constants are based on ++ * EPYC supported configurations. We may need to handle the cases if ++ * these values change in future. ++ */ ++/* Maximum core complexes in a node */ ++#define MAX_CCX 2 ++/* Maximum cores in a core complex */ ++#define MAX_CORES_IN_CCX 4 ++/* Maximum cores in a node */ ++#define MAX_CORES_IN_NODE 8 ++/* Maximum nodes in a socket */ ++#define MAX_NODES_PER_SOCKET 4 ++ ++/* ++ * Figure out the number of nodes required to build this config. ++ * Max cores in a node is 8 ++ */ ++static int nodes_in_socket(int nr_cores) ++{ ++ int nodes; ++ ++ nodes = DIV_ROUND_UP(nr_cores, MAX_CORES_IN_NODE); ++ ++ /* Hardware does not support config with 3 nodes, return 4 in that case */ ++ return (nodes == 3) ? 4 : nodes; ++} ++ ++/* ++ * Decide the number of cores in a core complex with the given nr_cores using ++ * following set constants MAX_CCX, MAX_CORES_IN_CCX, MAX_CORES_IN_NODE and ++ * MAX_NODES_PER_SOCKET. Maintain symmetry as much as possible ++ * L3 cache is shared across all cores in a core complex. So, this will also ++ * tell us how many cores are sharing the L3 cache. ++ */ ++static int cores_in_core_complex(int nr_cores) ++{ ++ int nodes; ++ ++ /* Check if we can fit all the cores in one core complex */ ++ if (nr_cores <= MAX_CORES_IN_CCX) { ++ return nr_cores; ++ } ++ /* Get the number of nodes required to build this config */ ++ nodes = nodes_in_socket(nr_cores); ++ ++ /* ++ * Divide the cores accros all the core complexes ++ * Return rounded up value ++ */ ++ return DIV_ROUND_UP(nr_cores, nodes * MAX_CCX); ++} ++ ++/* Encode cache info for CPUID[8000001D] */ ++static void encode_cache_cpuid8000001d(CPUCacheInfo *cache, CPUState *cs, ++ uint32_t *eax, uint32_t *ebx, ++ uint32_t *ecx, uint32_t *edx) ++{ ++ uint32_t l3_cores; ++ assert(cache->size == cache->line_size * cache->associativity * ++ cache->partitions * cache->sets); ++ ++ *eax = CACHE_TYPE(cache->type) | CACHE_LEVEL(cache->level) | ++ (cache->self_init ? CACHE_SELF_INIT_LEVEL : 0); ++ ++ /* L3 is shared among multiple cores */ ++ if (cache->level == 3) { ++ l3_cores = cores_in_core_complex(cs->nr_cores); ++ *eax |= ((l3_cores * cs->nr_threads) - 1) << 14; ++ } else { ++ *eax |= ((cs->nr_threads - 1) << 14); ++ } ++ ++ assert(cache->line_size > 0); ++ assert(cache->partitions > 0); ++ assert(cache->associativity > 0); ++ /* We don't implement fully-associative caches */ ++ assert(cache->associativity < cache->sets); ++ *ebx = (cache->line_size - 1) | ++ ((cache->partitions - 1) << 12) | ++ ((cache->associativity - 1) << 22); ++ ++ assert(cache->sets > 0); ++ *ecx = cache->sets - 1; ++ ++ *edx = (cache->no_invd_sharing ? CACHE_NO_INVD_SHARING : 0) | ++ (cache->inclusive ? CACHE_INCLUSIVE : 0) | ++ (cache->complex_indexing ? CACHE_COMPLEX_IDX : 0); ++} ++ ++/* + * Definitions of the hardcoded cache entries we expose: + * These are legacy cache values. If there is a need to change any + * of these values please use builtin_x86_defs +@@ -3988,6 +4081,30 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + *edx = 0; + } + break; ++ case 0x8000001D: ++ *eax = 0; ++ switch (count) { ++ case 0: /* L1 dcache info */ ++ encode_cache_cpuid8000001d(env->cache_info_amd.l1d_cache, cs, ++ eax, ebx, ecx, edx); ++ break; ++ case 1: /* L1 icache info */ ++ encode_cache_cpuid8000001d(env->cache_info_amd.l1i_cache, cs, ++ eax, ebx, ecx, edx); ++ break; ++ case 2: /* L2 cache info */ ++ encode_cache_cpuid8000001d(env->cache_info_amd.l2_cache, cs, ++ eax, ebx, ecx, edx); ++ break; ++ case 3: /* L3 cache info */ ++ encode_cache_cpuid8000001d(env->cache_info_amd.l3_cache, cs, ++ eax, ebx, ecx, edx); ++ break; ++ default: /* end of info */ ++ *eax = *ebx = *ecx = *edx = 0; ++ break; ++ } ++ break; + case 0xC0000000: + *eax = env->cpuid_xlevel2; + *ebx = 0; +diff --git a/target/i386/kvm.c b/target/i386/kvm.c +index 19e6aa3..447215b 100644 +--- a/target/i386/kvm.c ++++ b/target/i386/kvm.c +@@ -968,9 +968,32 @@ int kvm_arch_init_vcpu(CPUState *cs) + } + c = &cpuid_data.entries[cpuid_i++]; + +- c->function = i; +- c->flags = 0; +- cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx); ++ switch (i) { ++ case 0x8000001d: ++ /* Query for all AMD cache information leaves */ ++ for (j = 0; ; j++) { ++ c->function = i; ++ c->flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX; ++ c->index = j; ++ cpu_x86_cpuid(env, i, j, &c->eax, &c->ebx, &c->ecx, &c->edx); ++ ++ if (c->eax == 0) { ++ break; ++ } ++ if (cpuid_i == KVM_MAX_CPUID_ENTRIES) { ++ fprintf(stderr, "cpuid_data is full, no space for " ++ "cpuid(eax:0x%x,ecx:0x%x)\n", i, j); ++ abort(); ++ } ++ c = &cpuid_data.entries[cpuid_i++]; ++ } ++ break; ++ default: ++ c->function = i; ++ c->flags = 0; ++ cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx); ++ break; ++ } + } + + /* Call Centaur's CPUID instructions they are supported. */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-i386-Remove-generic-SMT-thread-check.patch b/SOURCES/kvm-i386-Remove-generic-SMT-thread-check.patch new file mode 100644 index 0000000..1c065c3 --- /dev/null +++ b/SOURCES/kvm-i386-Remove-generic-SMT-thread-check.patch @@ -0,0 +1,69 @@ +From 65165d3130b3f1d85cfb3078f96f9b0b29e8f42e Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Tue, 3 Jul 2018 17:23:56 +0200 +Subject: [PATCH 11/89] i386: Remove generic SMT thread check + +RH-Author: Eduardo Habkost +Message-id: <20180703172356.21038-11-ehabkost@redhat.com> +Patchwork-id: 81220 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v3 10/10] i386: Remove generic SMT thread check +Bugzilla: 1481253 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Igor Mammedov +RH-Acked-by: Miroslav Rezanina + +From: Babu Moger + +Remove generic non-intel check while validating hyperthreading support. +Certain AMD CPUs can support hyperthreading now. + +CPU family with TOPOEXT feature can support hyperthreading now. + +Signed-off-by: Babu Moger +Tested-by: Geoffrey McRae +Reviewed-by: Eduardo Habkost +Message-Id: <1529443919-67509-4-git-send-email-babu.moger@amd.com> +Signed-off-by: Eduardo Habkost +(cherry picked from commit 6b2942f966d5e54c37d305c80f5f98d504c2bc55) +Signed-off-by: Eduardo Habkost +Signed-off-by: Miroslav Rezanina +--- + target/i386/cpu.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 5d5d7e6..eabe4ea 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -4952,17 +4952,22 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) + + qemu_init_vcpu(cs); + +- /* Only Intel CPUs support hyperthreading. Even though QEMU fixes this +- * issue by adjusting CPUID_0000_0001_EBX and CPUID_8000_0008_ECX +- * based on inputs (sockets,cores,threads), it is still better to gives ++ /* ++ * Most Intel and certain AMD CPUs support hyperthreading. Even though QEMU ++ * fixes this issue by adjusting CPUID_0000_0001_EBX and CPUID_8000_0008_ECX ++ * based on inputs (sockets,cores,threads), it is still better to give + * users a warning. + * + * NOTE: the following code has to follow qemu_init_vcpu(). Otherwise + * cs->nr_threads hasn't be populated yet and the checking is incorrect. + */ +- if (!IS_INTEL_CPU(env) && cs->nr_threads > 1 && !ht_warned) { +- error_report("AMD CPU doesn't support hyperthreading. Please configure" +- " -smp options properly."); ++ if (IS_AMD_CPU(env) && ++ !(env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_TOPOEXT) && ++ cs->nr_threads > 1 && !ht_warned) { ++ error_report("This family of AMD CPU doesn't support " ++ "hyperthreading(%d). Please configure -smp " ++ "options properly or try enabling topoext feature.", ++ cs->nr_threads); + ht_warned = true; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-i386-cpu-hyperv-support-over-64-vcpus-for-windows-gu.patch b/SOURCES/kvm-i386-cpu-hyperv-support-over-64-vcpus-for-windows-gu.patch deleted file mode 100644 index 9c55fa9..0000000 --- a/SOURCES/kvm-i386-cpu-hyperv-support-over-64-vcpus-for-windows-gu.patch +++ /dev/null @@ -1,116 +0,0 @@ -From b2f9f4fcaad9c64f4551ab1dbe9e474c3dc6b2b4 Mon Sep 17 00:00:00 2001 -From: Miroslav Rezanina -Date: Mon, 27 Nov 2017 12:59:13 +0100 -Subject: [PATCH 10/15] i386/cpu/hyperv: support over 64 vcpus for windows - guests - -RH-Author: vrozenfe -Message-id: <1511256034-28105-1-git-send-email-vrozenfe@redhat.com> -Patchwork-id: 77769 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH v2] i386/cpu/hyperv: support over 64 vcpus for windows guests -Bugzilla: 1451959 -RH-Acked-by: Eduardo Habkost -RH-Acked-by: Thomas Huth -RH-Acked-by: Miroslav Rezanina - -From: Gonglei - -Upstream-status: 6c69dfb67e84747cf071958594d939e845dfcc0c - -Starting with Windows Server 2012 and Windows 8, if -CPUID.40000005.EAX contains a value of -1, Windows assumes specific -limit to the number of VPs. In this case, Windows Server 2012 -guest VMs may use more than 64 VPs, up to the maximum supported -number of processors applicable to the specific Windows -version being used. - -https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs - -For compatibility, Let's introduce a new property for X86CPU, -named "x-hv-max-vps" as Eduardo's suggestion, and set it -to 0x40 before machine 2.10. - -(The "x-" prefix indicates that the property is not supposed to -be a stable user interface.) - -Signed-off-by: Gonglei -Message-Id: <1505143227-14324-1-git-send-email-arei.gonglei@huawei.com> -Signed-off-by: Paolo Bonzini -Signed-off-by: Vadim Rozenfeld ---- - include/hw/i386/pc.h | 5 +++++ - target/i386/cpu.c | 13 +++++++++++++ - target/i386/cpu.h | 2 ++ - target/i386/kvm.c | 3 ++- - 4 files changed, 22 insertions(+), 1 deletion(-) - -diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h -index 7b46121..f9b7998 100644 ---- a/include/hw/i386/pc.h -+++ b/include/hw/i386/pc.h -@@ -1089,6 +1089,11 @@ extern void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id); - .driver = TYPE_X86_CPU,\ - .property = "kvm-no-smi-migration",\ - .value = "on",\ -+ },\ -+ { /* PC_RHEL7_4_COMPAT from PC_COMPAT_2_10 */ \ -+ .driver = TYPE_X86_CPU,\ -+ .property = "x-hv-max-vps",\ -+ .value = "0x40",\ - }, - - #define PC_RHEL7_2_COMPAT \ -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index ca95336..c2dee60 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -4179,6 +4179,19 @@ static Property x86_cpu_properties[] = { - false), - DEFINE_PROP_BOOL("vmware-cpuid-freq", X86CPU, vmware_cpuid_freq, true), - DEFINE_PROP_BOOL("tcg-cpuid", X86CPU, expose_tcg, true), -+ /* -+ * From "Requirements for Implementing the Microsoft -+ * Hypervisor Interface": -+ * https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs -+ * -+ * "Starting with Windows Server 2012 and Windows 8, if -+ * CPUID.40000005.EAX contains a value of -1, Windows assumes that -+ * the hypervisor imposes no specific limit to the number of VPs. -+ * In this case, Windows Server 2012 guest VMs may use more than -+ * 64 VPs, up to the maximum supported number of processors applicable -+ * to the specific Windows version being used." -+ */ -+ DEFINE_PROP_INT32("x-hv-max-vps", X86CPU, hv_max_vps, -1), - DEFINE_PROP_END_OF_LIST() - }; - -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 0518673..fd73888 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -1282,6 +1282,8 @@ struct X86CPU { - int32_t socket_id; - int32_t core_id; - int32_t thread_id; -+ -+ int32_t hv_max_vps; - }; - - static inline X86CPU *x86_env_get_cpu(CPUX86State *env) -diff --git a/target/i386/kvm.c b/target/i386/kvm.c -index 739334a..ee4e91f 100644 ---- a/target/i386/kvm.c -+++ b/target/i386/kvm.c -@@ -786,7 +786,8 @@ int kvm_arch_init_vcpu(CPUState *cs) - - c = &cpuid_data.entries[cpuid_i++]; - c->function = HYPERV_CPUID_IMPLEMENT_LIMITS; -- c->eax = 0x40; -+ -+ c->eax = cpu->hv_max_vps; - c->ebx = 0x40; - - kvm_base = KVM_CPUID_SIGNATURE_NEXT; --- -1.8.3.1 - diff --git a/SOURCES/kvm-i386-define-the-AMD-virt-ssbd-CPUID-feature-bit-CVE-.patch b/SOURCES/kvm-i386-define-the-AMD-virt-ssbd-CPUID-feature-bit-CVE-.patch new file mode 100644 index 0000000..e9bbcf9 --- /dev/null +++ b/SOURCES/kvm-i386-define-the-AMD-virt-ssbd-CPUID-feature-bit-CVE-.patch @@ -0,0 +1,54 @@ +From e51d47fda8344f093a28c49de9daea38ba2527dd Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Wed, 13 Jun 2018 18:08:12 +0200 +Subject: [PATCH 05/57] i386: define the AMD 'virt-ssbd' CPUID feature bit + (CVE-2018-3639) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Eduardo Habkost +Message-id: <20180613180812.28169-3-ehabkost@redhat.com> +Patchwork-id: 80676 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 2/2] i386: define the AMD 'virt-ssbd' CPUID feature bit (CVE-2018-3639) +Bugzilla: 1574216 +RH-Acked-by: Igor Mammedov +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: Laurent Vivier + +From: Konrad Rzeszutek Wilk + +AMD Zen expose the Intel equivalant to Speculative Store Bypass Disable +via the 0x80000008_EBX[25] CPUID feature bit. + +This needs to be exposed to guest OS to allow them to protect +against CVE-2018-3639. + +Signed-off-by: Konrad Rzeszutek Wilk +Reviewed-by: Daniel P. Berrangé +Signed-off-by: Daniel P. Berrangé +Message-Id: <20180521215424.13520-3-berrange@redhat.com> +Signed-off-by: Eduardo Habkost +(cherry picked from commit 403503b162ffc33fb64cfefdf7b880acf41772cd) +Signed-off-by: Eduardo Habkost +Signed-off-by: Miroslav Rezanina +--- + target/i386/cpu.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 0fc7fb0..5d60d76 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -541,7 +541,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + "ibpb", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +- NULL, NULL, NULL, NULL, ++ NULL, "virt-ssbd", NULL, NULL, + NULL, NULL, NULL, NULL, + }, + .cpuid_eax = 0x80000008, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-i386-define-the-ssbd-CPUID-feature-bit-CVE-2018-3639.patch b/SOURCES/kvm-i386-define-the-ssbd-CPUID-feature-bit-CVE-2018-3639.patch new file mode 100644 index 0000000..5e2de7d --- /dev/null +++ b/SOURCES/kvm-i386-define-the-ssbd-CPUID-feature-bit-CVE-2018-3639.patch @@ -0,0 +1,65 @@ +From a075f54393d3a00554855b938f3adfd7aaafec76 Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Thu, 30 Aug 2018 14:18:05 +0200 +Subject: [PATCH 06/29] i386: define the 'ssbd' CPUID feature bit + (CVE-2018-3639) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Eduardo Habkost +Message-id: <20180830141805.6667-2-ehabkost@redhat.com> +Patchwork-id: 81977 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/1] i386: define the 'ssbd' CPUID feature bit (CVE-2018-3639) +Bugzilla: 1574216 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Igor Mammedov +RH-Acked-by: Daniel P. Berrange + +From: Daniel P. Berrangé + +New microcode introduces the "Speculative Store Bypass Disable" +CPUID feature bit. This needs to be exposed to guest OS to allow +them to protect against CVE-2018-3639. + +Signed-off-by: Daniel P. Berrangé +Reviewed-by: Konrad Rzeszutek Wilk +Signed-off-by: Konrad Rzeszutek Wilk +Message-Id: <20180521215424.13520-2-berrange@redhat.com> +Signed-off-by: Eduardo Habkost +(cherry picked from commit d19d1f965904a533998739698020ff4ee8a103da) +Signed-off-by: Eduardo Habkost +Signed-off-by: Miroslav Rezanina +--- + target/i386/cpu.c | 2 +- + target/i386/cpu.h | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index e6ad66c..e317aaf 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -1008,7 +1008,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, "spec-ctrl", NULL, +- NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, "ssbd", + }, + .cpuid_eax = 7, + .cpuid_needs_ecx = true, .cpuid_ecx = 0, +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index c80c461..75cf5ed 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -686,6 +686,7 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; + #define CPUID_7_0_EDX_AVX512_4VNNIW (1U << 2) /* AVX512 Neural Network Instructions */ + #define CPUID_7_0_EDX_AVX512_4FMAPS (1U << 3) /* AVX512 Multiply Accumulation Single Precision */ + #define CPUID_7_0_EDX_SPEC_CTRL (1U << 26) /* Speculation Control */ ++#define CPUID_7_0_EDX_SPEC_CTRL_SSBD (1U << 31) /* Speculative Store Bypass Disable */ + + #define KVM_HINTS_DEDICATED (1U << 0) + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-i386-kvm-advertise-Hyper-V-frequency-MSRs.patch b/SOURCES/kvm-i386-kvm-advertise-Hyper-V-frequency-MSRs.patch deleted file mode 100644 index dd72f1a..0000000 --- a/SOURCES/kvm-i386-kvm-advertise-Hyper-V-frequency-MSRs.patch +++ /dev/null @@ -1,74 +0,0 @@ -From 8225804259b165300d2d1cc1c4bdbad32fadf6da Mon Sep 17 00:00:00 2001 -From: Ladi Prosek -Date: Tue, 10 Oct 2017 14:02:51 +0200 -Subject: [PATCH 13/69] i386/kvm: advertise Hyper-V frequency MSRs - -RH-Author: Ladi Prosek -Message-id: <20171010140251.23801-5-lprosek@redhat.com> -Patchwork-id: 77063 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 4/4] i386/kvm: advertise Hyper-V frequency MSRs -Bugzilla: 1500347 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: David Hildenbrand -RH-Acked-by: Laszlo Ersek - -As of kernel commit eb82feea59d6 ("KVM: hyperv: support HV_X64_MSR_TSC_FREQUENCY -and HV_X64_MSR_APIC_FREQUENCY"), KVM supports two new MSRs which are required -for nested Hyper-V to read timestamps with RDTSC + TSC page. - -This commit makes QEMU advertise the MSRs with CPUID.40000003H:EAX[11] and -CPUID.40000003H:EDX[8] as specified in the Hyper-V TLFS and experimentally -verified on a Hyper-V host. The feature is enabled with the existing hv-time CPU -flag, and only if the TSC frequency is stable across migrations and known. - -Signed-off-by: Ladi Prosek -Reviewed-by: David Hildenbrand -Message-Id: <20170807085703.32267-5-lprosek@redhat.com> -Signed-off-by: Paolo Bonzini -(cherry picked from commit d72bc7f6f8a397790abee4a25ba1b8c35dd2b841) -Signed-off-by: Ladi Prosek -Signed-off-by: Miroslav Rezanina ---- - target/i386/kvm.c | 12 +++++++++++- - 1 file changed, 11 insertions(+), 1 deletion(-) - -diff --git a/target/i386/kvm.c b/target/i386/kvm.c -index 2dc01c9..739334a 100644 ---- a/target/i386/kvm.c -+++ b/target/i386/kvm.c -@@ -89,6 +89,7 @@ static bool has_msr_hv_vpindex; - static bool has_msr_hv_runtime; - static bool has_msr_hv_synic; - static bool has_msr_hv_stimer; -+static bool has_msr_hv_frequencies; - static bool has_msr_xss; - - static bool has_msr_architectural_pmu; -@@ -640,7 +641,13 @@ static int hyperv_handle_properties(CPUState *cs) - if (cpu->hyperv_time) { - env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_HYPERCALL_AVAILABLE; - env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_TIME_REF_COUNT_AVAILABLE; -- env->features[FEAT_HYPERV_EAX] |= 0x200; -+ env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_REFERENCE_TSC_AVAILABLE; -+ -+ if (has_msr_hv_frequencies && tsc_is_stable_and_known(env)) { -+ env->features[FEAT_HYPERV_EAX] |= HV_X64_ACCESS_FREQUENCY_MSRS; -+ env->features[FEAT_HYPERV_EDX] |= -+ HV_FEATURE_FREQUENCY_MSRS_AVAILABLE; -+ } - } - if (cpu->hyperv_crash && has_msr_hv_crash) { - env->features[FEAT_HYPERV_EDX] |= HV_X64_GUEST_CRASH_MSR_AVAILABLE; -@@ -1134,6 +1141,9 @@ static int kvm_get_supported_msrs(KVMState *s) - case HV_X64_MSR_STIMER0_CONFIG: - has_msr_hv_stimer = true; - break; -+ case HV_X64_MSR_TSC_FREQUENCY: -+ has_msr_hv_frequencies = true; -+ break; - } - } - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-i386-kvm-introduce-tsc_is_stable_and_known.patch b/SOURCES/kvm-i386-kvm-introduce-tsc_is_stable_and_known.patch deleted file mode 100644 index c8f4690..0000000 --- a/SOURCES/kvm-i386-kvm-introduce-tsc_is_stable_and_known.patch +++ /dev/null @@ -1,61 +0,0 @@ -From d9e6ce9628a29f7992dd381a54aae14d45078bf8 Mon Sep 17 00:00:00 2001 -From: Ladi Prosek -Date: Tue, 10 Oct 2017 14:02:50 +0200 -Subject: [PATCH 12/69] i386/kvm: introduce tsc_is_stable_and_known() - -RH-Author: Ladi Prosek -Message-id: <20171010140251.23801-4-lprosek@redhat.com> -Patchwork-id: 77062 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 3/4] i386/kvm: introduce tsc_is_stable_and_known() -Bugzilla: 1500347 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: David Hildenbrand -RH-Acked-by: Laszlo Ersek - -Move the "is TSC stable and known" condition to a reusable helper. - -Signed-off-by: Ladi Prosek -Reviewed-by: David Hildenbrand -Message-Id: <20170807085703.32267-4-lprosek@redhat.com> -Signed-off-by: Paolo Bonzini -(cherry picked from commit 4bb95b82df7ea4a1c7de15649dd16a70a19e6bab) -Signed-off-by: Ladi Prosek -Signed-off-by: Miroslav Rezanina ---- - target/i386/kvm.c | 13 ++++++++++--- - 1 file changed, 10 insertions(+), 3 deletions(-) - -diff --git a/target/i386/kvm.c b/target/i386/kvm.c -index 15d56ae..2dc01c9 100644 ---- a/target/i386/kvm.c -+++ b/target/i386/kvm.c -@@ -611,6 +611,15 @@ static int kvm_arch_set_tsc_khz(CPUState *cs) - return 0; - } - -+static bool tsc_is_stable_and_known(CPUX86State *env) -+{ -+ if (!env->tsc_khz) { -+ return false; -+ } -+ return (env->features[FEAT_8000_0007_EDX] & CPUID_APM_INVTSC) -+ || env->user_tsc_khz; -+} -+ - static int hyperv_handle_properties(CPUState *cs) - { - X86CPU *cpu = X86_CPU(cs); -@@ -986,9 +995,7 @@ int kvm_arch_init_vcpu(CPUState *cs) - && cpu->expose_kvm - && kvm_base == KVM_CPUID_SIGNATURE - /* TSC clock must be stable and known for this feature. */ -- && ((env->features[FEAT_8000_0007_EDX] & CPUID_APM_INVTSC) -- || env->user_tsc_khz != 0) -- && env->tsc_khz != 0) { -+ && tsc_is_stable_and_known(env)) { - - c = &cpuid_data.entries[cpuid_i++]; - c->function = KVM_CPUID_SIGNATURE | 0x10; --- -1.8.3.1 - diff --git a/SOURCES/kvm-i386-kvm-set-tsc_khz-before-configuring-Hyper-V-CPUI.patch b/SOURCES/kvm-i386-kvm-set-tsc_khz-before-configuring-Hyper-V-CPUI.patch deleted file mode 100644 index 02db5ee..0000000 --- a/SOURCES/kvm-i386-kvm-set-tsc_khz-before-configuring-Hyper-V-CPUI.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 4297501331fd196444ad0b830b026ae39c2744cf Mon Sep 17 00:00:00 2001 -From: Ladi Prosek -Date: Tue, 10 Oct 2017 14:02:49 +0200 -Subject: [PATCH 11/69] i386/kvm: set tsc_khz before configuring Hyper-V CPUID - -RH-Author: Ladi Prosek -Message-id: <20171010140251.23801-3-lprosek@redhat.com> -Patchwork-id: 77060 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 2/4] i386/kvm: set tsc_khz before configuring Hyper-V CPUID -Bugzilla: 1500347 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: David Hildenbrand -RH-Acked-by: Laszlo Ersek - -Timing-related Hyper-V enlightenments will benefit from knowing the final -tsc_khz value. This commit just moves the code in preparation for further -changes. - -Signed-off-by: Ladi Prosek -Message-Id: <20170807085703.32267-3-lprosek@redhat.com> -Signed-off-by: Paolo Bonzini -(cherry picked from commit ddb98b5a9ff27b21100da1d701ddf5da34c66673) -Signed-off-by: Ladi Prosek -Signed-off-by: Miroslav Rezanina ---- - target/i386/kvm.c | 38 +++++++++++++++++++------------------- - 1 file changed, 19 insertions(+), 19 deletions(-) - -diff --git a/target/i386/kvm.c b/target/i386/kvm.c -index b14a0db..15d56ae 100644 ---- a/target/i386/kvm.c -+++ b/target/i386/kvm.c -@@ -695,6 +695,25 @@ int kvm_arch_init_vcpu(CPUState *cs) - - cpuid_i = 0; - -+ r = kvm_arch_set_tsc_khz(cs); -+ if (r < 0) { -+ goto fail; -+ } -+ -+ /* vcpu's TSC frequency is either specified by user, or following -+ * the value used by KVM if the former is not present. In the -+ * latter case, we query it from KVM and record in env->tsc_khz, -+ * so that vcpu's TSC frequency can be migrated later via this field. -+ */ -+ if (!env->tsc_khz) { -+ r = kvm_check_extension(cs->kvm_state, KVM_CAP_GET_TSC_KHZ) ? -+ kvm_vcpu_ioctl(cs, KVM_GET_TSC_KHZ) : -+ -ENOTSUP; -+ if (r > 0) { -+ env->tsc_khz = r; -+ } -+ } -+ - /* Paravirtualization CPUIDs */ - if (hyperv_enabled(cpu)) { - c = &cpuid_data.entries[cpuid_i++]; -@@ -961,25 +980,6 @@ int kvm_arch_init_vcpu(CPUState *cs) - } - } - -- r = kvm_arch_set_tsc_khz(cs); -- if (r < 0) { -- goto fail; -- } -- -- /* vcpu's TSC frequency is either specified by user, or following -- * the value used by KVM if the former is not present. In the -- * latter case, we query it from KVM and record in env->tsc_khz, -- * so that vcpu's TSC frequency can be migrated later via this field. -- */ -- if (!env->tsc_khz) { -- r = kvm_check_extension(cs->kvm_state, KVM_CAP_GET_TSC_KHZ) ? -- kvm_vcpu_ioctl(cs, KVM_GET_TSC_KHZ) : -- -ENOTSUP; -- if (r > 0) { -- env->tsc_khz = r; -- } -- } -- - if (cpu->vmware_cpuid_freq - /* Guests depend on 0x40000000 to detect this feature, so only expose - * it if KVM exposes leaf 0x40000000. (Conflicts with Hyper-V) */ --- -1.8.3.1 - diff --git a/SOURCES/kvm-i386-kvm-use-a-switch-statement-for-MSR-detection.patch b/SOURCES/kvm-i386-kvm-use-a-switch-statement-for-MSR-detection.patch deleted file mode 100644 index d7a78f5..0000000 --- a/SOURCES/kvm-i386-kvm-use-a-switch-statement-for-MSR-detection.patch +++ /dev/null @@ -1,131 +0,0 @@ -From 5657d9d31587d9e5e2e89ec5036af88dccb3a6a7 Mon Sep 17 00:00:00 2001 -From: Ladi Prosek -Date: Tue, 10 Oct 2017 14:02:48 +0200 -Subject: [PATCH 10/69] i386/kvm: use a switch statement for MSR detection - -RH-Author: Ladi Prosek -Message-id: <20171010140251.23801-2-lprosek@redhat.com> -Patchwork-id: 77059 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 1/4] i386/kvm: use a switch statement for MSR detection -Bugzilla: 1500347 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: David Hildenbrand -RH-Acked-by: Laszlo Ersek - -Switch is easier on the eye and might lead to better codegen. - -Signed-off-by: Ladi Prosek -Reviewed-by: David Hildenbrand -Message-Id: <20170807085703.32267-2-lprosek@redhat.com> -Signed-off-by: Paolo Bonzini -(cherry picked from commit 1d268dece4991915c0dd0f882248cbcb22ae8ffc) -Signed-off-by: Ladi Prosek -Signed-off-by: Miroslav Rezanina ---- - target/i386/kvm.c | 75 +++++++++++++++++++++++-------------------------------- - 1 file changed, 31 insertions(+), 44 deletions(-) - -diff --git a/target/i386/kvm.c b/target/i386/kvm.c -index 6db7783..b14a0db 100644 ---- a/target/i386/kvm.c -+++ b/target/i386/kvm.c -@@ -1081,65 +1081,52 @@ static int kvm_get_supported_msrs(KVMState *s) - int i; - - for (i = 0; i < kvm_msr_list->nmsrs; i++) { -- if (kvm_msr_list->indices[i] == MSR_STAR) { -+ switch (kvm_msr_list->indices[i]) { -+ case MSR_STAR: - has_msr_star = true; -- continue; -- } -- if (kvm_msr_list->indices[i] == MSR_VM_HSAVE_PA) { -+ break; -+ case MSR_VM_HSAVE_PA: - has_msr_hsave_pa = true; -- continue; -- } -- if (kvm_msr_list->indices[i] == MSR_TSC_AUX) { -+ break; -+ case MSR_TSC_AUX: - has_msr_tsc_aux = true; -- continue; -- } -- if (kvm_msr_list->indices[i] == MSR_TSC_ADJUST) { -+ break; -+ case MSR_TSC_ADJUST: - has_msr_tsc_adjust = true; -- continue; -- } -- if (kvm_msr_list->indices[i] == MSR_IA32_TSCDEADLINE) { -+ break; -+ case MSR_IA32_TSCDEADLINE: - has_msr_tsc_deadline = true; -- continue; -- } -- if (kvm_msr_list->indices[i] == MSR_IA32_SMBASE) { -+ break; -+ case MSR_IA32_SMBASE: - has_msr_smbase = true; -- continue; -- } -- if (kvm_msr_list->indices[i] == MSR_IA32_MISC_ENABLE) { -+ break; -+ case MSR_IA32_MISC_ENABLE: - has_msr_misc_enable = true; -- continue; -- } -- if (kvm_msr_list->indices[i] == MSR_IA32_BNDCFGS) { -+ break; -+ case MSR_IA32_BNDCFGS: - has_msr_bndcfgs = true; -- continue; -- } -- if (kvm_msr_list->indices[i] == MSR_IA32_XSS) { -+ break; -+ case MSR_IA32_XSS: - has_msr_xss = true; -- continue; -- } -- if (kvm_msr_list->indices[i] == HV_X64_MSR_CRASH_CTL) { -+ break;; -+ case HV_X64_MSR_CRASH_CTL: - has_msr_hv_crash = true; -- continue; -- } -- if (kvm_msr_list->indices[i] == HV_X64_MSR_RESET) { -+ break; -+ case HV_X64_MSR_RESET: - has_msr_hv_reset = true; -- continue; -- } -- if (kvm_msr_list->indices[i] == HV_X64_MSR_VP_INDEX) { -+ break; -+ case HV_X64_MSR_VP_INDEX: - has_msr_hv_vpindex = true; -- continue; -- } -- if (kvm_msr_list->indices[i] == HV_X64_MSR_VP_RUNTIME) { -+ break; -+ case HV_X64_MSR_VP_RUNTIME: - has_msr_hv_runtime = true; -- continue; -- } -- if (kvm_msr_list->indices[i] == HV_X64_MSR_SCONTROL) { -+ break; -+ case HV_X64_MSR_SCONTROL: - has_msr_hv_synic = true; -- continue; -- } -- if (kvm_msr_list->indices[i] == HV_X64_MSR_STIMER0_CONFIG) { -+ break; -+ case HV_X64_MSR_STIMER0_CONFIG: - has_msr_hv_stimer = true; -- continue; -+ break; - } - } - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-ide-avoid-referencing-NULL-dev-in-rotational-rate-se.patch b/SOURCES/kvm-ide-avoid-referencing-NULL-dev-in-rotational-rate-se.patch deleted file mode 100644 index c5947e8..0000000 --- a/SOURCES/kvm-ide-avoid-referencing-NULL-dev-in-rotational-rate-se.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 565928c4292fcc32ecb34c1516283929d7fcaf90 Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Wed, 29 Nov 2017 14:26:06 +0100 -Subject: [PATCH 20/21] ide: avoid referencing NULL dev in rotational rate - setting - -RH-Author: Daniel P. Berrange -Message-id: <20171129142606.15965-4-berrange@redhat.com> -Patchwork-id: 77972 -O-Subject: [PATCH RHV-7.5 qemu-kvm-rhev 3/3] ide: avoid referencing NULL dev in rotational rate setting -Bugzilla: 1498042 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: John Snow -RH-Acked-by: Stefan Hajnoczi - -The 'dev' variable can be NULL when the guest OS calls identify on an IDE -unit that does not have a drive attached to it. - -Signed-off-by: Daniel P. Berrange -Reviewed-by: Stefan Hajnoczi -Message-id: 20171020091403.1479-1-berrange@redhat.com -Signed-off-by: John Snow -(cherry picked from commit 96f43c2b0a663f4789b51ed97297163321e7ba5e) -Signed-off-by: Miroslav Rezanina ---- - hw/ide/core.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/hw/ide/core.c b/hw/ide/core.c -index 11986e3..506e8ed 100644 ---- a/hw/ide/core.c -+++ b/hw/ide/core.c -@@ -191,7 +191,9 @@ static void ide_identify(IDEState *s) - if (dev && dev->conf.discard_granularity) { - put_le16(p + 169, 1); /* TRIM support */ - } -- put_le16(p + 217, dev->rotation_rate); /* Nominal media rotation rate */ -+ if (dev) { -+ put_le16(p + 217, dev->rotation_rate); /* Nominal media rotation rate */ -+ } - - ide_identify_size(s); - s->identify_set = 1; --- -1.8.3.1 - diff --git a/SOURCES/kvm-ide-support-reporting-of-rotation-rate.patch b/SOURCES/kvm-ide-support-reporting-of-rotation-rate.patch deleted file mode 100644 index 3569f44..0000000 --- a/SOURCES/kvm-ide-support-reporting-of-rotation-rate.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 0bb526e2aa90f3f9143472da23ae3b64a4e3216d Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Wed, 29 Nov 2017 14:26:05 +0100 -Subject: [PATCH 19/21] ide: support reporting of rotation rate - -RH-Author: Daniel P. Berrange -Message-id: <20171129142606.15965-3-berrange@redhat.com> -Patchwork-id: 77965 -O-Subject: [PATCH RHV-7.5 qemu-kvm-rhev 2/3] ide: support reporting of rotation rate -Bugzilla: 1498042 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: John Snow -RH-Acked-by: Stefan Hajnoczi - -The Linux kernel will query the ATA IDENTITY DEVICE data, word 217 -to determine the rotations per minute of the disk. If this has -the value 1, it is taken to be an SSD and so Linux sets the -'rotational' flag to 0 for the I/O queue and will stop using that -disk as a source of random entropy. Other operating systems may -also take into account rotation rate when setting up default -behaviour. - -Mgmt apps should be able to set the rotation rate for virtualized -block devices, based on characteristics of the host storage in use, -so that the guest OS gets sensible behaviour out of the box. This -patch thus adds a 'rotation-rate' parameter for 'ide-hd' device -types. - -Signed-off-by: Daniel P. Berrange -Message-Id: <20171004114008.14849-3-berrange@redhat.com> -Reviewed-by: John Snow -Signed-off-by: Paolo Bonzini -(cherry picked from commit 3b19f4506901ecce25ff36cf62353a2b4bfe4f2b) -Signed-off-by: Miroslav Rezanina ---- - hw/ide/core.c | 1 + - hw/ide/qdev.c | 1 + - include/hw/ide/internal.h | 8 ++++++++ - 3 files changed, 10 insertions(+) - -diff --git a/hw/ide/core.c b/hw/ide/core.c -index bea3953..11986e3 100644 ---- a/hw/ide/core.c -+++ b/hw/ide/core.c -@@ -191,6 +191,7 @@ static void ide_identify(IDEState *s) - if (dev && dev->conf.discard_granularity) { - put_le16(p + 169, 1); /* TRIM support */ - } -+ put_le16(p + 217, dev->rotation_rate); /* Nominal media rotation rate */ - - ide_identify_size(s); - s->identify_set = 1; -diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c -index cc2f5bd..a412d6f 100644 ---- a/hw/ide/qdev.c -+++ b/hw/ide/qdev.c -@@ -304,6 +304,7 @@ static Property ide_hd_properties[] = { - DEFINE_BLOCK_CHS_PROPERTIES(IDEDrive, dev.conf), - DEFINE_PROP_BIOS_CHS_TRANS("bios-chs-trans", - IDEDrive, dev.chs_trans, BIOS_ATA_TRANSLATION_AUTO), -+ DEFINE_PROP_UINT16("rotation_rate", IDEDrive, dev.rotation_rate, 0), - DEFINE_PROP_END_OF_LIST(), - }; - -diff --git a/include/hw/ide/internal.h b/include/hw/ide/internal.h -index 482a951..f1aca72 100644 ---- a/include/hw/ide/internal.h -+++ b/include/hw/ide/internal.h -@@ -507,6 +507,14 @@ struct IDEDevice { - char *serial; - char *model; - uint64_t wwn; -+ /* -+ * 0x0000 - rotation rate not reported -+ * 0x0001 - non-rotating medium (SSD) -+ * 0x0002-0x0400 - reserved -+ * 0x0401-0xffe - rotations per minute -+ * 0xffff - reserved -+ */ -+ uint16_t rotation_rate; - }; - - /* These are used for the error_status field of IDEBus */ --- -1.8.3.1 - diff --git a/SOURCES/kvm-intel-iommu-add-iommu-lock.patch b/SOURCES/kvm-intel-iommu-add-iommu-lock.patch new file mode 100644 index 0000000..e699f30 --- /dev/null +++ b/SOURCES/kvm-intel-iommu-add-iommu-lock.patch @@ -0,0 +1,252 @@ +From c865a8af8574b64c06b9cbdf080d93e75dd8019c Mon Sep 17 00:00:00 2001 +From: Peter Xu +Date: Mon, 3 Sep 2018 04:52:35 +0200 +Subject: [PATCH 20/29] intel-iommu: add iommu lock + +RH-Author: Peter Xu +Message-id: <20180903045241.6456-4-peterx@redhat.com> +Patchwork-id: 82022 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 3/9] intel-iommu: add iommu lock +Bugzilla: 1623859 +RH-Acked-by: Xiao Wang +RH-Acked-by: Auger Eric +RH-Acked-by: Michael S. Tsirkin + +SECURITY IMPLICATION: this patch fixes a potential race when multiple +threads access the IOMMU IOTLB cache. + +Add a per-iommu big lock to protect IOMMU status. Currently the only +thing to be protected is the IOTLB/context cache, since that can be +accessed even without BQL, e.g., in IO dataplane. + +Note that we don't need to protect device page tables since that's fully +controlled by the guest kernel. However there is still possibility that +malicious drivers will program the device to not obey the rule. In that +case QEMU can't really do anything useful, instead the guest itself will +be responsible for all uncertainties. + +CC: QEMU Stable +Reported-by: Fam Zheng +Signed-off-by: Peter Xu +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 1d9efa73e12ddf361ea997c2d532cc4afa6674d1) +Signed-off-by: Peter Xu +Signed-off-by: Miroslav Rezanina +--- + hw/i386/intel_iommu.c | 56 ++++++++++++++++++++++++++++++++++++------- + include/hw/i386/intel_iommu.h | 6 +++++ + 2 files changed, 53 insertions(+), 9 deletions(-) + +diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c +index 3df9045..8d4069d 100644 +--- a/hw/i386/intel_iommu.c ++++ b/hw/i386/intel_iommu.c +@@ -128,6 +128,16 @@ static uint64_t vtd_set_clear_mask_quad(IntelIOMMUState *s, hwaddr addr, + return new_val; + } + ++static inline void vtd_iommu_lock(IntelIOMMUState *s) ++{ ++ qemu_mutex_lock(&s->iommu_lock); ++} ++ ++static inline void vtd_iommu_unlock(IntelIOMMUState *s) ++{ ++ qemu_mutex_unlock(&s->iommu_lock); ++} ++ + /* GHashTable functions */ + static gboolean vtd_uint64_equal(gconstpointer v1, gconstpointer v2) + { +@@ -172,9 +182,9 @@ static gboolean vtd_hash_remove_by_page(gpointer key, gpointer value, + } + + /* Reset all the gen of VTDAddressSpace to zero and set the gen of +- * IntelIOMMUState to 1. ++ * IntelIOMMUState to 1. Must be called with IOMMU lock held. + */ +-static void vtd_reset_context_cache(IntelIOMMUState *s) ++static void vtd_reset_context_cache_locked(IntelIOMMUState *s) + { + VTDAddressSpace *vtd_as; + VTDBus *vtd_bus; +@@ -197,12 +207,20 @@ static void vtd_reset_context_cache(IntelIOMMUState *s) + s->context_cache_gen = 1; + } + +-static void vtd_reset_iotlb(IntelIOMMUState *s) ++/* Must be called with IOMMU lock held. */ ++static void vtd_reset_iotlb_locked(IntelIOMMUState *s) + { + assert(s->iotlb); + g_hash_table_remove_all(s->iotlb); + } + ++static void vtd_reset_iotlb(IntelIOMMUState *s) ++{ ++ vtd_iommu_lock(s); ++ vtd_reset_iotlb_locked(s); ++ vtd_iommu_unlock(s); ++} ++ + static uint64_t vtd_get_iotlb_key(uint64_t gfn, uint16_t source_id, + uint32_t level) + { +@@ -215,6 +233,7 @@ static uint64_t vtd_get_iotlb_gfn(hwaddr addr, uint32_t level) + return (addr & vtd_slpt_level_page_mask(level)) >> VTD_PAGE_SHIFT_4K; + } + ++/* Must be called with IOMMU lock held */ + static VTDIOTLBEntry *vtd_lookup_iotlb(IntelIOMMUState *s, uint16_t source_id, + hwaddr addr) + { +@@ -235,6 +254,7 @@ out: + return entry; + } + ++/* Must be with IOMMU lock held */ + static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id, + uint16_t domain_id, hwaddr addr, uint64_t slpte, + uint8_t access_flags, uint32_t level) +@@ -246,7 +266,7 @@ static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id, + trace_vtd_iotlb_page_update(source_id, addr, slpte, domain_id); + if (g_hash_table_size(s->iotlb) >= VTD_IOTLB_MAX_SIZE) { + trace_vtd_iotlb_reset("iotlb exceeds size limit"); +- vtd_reset_iotlb(s); ++ vtd_reset_iotlb_locked(s); + } + + entry->gfn = gfn; +@@ -1106,7 +1126,7 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus, + IntelIOMMUState *s = vtd_as->iommu_state; + VTDContextEntry ce; + uint8_t bus_num = pci_bus_num(bus); +- VTDContextCacheEntry *cc_entry = &vtd_as->context_cache_entry; ++ VTDContextCacheEntry *cc_entry; + uint64_t slpte, page_mask; + uint32_t level; + uint16_t source_id = vtd_make_source_id(bus_num, devfn); +@@ -1123,6 +1143,10 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus, + */ + assert(!vtd_is_interrupt_addr(addr)); + ++ vtd_iommu_lock(s); ++ ++ cc_entry = &vtd_as->context_cache_entry; ++ + /* Try to fetch slpte form IOTLB */ + iotlb_entry = vtd_lookup_iotlb(s, source_id, addr); + if (iotlb_entry) { +@@ -1182,7 +1206,7 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus, + * IOMMU region can be swapped back. + */ + vtd_pt_enable_fast_path(s, source_id); +- ++ vtd_iommu_unlock(s); + return true; + } + +@@ -1203,6 +1227,7 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus, + vtd_update_iotlb(s, source_id, VTD_CONTEXT_ENTRY_DID(ce.hi), addr, slpte, + access_flags, level); + out: ++ vtd_iommu_unlock(s); + entry->iova = addr & page_mask; + entry->translated_addr = vtd_get_slpte_addr(slpte, s->aw_bits) & page_mask; + entry->addr_mask = ~page_mask; +@@ -1210,6 +1235,7 @@ out: + return true; + + error: ++ vtd_iommu_unlock(s); + entry->iova = 0; + entry->translated_addr = 0; + entry->addr_mask = 0; +@@ -1258,10 +1284,13 @@ static void vtd_iommu_replay_all(IntelIOMMUState *s) + static void vtd_context_global_invalidate(IntelIOMMUState *s) + { + trace_vtd_inv_desc_cc_global(); ++ /* Protects context cache */ ++ vtd_iommu_lock(s); + s->context_cache_gen++; + if (s->context_cache_gen == VTD_CONTEXT_CACHE_GEN_MAX) { +- vtd_reset_context_cache(s); ++ vtd_reset_context_cache_locked(s); + } ++ vtd_iommu_unlock(s); + vtd_switch_address_space_all(s); + /* + * From VT-d spec 6.5.2.1, a global context entry invalidation +@@ -1313,7 +1342,9 @@ static void vtd_context_device_invalidate(IntelIOMMUState *s, + if (vtd_as && ((devfn_it & mask) == (devfn & mask))) { + trace_vtd_inv_desc_cc_device(bus_n, VTD_PCI_SLOT(devfn_it), + VTD_PCI_FUNC(devfn_it)); ++ vtd_iommu_lock(s); + vtd_as->context_cache_entry.context_cache_gen = 0; ++ vtd_iommu_unlock(s); + /* + * Do switch address space when needed, in case if the + * device passthrough bit is switched. +@@ -1377,8 +1408,10 @@ static void vtd_iotlb_domain_invalidate(IntelIOMMUState *s, uint16_t domain_id) + + trace_vtd_inv_desc_iotlb_domain(domain_id); + ++ vtd_iommu_lock(s); + g_hash_table_foreach_remove(s->iotlb, vtd_hash_remove_by_domain, + &domain_id); ++ vtd_iommu_unlock(s); + + QLIST_FOREACH(vtd_as, &s->vtd_as_with_notifiers, next) { + if (!vtd_dev_to_context_entry(s, pci_bus_num(vtd_as->bus), +@@ -1426,7 +1459,9 @@ static void vtd_iotlb_page_invalidate(IntelIOMMUState *s, uint16_t domain_id, + info.domain_id = domain_id; + info.addr = addr; + info.mask = ~((1 << am) - 1); ++ vtd_iommu_lock(s); + g_hash_table_foreach_remove(s->iotlb, vtd_hash_remove_by_page, &info); ++ vtd_iommu_unlock(s); + vtd_iotlb_page_invalidate_notify(s, domain_id, addr, am); + } + +@@ -2929,8 +2964,10 @@ static void vtd_init(IntelIOMMUState *s) + s->cap |= VTD_CAP_CM; + } + +- vtd_reset_context_cache(s); +- vtd_reset_iotlb(s); ++ vtd_iommu_lock(s); ++ vtd_reset_context_cache_locked(s); ++ vtd_reset_iotlb_locked(s); ++ vtd_iommu_unlock(s); + + /* Define registers with default values and bit semantics */ + vtd_define_long(s, DMAR_VER_REG, 0x10UL, 0, 0); +@@ -3070,6 +3107,7 @@ static void vtd_realize(DeviceState *dev, Error **errp) + } + + QLIST_INIT(&s->vtd_as_with_notifiers); ++ qemu_mutex_init(&s->iommu_lock); + memset(s->vtd_as_by_bus_num, 0, sizeof(s->vtd_as_by_bus_num)); + memory_region_init_io(&s->csrmem, OBJECT(s), &vtd_mem_ops, s, + "intel_iommu", DMAR_REG_SIZE); +diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h +index 032e33b..016e74b 100644 +--- a/include/hw/i386/intel_iommu.h ++++ b/include/hw/i386/intel_iommu.h +@@ -300,6 +300,12 @@ struct IntelIOMMUState { + OnOffAuto intr_eim; /* Toggle for EIM cabability */ + bool buggy_eim; /* Force buggy EIM unless eim=off */ + uint8_t aw_bits; /* Host/IOVA address width (in bits) */ ++ ++ /* ++ * Protects IOMMU states in general. Currently it protects the ++ * per-IOMMU IOTLB cache, and context entry cache in VTDAddressSpace. ++ */ ++ QemuMutex iommu_lock; + }; + + /* Find the VTD Address space associated with the given bus pointer, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-intel-iommu-introduce-vtd_page_walk_info.patch b/SOURCES/kvm-intel-iommu-introduce-vtd_page_walk_info.patch new file mode 100644 index 0000000..f7a65a9 --- /dev/null +++ b/SOURCES/kvm-intel-iommu-introduce-vtd_page_walk_info.patch @@ -0,0 +1,206 @@ +From a0ee4c7297a134808024b069d8612146e32e2322 Mon Sep 17 00:00:00 2001 +From: Peter Xu +Date: Mon, 3 Sep 2018 04:52:37 +0200 +Subject: [PATCH 22/29] intel-iommu: introduce vtd_page_walk_info + +RH-Author: Peter Xu +Message-id: <20180903045241.6456-6-peterx@redhat.com> +Patchwork-id: 82025 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 5/9] intel-iommu: introduce vtd_page_walk_info +Bugzilla: 1623859 +RH-Acked-by: Xiao Wang +RH-Acked-by: Auger Eric +RH-Acked-by: Michael S. Tsirkin + +During the recursive page walking of IOVA page tables, some stack +variables are constant variables and never changed during the whole page +walking procedure. Isolate them into a struct so that we don't need to +pass those contants down the stack every time and multiple times. + +CC: QEMU Stable +Signed-off-by: Peter Xu +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit fe215b0cbb8c1f4b4af0a64aa5c02042080dd537) +Signed-off-by: Peter Xu +Signed-off-by: Miroslav Rezanina +--- + hw/i386/intel_iommu.c | 84 +++++++++++++++++++++++++++++++-------------------- + 1 file changed, 52 insertions(+), 32 deletions(-) + +diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c +index 38ccc74..e247269 100644 +--- a/hw/i386/intel_iommu.c ++++ b/hw/i386/intel_iommu.c +@@ -748,9 +748,27 @@ static int vtd_iova_to_slpte(VTDContextEntry *ce, uint64_t iova, bool is_write, + + typedef int (*vtd_page_walk_hook)(IOMMUTLBEntry *entry, void *private); + ++/** ++ * Constant information used during page walking ++ * ++ * @hook_fn: hook func to be called when detected page ++ * @private: private data to be passed into hook func ++ * @notify_unmap: whether we should notify invalid entries ++ * @aw: maximum address width ++ */ ++typedef struct { ++ vtd_page_walk_hook hook_fn; ++ void *private; ++ bool notify_unmap; ++ uint8_t aw; ++} vtd_page_walk_info; ++ + static int vtd_page_walk_one(IOMMUTLBEntry *entry, int level, +- vtd_page_walk_hook hook_fn, void *private) ++ vtd_page_walk_info *info) + { ++ vtd_page_walk_hook hook_fn = info->hook_fn; ++ void *private = info->private; ++ + assert(hook_fn); + trace_vtd_page_walk_one(level, entry->iova, entry->translated_addr, + entry->addr_mask, entry->perm); +@@ -763,17 +781,13 @@ static int vtd_page_walk_one(IOMMUTLBEntry *entry, int level, + * @addr: base GPA addr to start the walk + * @start: IOVA range start address + * @end: IOVA range end address (start <= addr < end) +- * @hook_fn: hook func to be called when detected page +- * @private: private data to be passed into hook func + * @read: whether parent level has read permission + * @write: whether parent level has write permission +- * @notify_unmap: whether we should notify invalid entries +- * @aw: maximum address width ++ * @info: constant information for the page walk + */ + static int vtd_page_walk_level(dma_addr_t addr, uint64_t start, +- uint64_t end, vtd_page_walk_hook hook_fn, +- void *private, uint32_t level, bool read, +- bool write, bool notify_unmap, uint8_t aw) ++ uint64_t end, uint32_t level, bool read, ++ bool write, vtd_page_walk_info *info) + { + bool read_cur, write_cur, entry_valid; + uint32_t offset; +@@ -823,24 +837,24 @@ static int vtd_page_walk_level(dma_addr_t addr, uint64_t start, + + if (vtd_is_last_slpte(slpte, level)) { + /* NOTE: this is only meaningful if entry_valid == true */ +- entry.translated_addr = vtd_get_slpte_addr(slpte, aw); +- if (!entry_valid && !notify_unmap) { ++ entry.translated_addr = vtd_get_slpte_addr(slpte, info->aw); ++ if (!entry_valid && !info->notify_unmap) { + trace_vtd_page_walk_skip_perm(iova, iova_next); + goto next; + } +- ret = vtd_page_walk_one(&entry, level, hook_fn, private); ++ ret = vtd_page_walk_one(&entry, level, info); + if (ret < 0) { + return ret; + } + } else { + if (!entry_valid) { +- if (notify_unmap) { ++ if (info->notify_unmap) { + /* + * The whole entry is invalid; unmap it all. + * Translated address is meaningless, zero it. + */ + entry.translated_addr = 0x0; +- ret = vtd_page_walk_one(&entry, level, hook_fn, private); ++ ret = vtd_page_walk_one(&entry, level, info); + if (ret < 0) { + return ret; + } +@@ -849,10 +863,9 @@ static int vtd_page_walk_level(dma_addr_t addr, uint64_t start, + } + goto next; + } +- ret = vtd_page_walk_level(vtd_get_slpte_addr(slpte, aw), iova, +- MIN(iova_next, end), hook_fn, private, +- level - 1, read_cur, write_cur, +- notify_unmap, aw); ++ ret = vtd_page_walk_level(vtd_get_slpte_addr(slpte, info->aw), ++ iova, MIN(iova_next, end), level - 1, ++ read_cur, write_cur, info); + if (ret < 0) { + return ret; + } +@@ -871,28 +884,24 @@ next: + * @ce: context entry to walk upon + * @start: IOVA address to start the walk + * @end: IOVA range end address (start <= addr < end) +- * @hook_fn: the hook that to be called for each detected area +- * @private: private data for the hook function +- * @aw: maximum address width ++ * @info: page walking information struct + */ + static int vtd_page_walk(VTDContextEntry *ce, uint64_t start, uint64_t end, +- vtd_page_walk_hook hook_fn, void *private, +- bool notify_unmap, uint8_t aw) ++ vtd_page_walk_info *info) + { + dma_addr_t addr = vtd_ce_get_slpt_base(ce); + uint32_t level = vtd_ce_get_level(ce); + +- if (!vtd_iova_range_check(start, ce, aw)) { ++ if (!vtd_iova_range_check(start, ce, info->aw)) { + return -VTD_FR_ADDR_BEYOND_MGAW; + } + +- if (!vtd_iova_range_check(end, ce, aw)) { ++ if (!vtd_iova_range_check(end, ce, info->aw)) { + /* Fix end so that it reaches the maximum */ +- end = vtd_iova_limit(ce, aw); ++ end = vtd_iova_limit(ce, info->aw); + } + +- return vtd_page_walk_level(addr, start, end, hook_fn, private, +- level, true, true, notify_unmap, aw); ++ return vtd_page_walk_level(addr, start, end, level, true, true, info); + } + + /* Map a device to its corresponding domain (context-entry) */ +@@ -1449,14 +1458,19 @@ static void vtd_iotlb_page_invalidate_notify(IntelIOMMUState *s, + vtd_as->devfn, &ce); + if (!ret && domain_id == VTD_CONTEXT_ENTRY_DID(ce.hi)) { + if (vtd_as_has_map_notifier(vtd_as)) { ++ vtd_page_walk_info info = { ++ .hook_fn = vtd_page_invalidate_notify_hook, ++ .private = (void *)&vtd_as->iommu, ++ .notify_unmap = true, ++ .aw = s->aw_bits, ++ }; ++ + /* + * As long as we have MAP notifications registered in + * any of our IOMMU notifiers, we need to sync the + * shadow page table. + */ +- vtd_page_walk(&ce, addr, addr + size, +- vtd_page_invalidate_notify_hook, +- (void *)&vtd_as->iommu, true, s->aw_bits); ++ vtd_page_walk(&ce, addr, addr + size, &info); + } else { + /* + * For UNMAP-only notifiers, we don't need to walk the +@@ -2924,8 +2938,14 @@ static void vtd_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n) + ce.hi, ce.lo); + if (vtd_as_has_map_notifier(vtd_as)) { + /* This is required only for MAP typed notifiers */ +- vtd_page_walk(&ce, 0, ~0ULL, vtd_replay_hook, (void *)n, false, +- s->aw_bits); ++ vtd_page_walk_info info = { ++ .hook_fn = vtd_replay_hook, ++ .private = (void *)n, ++ .notify_unmap = false, ++ .aw = s->aw_bits, ++ }; ++ ++ vtd_page_walk(&ce, 0, ~0ULL, &info); + } + } else { + trace_vtd_replay_ce_invalid(bus_n, PCI_SLOT(vtd_as->devfn), +-- +1.8.3.1 + diff --git a/SOURCES/kvm-intel-iommu-only-do-page-walk-for-MAP-notifiers.patch b/SOURCES/kvm-intel-iommu-only-do-page-walk-for-MAP-notifiers.patch new file mode 100644 index 0000000..458e525 --- /dev/null +++ b/SOURCES/kvm-intel-iommu-only-do-page-walk-for-MAP-notifiers.patch @@ -0,0 +1,127 @@ +From b6bc2d692f4f3c41b61c0917d4709e91827c8432 Mon Sep 17 00:00:00 2001 +From: Peter Xu +Date: Mon, 3 Sep 2018 04:52:36 +0200 +Subject: [PATCH 21/29] intel-iommu: only do page walk for MAP notifiers + +RH-Author: Peter Xu +Message-id: <20180903045241.6456-5-peterx@redhat.com> +Patchwork-id: 82024 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 4/9] intel-iommu: only do page walk for MAP notifiers +Bugzilla: 1623859 +RH-Acked-by: Xiao Wang +RH-Acked-by: Auger Eric +RH-Acked-by: Michael S. Tsirkin + +For UNMAP-only IOMMU notifiers, we don't need to walk the page tables. +Fasten that procedure by skipping the page table walk. That should +boost performance for UNMAP-only notifiers like vhost. + +CC: QEMU Stable +Signed-off-by: Peter Xu +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 4f8a62a933a79094e44bc1b16b63bb23e62d67b4) +Signed-off-by: Peter Xu +Signed-off-by: Miroslav Rezanina +--- + hw/i386/intel_iommu.c | 44 ++++++++++++++++++++++++++++++++++++++----- + include/hw/i386/intel_iommu.h | 2 ++ + 2 files changed, 41 insertions(+), 5 deletions(-) + +diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c +index 8d4069d..38ccc74 100644 +--- a/hw/i386/intel_iommu.c ++++ b/hw/i386/intel_iommu.c +@@ -138,6 +138,12 @@ static inline void vtd_iommu_unlock(IntelIOMMUState *s) + qemu_mutex_unlock(&s->iommu_lock); + } + ++/* Whether the address space needs to notify new mappings */ ++static inline gboolean vtd_as_has_map_notifier(VTDAddressSpace *as) ++{ ++ return as->notifier_flags & IOMMU_NOTIFIER_MAP; ++} ++ + /* GHashTable functions */ + static gboolean vtd_uint64_equal(gconstpointer v1, gconstpointer v2) + { +@@ -1436,14 +1442,36 @@ static void vtd_iotlb_page_invalidate_notify(IntelIOMMUState *s, + VTDAddressSpace *vtd_as; + VTDContextEntry ce; + int ret; ++ hwaddr size = (1 << am) * VTD_PAGE_SIZE; + + QLIST_FOREACH(vtd_as, &(s->vtd_as_with_notifiers), next) { + ret = vtd_dev_to_context_entry(s, pci_bus_num(vtd_as->bus), + vtd_as->devfn, &ce); + if (!ret && domain_id == VTD_CONTEXT_ENTRY_DID(ce.hi)) { +- vtd_page_walk(&ce, addr, addr + (1 << am) * VTD_PAGE_SIZE, +- vtd_page_invalidate_notify_hook, +- (void *)&vtd_as->iommu, true, s->aw_bits); ++ if (vtd_as_has_map_notifier(vtd_as)) { ++ /* ++ * As long as we have MAP notifications registered in ++ * any of our IOMMU notifiers, we need to sync the ++ * shadow page table. ++ */ ++ vtd_page_walk(&ce, addr, addr + size, ++ vtd_page_invalidate_notify_hook, ++ (void *)&vtd_as->iommu, true, s->aw_bits); ++ } else { ++ /* ++ * For UNMAP-only notifiers, we don't need to walk the ++ * page tables. We just deliver the PSI down to ++ * invalidate caches. ++ */ ++ IOMMUTLBEntry entry = { ++ .target_as = &address_space_memory, ++ .iova = addr, ++ .translated_addr = 0, ++ .addr_mask = size - 1, ++ .perm = IOMMU_NONE, ++ }; ++ memory_region_notify_iommu(&vtd_as->iommu, entry); ++ } + } + } + } +@@ -2383,6 +2411,9 @@ static void vtd_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu, + exit(1); + } + ++ /* Update per-address-space notifier flags */ ++ vtd_as->notifier_flags = new; ++ + if (old == IOMMU_NOTIFIER_NONE) { + QLIST_INSERT_HEAD(&s->vtd_as_with_notifiers, vtd_as, next); + } else if (new == IOMMU_NOTIFIER_NONE) { +@@ -2891,8 +2922,11 @@ static void vtd_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n) + PCI_FUNC(vtd_as->devfn), + VTD_CONTEXT_ENTRY_DID(ce.hi), + ce.hi, ce.lo); +- vtd_page_walk(&ce, 0, ~0ULL, vtd_replay_hook, (void *)n, false, +- s->aw_bits); ++ if (vtd_as_has_map_notifier(vtd_as)) { ++ /* This is required only for MAP typed notifiers */ ++ vtd_page_walk(&ce, 0, ~0ULL, vtd_replay_hook, (void *)n, false, ++ s->aw_bits); ++ } + } else { + trace_vtd_replay_ce_invalid(bus_n, PCI_SLOT(vtd_as->devfn), + PCI_FUNC(vtd_as->devfn)); +diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h +index 016e74b..156f35e 100644 +--- a/include/hw/i386/intel_iommu.h ++++ b/include/hw/i386/intel_iommu.h +@@ -93,6 +93,8 @@ struct VTDAddressSpace { + IntelIOMMUState *iommu_state; + VTDContextCacheEntry context_cache_entry; + QLIST_ENTRY(VTDAddressSpace) next; ++ /* Superset of notifier flags that this address space has */ ++ IOMMUNotifierFlag notifier_flags; + }; + + struct VTDBus { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-intel-iommu-pass-in-address-space-when-page-walk.patch b/SOURCES/kvm-intel-iommu-pass-in-address-space-when-page-walk.patch new file mode 100644 index 0000000..1575638 --- /dev/null +++ b/SOURCES/kvm-intel-iommu-pass-in-address-space-when-page-walk.patch @@ -0,0 +1,63 @@ +From 6e4599e1863990d7f8aa409fb67ca115b99c2fdf Mon Sep 17 00:00:00 2001 +From: Peter Xu +Date: Mon, 3 Sep 2018 04:52:38 +0200 +Subject: [PATCH 23/29] intel-iommu: pass in address space when page walk + +RH-Author: Peter Xu +Message-id: <20180903045241.6456-7-peterx@redhat.com> +Patchwork-id: 82027 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 6/9] intel-iommu: pass in address space when page walk +Bugzilla: 1623859 +RH-Acked-by: Xiao Wang +RH-Acked-by: Auger Eric +RH-Acked-by: Michael S. Tsirkin + +We pass in the VTDAddressSpace too. It'll be used in the follow up +patches. + +CC: QEMU Stable +Signed-off-by: Peter Xu +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 2f764fa87d2a81812b313dd6d998e10126292653) +Signed-off-by: Peter Xu +Signed-off-by: Miroslav Rezanina +--- + hw/i386/intel_iommu.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c +index e247269..a882894 100644 +--- a/hw/i386/intel_iommu.c ++++ b/hw/i386/intel_iommu.c +@@ -754,9 +754,11 @@ typedef int (*vtd_page_walk_hook)(IOMMUTLBEntry *entry, void *private); + * @hook_fn: hook func to be called when detected page + * @private: private data to be passed into hook func + * @notify_unmap: whether we should notify invalid entries ++ * @as: VT-d address space of the device + * @aw: maximum address width + */ + typedef struct { ++ VTDAddressSpace *as; + vtd_page_walk_hook hook_fn; + void *private; + bool notify_unmap; +@@ -1463,6 +1465,7 @@ static void vtd_iotlb_page_invalidate_notify(IntelIOMMUState *s, + .private = (void *)&vtd_as->iommu, + .notify_unmap = true, + .aw = s->aw_bits, ++ .as = vtd_as, + }; + + /* +@@ -2943,6 +2946,7 @@ static void vtd_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n) + .private = (void *)n, + .notify_unmap = false, + .aw = s->aw_bits, ++ .as = vtd_as, + }; + + vtd_page_walk(&ce, 0, ~0ULL, &info); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-intel-iommu-remove-IntelIOMMUNotifierNode.patch b/SOURCES/kvm-intel-iommu-remove-IntelIOMMUNotifierNode.patch new file mode 100644 index 0000000..2bd0bd1 --- /dev/null +++ b/SOURCES/kvm-intel-iommu-remove-IntelIOMMUNotifierNode.patch @@ -0,0 +1,182 @@ +From fd9f21135b1317ddfdf70d5d749e9c2ef51e4c22 Mon Sep 17 00:00:00 2001 +From: Peter Xu +Date: Mon, 3 Sep 2018 04:52:34 +0200 +Subject: [PATCH 19/29] intel-iommu: remove IntelIOMMUNotifierNode + +RH-Author: Peter Xu +Message-id: <20180903045241.6456-3-peterx@redhat.com> +Patchwork-id: 82023 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 2/9] intel-iommu: remove IntelIOMMUNotifierNode +Bugzilla: 1623859 +RH-Acked-by: Xiao Wang +RH-Acked-by: Auger Eric +RH-Acked-by: Michael S. Tsirkin + +That is not really necessary. Removing that node struct and put the +list entry directly into VTDAddressSpace. It simplfies the code a lot. +Since at it, rename the old notifiers_list into vtd_as_with_notifiers. + +CC: QEMU Stable +Signed-off-by: Peter Xu +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit b4a4ba0d68f50f218ee3957b6638dbee32a5eeef) +Signed-off-by: Peter Xu +Signed-off-by: Miroslav Rezanina +--- + hw/i386/intel_iommu.c | 41 +++++++++++------------------------------ + include/hw/i386/intel_iommu.h | 9 ++------- + 2 files changed, 13 insertions(+), 37 deletions(-) + +diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c +index b359efd..3df9045 100644 +--- a/hw/i386/intel_iommu.c ++++ b/hw/i386/intel_iommu.c +@@ -1248,10 +1248,10 @@ static void vtd_interrupt_remap_table_setup(IntelIOMMUState *s) + + static void vtd_iommu_replay_all(IntelIOMMUState *s) + { +- IntelIOMMUNotifierNode *node; ++ VTDAddressSpace *vtd_as; + +- QLIST_FOREACH(node, &s->notifiers_list, next) { +- memory_region_iommu_replay_all(&node->vtd_as->iommu); ++ QLIST_FOREACH(vtd_as, &s->vtd_as_with_notifiers, next) { ++ memory_region_iommu_replay_all(&vtd_as->iommu); + } + } + +@@ -1372,7 +1372,6 @@ static void vtd_iotlb_global_invalidate(IntelIOMMUState *s) + + static void vtd_iotlb_domain_invalidate(IntelIOMMUState *s, uint16_t domain_id) + { +- IntelIOMMUNotifierNode *node; + VTDContextEntry ce; + VTDAddressSpace *vtd_as; + +@@ -1381,8 +1380,7 @@ static void vtd_iotlb_domain_invalidate(IntelIOMMUState *s, uint16_t domain_id) + g_hash_table_foreach_remove(s->iotlb, vtd_hash_remove_by_domain, + &domain_id); + +- QLIST_FOREACH(node, &s->notifiers_list, next) { +- vtd_as = node->vtd_as; ++ QLIST_FOREACH(vtd_as, &s->vtd_as_with_notifiers, next) { + if (!vtd_dev_to_context_entry(s, pci_bus_num(vtd_as->bus), + vtd_as->devfn, &ce) && + domain_id == VTD_CONTEXT_ENTRY_DID(ce.hi)) { +@@ -1402,12 +1400,11 @@ static void vtd_iotlb_page_invalidate_notify(IntelIOMMUState *s, + uint16_t domain_id, hwaddr addr, + uint8_t am) + { +- IntelIOMMUNotifierNode *node; ++ VTDAddressSpace *vtd_as; + VTDContextEntry ce; + int ret; + +- QLIST_FOREACH(node, &(s->notifiers_list), next) { +- VTDAddressSpace *vtd_as = node->vtd_as; ++ QLIST_FOREACH(vtd_as, &(s->vtd_as_with_notifiers), next) { + ret = vtd_dev_to_context_entry(s, pci_bus_num(vtd_as->bus), + vtd_as->devfn, &ce); + if (!ret && domain_id == VTD_CONTEXT_ENTRY_DID(ce.hi)) { +@@ -2344,8 +2341,6 @@ static void vtd_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu, + { + VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu); + IntelIOMMUState *s = vtd_as->iommu_state; +- IntelIOMMUNotifierNode *node = NULL; +- IntelIOMMUNotifierNode *next_node = NULL; + + if (!s->caching_mode && new & IOMMU_NOTIFIER_MAP) { + error_report("We need to set caching-mode=1 for intel-iommu to enable " +@@ -2354,21 +2349,9 @@ static void vtd_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu, + } + + if (old == IOMMU_NOTIFIER_NONE) { +- node = g_malloc0(sizeof(*node)); +- node->vtd_as = vtd_as; +- QLIST_INSERT_HEAD(&s->notifiers_list, node, next); +- return; +- } +- +- /* update notifier node with new flags */ +- QLIST_FOREACH_SAFE(node, &s->notifiers_list, next, next_node) { +- if (node->vtd_as == vtd_as) { +- if (new == IOMMU_NOTIFIER_NONE) { +- QLIST_REMOVE(node, next); +- g_free(node); +- } +- return; +- } ++ QLIST_INSERT_HEAD(&s->vtd_as_with_notifiers, vtd_as, next); ++ } else if (new == IOMMU_NOTIFIER_NONE) { ++ QLIST_REMOVE(vtd_as, next); + } + } + +@@ -2838,12 +2821,10 @@ static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n) + + static void vtd_address_space_unmap_all(IntelIOMMUState *s) + { +- IntelIOMMUNotifierNode *node; + VTDAddressSpace *vtd_as; + IOMMUNotifier *n; + +- QLIST_FOREACH(node, &s->notifiers_list, next) { +- vtd_as = node->vtd_as; ++ QLIST_FOREACH(vtd_as, &s->vtd_as_with_notifiers, next) { + IOMMU_NOTIFIER_FOREACH(n, &vtd_as->iommu) { + vtd_address_space_unmap(vtd_as, n); + } +@@ -3088,7 +3069,7 @@ static void vtd_realize(DeviceState *dev, Error **errp) + return; + } + +- QLIST_INIT(&s->notifiers_list); ++ QLIST_INIT(&s->vtd_as_with_notifiers); + memset(s->vtd_as_by_bus_num, 0, sizeof(s->vtd_as_by_bus_num)); + memory_region_init_io(&s->csrmem, OBJECT(s), &vtd_mem_ops, s, + "intel_iommu", DMAR_REG_SIZE); +diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h +index 45ec891..032e33b 100644 +--- a/include/hw/i386/intel_iommu.h ++++ b/include/hw/i386/intel_iommu.h +@@ -67,7 +67,6 @@ typedef union VTD_IR_TableEntry VTD_IR_TableEntry; + typedef union VTD_IR_MSIAddress VTD_IR_MSIAddress; + typedef struct VTDIrq VTDIrq; + typedef struct VTD_MSIMessage VTD_MSIMessage; +-typedef struct IntelIOMMUNotifierNode IntelIOMMUNotifierNode; + + /* Context-Entry */ + struct VTDContextEntry { +@@ -93,6 +92,7 @@ struct VTDAddressSpace { + MemoryRegion iommu_ir; /* Interrupt region: 0xfeeXXXXX */ + IntelIOMMUState *iommu_state; + VTDContextCacheEntry context_cache_entry; ++ QLIST_ENTRY(VTDAddressSpace) next; + }; + + struct VTDBus { +@@ -253,11 +253,6 @@ struct VTD_MSIMessage { + /* When IR is enabled, all MSI/MSI-X data bits should be zero */ + #define VTD_IR_MSI_DATA (0) + +-struct IntelIOMMUNotifierNode { +- VTDAddressSpace *vtd_as; +- QLIST_ENTRY(IntelIOMMUNotifierNode) next; +-}; +- + /* The iommu (DMAR) device state struct */ + struct IntelIOMMUState { + X86IOMMUState x86_iommu; +@@ -295,7 +290,7 @@ struct IntelIOMMUState { + GHashTable *vtd_as_by_busptr; /* VTDBus objects indexed by PCIBus* reference */ + VTDBus *vtd_as_by_bus_num[VTD_PCI_BUS_MAX]; /* VTDBus objects indexed by bus number */ + /* list of registered notifiers */ +- QLIST_HEAD(, IntelIOMMUNotifierNode) notifiers_list; ++ QLIST_HEAD(, VTDAddressSpace) vtd_as_with_notifiers; + + /* interrupt remapping */ + bool intr_enabled; /* Whether guest enabled IR */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-intel-iommu-rework-the-page-walk-logic.patch b/SOURCES/kvm-intel-iommu-rework-the-page-walk-logic.patch new file mode 100644 index 0000000..3f8f80a --- /dev/null +++ b/SOURCES/kvm-intel-iommu-rework-the-page-walk-logic.patch @@ -0,0 +1,401 @@ +From 0b6a29f743e4dcbf340d5abe0e7e230591b7d5d3 Mon Sep 17 00:00:00 2001 +From: Peter Xu +Date: Mon, 3 Sep 2018 04:52:41 +0200 +Subject: [PATCH 26/29] intel-iommu: rework the page walk logic + +RH-Author: Peter Xu +Message-id: <20180903045241.6456-10-peterx@redhat.com> +Patchwork-id: 82029 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 9/9] intel-iommu: rework the page walk logic +Bugzilla: 1623859 +RH-Acked-by: Xiao Wang +RH-Acked-by: Auger Eric +RH-Acked-by: Michael S. Tsirkin + +This patch fixes a potential small window that the DMA page table might +be incomplete or invalid when the guest sends domain/context +invalidations to a device. This can cause random DMA errors for +assigned devices. + +This is a major change to the VT-d shadow page walking logic. It +includes but is not limited to: + +- For each VTDAddressSpace, now we maintain what IOVA ranges we have + mapped and what we have not. With that information, now we only send + MAP or UNMAP when necessary. Say, we don't send MAP notifies if we + know we have already mapped the range, meanwhile we don't send UNMAP + notifies if we know we never mapped the range at all. + +- Introduce vtd_sync_shadow_page_table[_range] APIs so that we can call + in any places to resync the shadow page table for a device. + +- When we receive domain/context invalidation, we should not really run + the replay logic, instead we use the new sync shadow page table API to + resync the whole shadow page table without unmapping the whole + region. After this change, we'll only do the page walk once for each + domain invalidations (before this, it can be multiple, depending on + number of notifiers per address space). + +While at it, the page walking logic is also refactored to be simpler. + +CC: QEMU Stable +Reported-by: Jintack Lim +Tested-by: Jintack Lim +Signed-off-by: Peter Xu +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 63b88968f139b6a77f2f81e6f1eedf70c0170a85) +Signed-off-by: Peter Xu +Signed-off-by: Miroslav Rezanina +--- + hw/i386/intel_iommu.c | 213 ++++++++++++++++++++++++++++++------------ + hw/i386/trace-events | 3 +- + include/hw/i386/intel_iommu.h | 2 + + 3 files changed, 159 insertions(+), 59 deletions(-) + +diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c +index 61bb3d3..b5a09b7 100644 +--- a/hw/i386/intel_iommu.c ++++ b/hw/i386/intel_iommu.c +@@ -769,10 +769,77 @@ typedef struct { + + static int vtd_page_walk_one(IOMMUTLBEntry *entry, vtd_page_walk_info *info) + { ++ VTDAddressSpace *as = info->as; + vtd_page_walk_hook hook_fn = info->hook_fn; + void *private = info->private; ++ DMAMap target = { ++ .iova = entry->iova, ++ .size = entry->addr_mask, ++ .translated_addr = entry->translated_addr, ++ .perm = entry->perm, ++ }; ++ DMAMap *mapped = iova_tree_find(as->iova_tree, &target); ++ ++ if (entry->perm == IOMMU_NONE && !info->notify_unmap) { ++ trace_vtd_page_walk_one_skip_unmap(entry->iova, entry->addr_mask); ++ return 0; ++ } + + assert(hook_fn); ++ ++ /* Update local IOVA mapped ranges */ ++ if (entry->perm) { ++ if (mapped) { ++ /* If it's exactly the same translation, skip */ ++ if (!memcmp(mapped, &target, sizeof(target))) { ++ trace_vtd_page_walk_one_skip_map(entry->iova, entry->addr_mask, ++ entry->translated_addr); ++ return 0; ++ } else { ++ /* ++ * Translation changed. Normally this should not ++ * happen, but it can happen when with buggy guest ++ * OSes. Note that there will be a small window that ++ * we don't have map at all. But that's the best ++ * effort we can do. The ideal way to emulate this is ++ * atomically modify the PTE to follow what has ++ * changed, but we can't. One example is that vfio ++ * driver only has VFIO_IOMMU_[UN]MAP_DMA but no ++ * interface to modify a mapping (meanwhile it seems ++ * meaningless to even provide one). Anyway, let's ++ * mark this as a TODO in case one day we'll have ++ * a better solution. ++ */ ++ IOMMUAccessFlags cache_perm = entry->perm; ++ int ret; ++ ++ /* Emulate an UNMAP */ ++ entry->perm = IOMMU_NONE; ++ trace_vtd_page_walk_one(info->domain_id, ++ entry->iova, ++ entry->translated_addr, ++ entry->addr_mask, ++ entry->perm); ++ ret = hook_fn(entry, private); ++ if (ret) { ++ return ret; ++ } ++ /* Drop any existing mapping */ ++ iova_tree_remove(as->iova_tree, &target); ++ /* Recover the correct permission */ ++ entry->perm = cache_perm; ++ } ++ } ++ iova_tree_insert(as->iova_tree, &target); ++ } else { ++ if (!mapped) { ++ /* Skip since we didn't map this range at all */ ++ trace_vtd_page_walk_one_skip_unmap(entry->iova, entry->addr_mask); ++ return 0; ++ } ++ iova_tree_remove(as->iova_tree, &target); ++ } ++ + trace_vtd_page_walk_one(info->domain_id, entry->iova, + entry->translated_addr, entry->addr_mask, + entry->perm); +@@ -834,45 +901,34 @@ static int vtd_page_walk_level(dma_addr_t addr, uint64_t start, + */ + entry_valid = read_cur | write_cur; + +- entry.target_as = &address_space_memory; +- entry.iova = iova & subpage_mask; +- entry.perm = IOMMU_ACCESS_FLAG(read_cur, write_cur); +- entry.addr_mask = ~subpage_mask; +- +- if (vtd_is_last_slpte(slpte, level)) { +- /* NOTE: this is only meaningful if entry_valid == true */ +- entry.translated_addr = vtd_get_slpte_addr(slpte, info->aw); +- if (!entry_valid && !info->notify_unmap) { +- trace_vtd_page_walk_skip_perm(iova, iova_next); +- goto next; +- } +- ret = vtd_page_walk_one(&entry, info); +- if (ret < 0) { +- return ret; +- } +- } else { +- if (!entry_valid) { +- if (info->notify_unmap) { +- /* +- * The whole entry is invalid; unmap it all. +- * Translated address is meaningless, zero it. +- */ +- entry.translated_addr = 0x0; +- ret = vtd_page_walk_one(&entry, info); +- if (ret < 0) { +- return ret; +- } +- } else { +- trace_vtd_page_walk_skip_perm(iova, iova_next); +- } +- goto next; +- } ++ if (!vtd_is_last_slpte(slpte, level) && entry_valid) { ++ /* ++ * This is a valid PDE (or even bigger than PDE). We need ++ * to walk one further level. ++ */ + ret = vtd_page_walk_level(vtd_get_slpte_addr(slpte, info->aw), + iova, MIN(iova_next, end), level - 1, + read_cur, write_cur, info); +- if (ret < 0) { +- return ret; +- } ++ } else { ++ /* ++ * This means we are either: ++ * ++ * (1) the real page entry (either 4K page, or huge page) ++ * (2) the whole range is invalid ++ * ++ * In either case, we send an IOTLB notification down. ++ */ ++ entry.target_as = &address_space_memory; ++ entry.iova = iova & subpage_mask; ++ entry.perm = IOMMU_ACCESS_FLAG(read_cur, write_cur); ++ entry.addr_mask = ~subpage_mask; ++ /* NOTE: this is only meaningful if entry_valid == true */ ++ entry.translated_addr = vtd_get_slpte_addr(slpte, info->aw); ++ ret = vtd_page_walk_one(&entry, info); ++ } ++ ++ if (ret < 0) { ++ return ret; + } + + next: +@@ -964,6 +1020,58 @@ static int vtd_dev_to_context_entry(IntelIOMMUState *s, uint8_t bus_num, + return 0; + } + ++static int vtd_sync_shadow_page_hook(IOMMUTLBEntry *entry, ++ void *private) ++{ ++ memory_region_notify_iommu((IOMMUMemoryRegion *)private, *entry); ++ return 0; ++} ++ ++/* If context entry is NULL, we'll try to fetch it on our own. */ ++static int vtd_sync_shadow_page_table_range(VTDAddressSpace *vtd_as, ++ VTDContextEntry *ce, ++ hwaddr addr, hwaddr size) ++{ ++ IntelIOMMUState *s = vtd_as->iommu_state; ++ vtd_page_walk_info info = { ++ .hook_fn = vtd_sync_shadow_page_hook, ++ .private = (void *)&vtd_as->iommu, ++ .notify_unmap = true, ++ .aw = s->aw_bits, ++ .as = vtd_as, ++ }; ++ VTDContextEntry ce_cache; ++ int ret; ++ ++ if (ce) { ++ /* If the caller provided context entry, use it */ ++ ce_cache = *ce; ++ } else { ++ /* If the caller didn't provide ce, try to fetch */ ++ ret = vtd_dev_to_context_entry(s, pci_bus_num(vtd_as->bus), ++ vtd_as->devfn, &ce_cache); ++ if (ret) { ++ /* ++ * This should not really happen, but in case it happens, ++ * we just skip the sync for this time. After all we even ++ * don't have the root table pointer! ++ */ ++ trace_vtd_err("Detected invalid context entry when " ++ "trying to sync shadow page table"); ++ return 0; ++ } ++ } ++ ++ info.domain_id = VTD_CONTEXT_ENTRY_DID(ce_cache.hi); ++ ++ return vtd_page_walk(&ce_cache, addr, addr + size, &info); ++} ++ ++static int vtd_sync_shadow_page_table(VTDAddressSpace *vtd_as) ++{ ++ return vtd_sync_shadow_page_table_range(vtd_as, NULL, 0, UINT64_MAX); ++} ++ + /* + * Fetch translation type for specific device. Returns <0 if error + * happens, otherwise return the shifted type to check against +@@ -1296,7 +1404,7 @@ static void vtd_iommu_replay_all(IntelIOMMUState *s) + VTDAddressSpace *vtd_as; + + QLIST_FOREACH(vtd_as, &s->vtd_as_with_notifiers, next) { +- memory_region_iommu_replay_all(&vtd_as->iommu); ++ vtd_sync_shadow_page_table(vtd_as); + } + } + +@@ -1371,14 +1479,13 @@ static void vtd_context_device_invalidate(IntelIOMMUState *s, + vtd_switch_address_space(vtd_as); + /* + * So a device is moving out of (or moving into) a +- * domain, a replay() suites here to notify all the +- * IOMMU_NOTIFIER_MAP registers about this change. ++ * domain, resync the shadow page table. + * This won't bring bad even if we have no such + * notifier registered - the IOMMU notification + * framework will skip MAP notifications if that + * happened. + */ +- memory_region_iommu_replay_all(&vtd_as->iommu); ++ vtd_sync_shadow_page_table(vtd_as); + } + } + } +@@ -1436,18 +1543,11 @@ static void vtd_iotlb_domain_invalidate(IntelIOMMUState *s, uint16_t domain_id) + if (!vtd_dev_to_context_entry(s, pci_bus_num(vtd_as->bus), + vtd_as->devfn, &ce) && + domain_id == VTD_CONTEXT_ENTRY_DID(ce.hi)) { +- memory_region_iommu_replay_all(&vtd_as->iommu); ++ vtd_sync_shadow_page_table(vtd_as); + } + } + } + +-static int vtd_page_invalidate_notify_hook(IOMMUTLBEntry *entry, +- void *private) +-{ +- memory_region_notify_iommu((IOMMUMemoryRegion *)private, *entry); +- return 0; +-} +- + static void vtd_iotlb_page_invalidate_notify(IntelIOMMUState *s, + uint16_t domain_id, hwaddr addr, + uint8_t am) +@@ -1462,21 +1562,12 @@ static void vtd_iotlb_page_invalidate_notify(IntelIOMMUState *s, + vtd_as->devfn, &ce); + if (!ret && domain_id == VTD_CONTEXT_ENTRY_DID(ce.hi)) { + if (vtd_as_has_map_notifier(vtd_as)) { +- vtd_page_walk_info info = { +- .hook_fn = vtd_page_invalidate_notify_hook, +- .private = (void *)&vtd_as->iommu, +- .notify_unmap = true, +- .aw = s->aw_bits, +- .as = vtd_as, +- .domain_id = domain_id, +- }; +- + /* + * As long as we have MAP notifications registered in + * any of our IOMMU notifiers, we need to sync the + * shadow page table. + */ +- vtd_page_walk(&ce, addr, addr + size, &info); ++ vtd_sync_shadow_page_table_range(vtd_as, &ce, addr, size); + } else { + /* + * For UNMAP-only notifiers, we don't need to walk the +@@ -2806,6 +2897,7 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn) + vtd_dev_as->devfn = (uint8_t)devfn; + vtd_dev_as->iommu_state = s; + vtd_dev_as->context_cache_entry.context_cache_gen = 0; ++ vtd_dev_as->iova_tree = iova_tree_new(); + + /* + * Memory region relationships looks like (Address range shows +@@ -2858,6 +2950,7 @@ static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n) + hwaddr start = n->start; + hwaddr end = n->end; + IntelIOMMUState *s = as->iommu_state; ++ DMAMap map; + + /* + * Note: all the codes in this function has a assumption that IOVA +@@ -2902,6 +2995,10 @@ static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n) + VTD_PCI_FUNC(as->devfn), + entry.iova, size); + ++ map.iova = entry.iova; ++ map.size = entry.addr_mask; ++ iova_tree_remove(as->iova_tree, &map); ++ + memory_region_notify_one(n, &entry); + } + +diff --git a/hw/i386/trace-events b/hw/i386/trace-events +index ca23ba9..e14d06e 100644 +--- a/hw/i386/trace-events ++++ b/hw/i386/trace-events +@@ -40,8 +40,9 @@ vtd_replay_ce_valid(uint8_t bus, uint8_t dev, uint8_t fn, uint16_t domain, uint6 + vtd_replay_ce_invalid(uint8_t bus, uint8_t dev, uint8_t fn) "replay invalid context device %02"PRIx8":%02"PRIx8".%02"PRIx8 + vtd_page_walk_level(uint64_t addr, uint32_t level, uint64_t start, uint64_t end) "walk (base=0x%"PRIx64", level=%"PRIu32") iova range 0x%"PRIx64" - 0x%"PRIx64 + vtd_page_walk_one(uint16_t domain, uint64_t iova, uint64_t gpa, uint64_t mask, int perm) "domain 0x%"PRIu16" iova 0x%"PRIx64" -> gpa 0x%"PRIx64" mask 0x%"PRIx64" perm %d" ++vtd_page_walk_one_skip_map(uint64_t iova, uint64_t mask, uint64_t translated) "iova 0x%"PRIx64" mask 0x%"PRIx64" translated 0x%"PRIx64 ++vtd_page_walk_one_skip_unmap(uint64_t iova, uint64_t mask) "iova 0x%"PRIx64" mask 0x%"PRIx64 + vtd_page_walk_skip_read(uint64_t iova, uint64_t next) "Page walk skip iova 0x%"PRIx64" - 0x%"PRIx64" due to unable to read" +-vtd_page_walk_skip_perm(uint64_t iova, uint64_t next) "Page walk skip iova 0x%"PRIx64" - 0x%"PRIx64" due to perm empty" + vtd_page_walk_skip_reserve(uint64_t iova, uint64_t next) "Page walk skip iova 0x%"PRIx64" - 0x%"PRIx64" due to rsrv set" + vtd_switch_address_space(uint8_t bus, uint8_t slot, uint8_t fn, bool on) "Device %02x:%02x.%x switching address space (iommu enabled=%d)" + vtd_as_unmap_whole(uint8_t bus, uint8_t slot, uint8_t fn, uint64_t iova, uint64_t size) "Device %02x:%02x.%x start 0x%"PRIx64" size 0x%"PRIx64 +diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h +index 156f35e..fbfedcb 100644 +--- a/include/hw/i386/intel_iommu.h ++++ b/include/hw/i386/intel_iommu.h +@@ -27,6 +27,7 @@ + #include "hw/i386/ioapic.h" + #include "hw/pci/msi.h" + #include "hw/sysbus.h" ++#include "qemu/iova-tree.h" + + #define TYPE_INTEL_IOMMU_DEVICE "intel-iommu" + #define INTEL_IOMMU_DEVICE(obj) \ +@@ -95,6 +96,7 @@ struct VTDAddressSpace { + QLIST_ENTRY(VTDAddressSpace) next; + /* Superset of notifier flags that this address space has */ + IOMMUNotifierFlag notifier_flags; ++ IOVATree *iova_tree; /* Traces mapped IOVA ranges */ + }; + + struct VTDBus { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-intel-iommu-send-PSI-always-even-if-across-PDEs.patch b/SOURCES/kvm-intel-iommu-send-PSI-always-even-if-across-PDEs.patch new file mode 100644 index 0000000..f668ad1 --- /dev/null +++ b/SOURCES/kvm-intel-iommu-send-PSI-always-even-if-across-PDEs.patch @@ -0,0 +1,131 @@ +From db590f2a02907a6762edd0877b32e79405ed4932 Mon Sep 17 00:00:00 2001 +From: Peter Xu +Date: Mon, 3 Sep 2018 04:52:33 +0200 +Subject: [PATCH 18/29] intel-iommu: send PSI always even if across PDEs + +RH-Author: Peter Xu +Message-id: <20180903045241.6456-2-peterx@redhat.com> +Patchwork-id: 82021 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/9] intel-iommu: send PSI always even if across PDEs +Bugzilla: 1623859 +RH-Acked-by: Xiao Wang +RH-Acked-by: Auger Eric +RH-Acked-by: Michael S. Tsirkin + +SECURITY IMPLICATION: without this patch, any guest with both assigned +device and a vIOMMU might encounter stale IO page mappings even if guest +has already unmapped the page, which may lead to guest memory +corruption. The stale mappings will only be limited to the guest's own +memory range, so it should not affect the host memory or other guests on +the host. + +During IOVA page table walking, there is a special case when the PSI +covers one whole PDE (Page Directory Entry, which contains 512 Page +Table Entries) or more. In the past, we skip that entry and we don't +notify the IOMMU notifiers. This is not correct. We should send UNMAP +notification to registered UNMAP notifiers in this case. + +For UNMAP only notifiers, this might cause IOTLBs cached in the devices +even if they were already invalid. For MAP/UNMAP notifiers like +vfio-pci, this will cause stale page mappings. + +This special case doesn't trigger often, but it is very easy to be +triggered by nested device assignments, since in that case we'll +possibly map the whole L2 guest RAM region into the device's IOVA +address space (several GBs at least), which is far bigger than normal +kernel driver usages of the device (tens of MBs normally). + +Without this patch applied to L1 QEMU, nested device assignment to L2 +guests will dump some errors like: + +qemu-system-x86_64: VFIO_MAP_DMA: -17 +qemu-system-x86_64: vfio_dma_map(0x557305420c30, 0xad000, 0x1000, + 0x7f89a920d000) = -17 (File exists) + +CC: QEMU Stable +Acked-by: Jason Wang +[peterx: rewrite the commit message] +Signed-off-by: Peter Xu +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 36d2d52bdb45f5b753a61fdaf0fe7891f1f5b61d) +Signed-off-by: Peter Xu + +Signed-off-by: Miroslav Rezanina +--- + hw/i386/intel_iommu.c | 42 ++++++++++++++++++++++++++++++------------ + 1 file changed, 30 insertions(+), 12 deletions(-) + +diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c +index fb31de9..b359efd 100644 +--- a/hw/i386/intel_iommu.c ++++ b/hw/i386/intel_iommu.c +@@ -722,6 +722,15 @@ static int vtd_iova_to_slpte(VTDContextEntry *ce, uint64_t iova, bool is_write, + + typedef int (*vtd_page_walk_hook)(IOMMUTLBEntry *entry, void *private); + ++static int vtd_page_walk_one(IOMMUTLBEntry *entry, int level, ++ vtd_page_walk_hook hook_fn, void *private) ++{ ++ assert(hook_fn); ++ trace_vtd_page_walk_one(level, entry->iova, entry->translated_addr, ++ entry->addr_mask, entry->perm); ++ return hook_fn(entry, private); ++} ++ + /** + * vtd_page_walk_level - walk over specific level for IOVA range + * +@@ -781,28 +790,37 @@ static int vtd_page_walk_level(dma_addr_t addr, uint64_t start, + */ + entry_valid = read_cur | write_cur; + ++ entry.target_as = &address_space_memory; ++ entry.iova = iova & subpage_mask; ++ entry.perm = IOMMU_ACCESS_FLAG(read_cur, write_cur); ++ entry.addr_mask = ~subpage_mask; ++ + if (vtd_is_last_slpte(slpte, level)) { +- entry.target_as = &address_space_memory; +- entry.iova = iova & subpage_mask; + /* NOTE: this is only meaningful if entry_valid == true */ + entry.translated_addr = vtd_get_slpte_addr(slpte, aw); +- entry.addr_mask = ~subpage_mask; +- entry.perm = IOMMU_ACCESS_FLAG(read_cur, write_cur); + if (!entry_valid && !notify_unmap) { + trace_vtd_page_walk_skip_perm(iova, iova_next); + goto next; + } +- trace_vtd_page_walk_one(level, entry.iova, entry.translated_addr, +- entry.addr_mask, entry.perm); +- if (hook_fn) { +- ret = hook_fn(&entry, private); +- if (ret < 0) { +- return ret; +- } ++ ret = vtd_page_walk_one(&entry, level, hook_fn, private); ++ if (ret < 0) { ++ return ret; + } + } else { + if (!entry_valid) { +- trace_vtd_page_walk_skip_perm(iova, iova_next); ++ if (notify_unmap) { ++ /* ++ * The whole entry is invalid; unmap it all. ++ * Translated address is meaningless, zero it. ++ */ ++ entry.translated_addr = 0x0; ++ ret = vtd_page_walk_one(&entry, level, hook_fn, private); ++ if (ret < 0) { ++ return ret; ++ } ++ } else { ++ trace_vtd_page_walk_skip_perm(iova, iova_next); ++ } + goto next; + } + ret = vtd_page_walk_level(vtd_get_slpte_addr(slpte, aw), iova, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-intel-iommu-trace-domain-id-during-page-walk.patch b/SOURCES/kvm-intel-iommu-trace-domain-id-during-page-walk.patch new file mode 100644 index 0000000..141ecec --- /dev/null +++ b/SOURCES/kvm-intel-iommu-trace-domain-id-during-page-walk.patch @@ -0,0 +1,119 @@ +From 2511801028d31c9a6cee77d8a978d2642b82e0df Mon Sep 17 00:00:00 2001 +From: Peter Xu +Date: Mon, 3 Sep 2018 04:52:39 +0200 +Subject: [PATCH 24/29] intel-iommu: trace domain id during page walk + +RH-Author: Peter Xu +Message-id: <20180903045241.6456-8-peterx@redhat.com> +Patchwork-id: 82028 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 7/9] intel-iommu: trace domain id during page walk +Bugzilla: 1623859 +RH-Acked-by: Xiao Wang +RH-Acked-by: Auger Eric +RH-Acked-by: Michael S. Tsirkin + +This patch only modifies the trace points. + +Previously we were tracing page walk levels. They are redundant since +we have page mask (size) already. Now we trace something much more +useful which is the domain ID of the page walking. That can be very +useful when we trace more than one devices on the same system, so that +we can know which map is for which domain. + +CC: QEMU Stable +Signed-off-by: Peter Xu +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit d118c06ebbee2d23ddf873cae4a809311aa61310) +Signed-off-by: Peter Xu +Signed-off-by: Miroslav Rezanina +--- + hw/i386/intel_iommu.c | 16 ++++++++++------ + hw/i386/trace-events | 2 +- + 2 files changed, 11 insertions(+), 7 deletions(-) + +diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c +index a882894..61bb3d3 100644 +--- a/hw/i386/intel_iommu.c ++++ b/hw/i386/intel_iommu.c +@@ -756,6 +756,7 @@ typedef int (*vtd_page_walk_hook)(IOMMUTLBEntry *entry, void *private); + * @notify_unmap: whether we should notify invalid entries + * @as: VT-d address space of the device + * @aw: maximum address width ++ * @domain: domain ID of the page walk + */ + typedef struct { + VTDAddressSpace *as; +@@ -763,17 +764,18 @@ typedef struct { + void *private; + bool notify_unmap; + uint8_t aw; ++ uint16_t domain_id; + } vtd_page_walk_info; + +-static int vtd_page_walk_one(IOMMUTLBEntry *entry, int level, +- vtd_page_walk_info *info) ++static int vtd_page_walk_one(IOMMUTLBEntry *entry, vtd_page_walk_info *info) + { + vtd_page_walk_hook hook_fn = info->hook_fn; + void *private = info->private; + + assert(hook_fn); +- trace_vtd_page_walk_one(level, entry->iova, entry->translated_addr, +- entry->addr_mask, entry->perm); ++ trace_vtd_page_walk_one(info->domain_id, entry->iova, ++ entry->translated_addr, entry->addr_mask, ++ entry->perm); + return hook_fn(entry, private); + } + +@@ -844,7 +846,7 @@ static int vtd_page_walk_level(dma_addr_t addr, uint64_t start, + trace_vtd_page_walk_skip_perm(iova, iova_next); + goto next; + } +- ret = vtd_page_walk_one(&entry, level, info); ++ ret = vtd_page_walk_one(&entry, info); + if (ret < 0) { + return ret; + } +@@ -856,7 +858,7 @@ static int vtd_page_walk_level(dma_addr_t addr, uint64_t start, + * Translated address is meaningless, zero it. + */ + entry.translated_addr = 0x0; +- ret = vtd_page_walk_one(&entry, level, info); ++ ret = vtd_page_walk_one(&entry, info); + if (ret < 0) { + return ret; + } +@@ -1466,6 +1468,7 @@ static void vtd_iotlb_page_invalidate_notify(IntelIOMMUState *s, + .notify_unmap = true, + .aw = s->aw_bits, + .as = vtd_as, ++ .domain_id = domain_id, + }; + + /* +@@ -2947,6 +2950,7 @@ static void vtd_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n) + .notify_unmap = false, + .aw = s->aw_bits, + .as = vtd_as, ++ .domain_id = VTD_CONTEXT_ENTRY_DID(ce.hi), + }; + + vtd_page_walk(&ce, 0, ~0ULL, &info); +diff --git a/hw/i386/trace-events b/hw/i386/trace-events +index 22d4464..ca23ba9 100644 +--- a/hw/i386/trace-events ++++ b/hw/i386/trace-events +@@ -39,7 +39,7 @@ vtd_fault_disabled(void) "Fault processing disabled for context entry" + vtd_replay_ce_valid(uint8_t bus, uint8_t dev, uint8_t fn, uint16_t domain, uint64_t hi, uint64_t lo) "replay valid context device %02"PRIx8":%02"PRIx8".%02"PRIx8" domain 0x%"PRIx16" hi 0x%"PRIx64" lo 0x%"PRIx64 + vtd_replay_ce_invalid(uint8_t bus, uint8_t dev, uint8_t fn) "replay invalid context device %02"PRIx8":%02"PRIx8".%02"PRIx8 + vtd_page_walk_level(uint64_t addr, uint32_t level, uint64_t start, uint64_t end) "walk (base=0x%"PRIx64", level=%"PRIu32") iova range 0x%"PRIx64" - 0x%"PRIx64 +-vtd_page_walk_one(uint32_t level, uint64_t iova, uint64_t gpa, uint64_t mask, int perm) "detected page level 0x%"PRIx32" iova 0x%"PRIx64" -> gpa 0x%"PRIx64" mask 0x%"PRIx64" perm %d" ++vtd_page_walk_one(uint16_t domain, uint64_t iova, uint64_t gpa, uint64_t mask, int perm) "domain 0x%"PRIu16" iova 0x%"PRIx64" -> gpa 0x%"PRIx64" mask 0x%"PRIx64" perm %d" + vtd_page_walk_skip_read(uint64_t iova, uint64_t next) "Page walk skip iova 0x%"PRIx64" - 0x%"PRIx64" due to unable to read" + vtd_page_walk_skip_perm(uint64_t iova, uint64_t next) "Page walk skip iova 0x%"PRIx64" - 0x%"PRIx64" due to perm empty" + vtd_page_walk_skip_reserve(uint64_t iova, uint64_t next) "Page walk skip iova 0x%"PRIx64" - 0x%"PRIx64" due to rsrv set" +-- +1.8.3.1 + diff --git a/SOURCES/kvm-intel_iommu-fix-missing-BQL-in-pt-fast-path.patch b/SOURCES/kvm-intel_iommu-fix-missing-BQL-in-pt-fast-path.patch deleted file mode 100644 index f5b6ed5..0000000 --- a/SOURCES/kvm-intel_iommu-fix-missing-BQL-in-pt-fast-path.patch +++ /dev/null @@ -1,74 +0,0 @@ -From f2fb460ba2b9c5547f8bcf4d7542a5e17bbe09bd Mon Sep 17 00:00:00 2001 -From: Peter Xu -Date: Mon, 9 Oct 2017 06:51:32 +0200 -Subject: [PATCH 05/69] intel_iommu: fix missing BQL in pt fast path - -RH-Author: Peter Xu -Message-id: <20171009065132.5597-2-peterx@redhat.com> -Patchwork-id: 76929 -O-Subject: [RHEV-7.5 qemu-kvm-rhev PATCH 1/1] intel_iommu: fix missing BQL in pt fast path -Bugzilla: 1449067 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Thomas Huth - -In vtd_switch_address_space() we did the memory region switch, however -it's possible that the caller of it has not taken the BQL at all. Make -sure we have it. - -CC: Paolo Bonzini -CC: Jason Wang -CC: Michael S. Tsirkin -Signed-off-by: Peter Xu -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 66a4a0318e6b9539505491e4576fb93a708095d8) -Signed-off-by: Peter Xu -Signed-off-by: Miroslav Rezanina ---- - hw/i386/intel_iommu.c | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - -diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c -index a7bf87a..3a5bb0b 100644 ---- a/hw/i386/intel_iommu.c -+++ b/hw/i386/intel_iommu.c -@@ -957,6 +957,8 @@ static bool vtd_dev_pt_enabled(VTDAddressSpace *as) - static bool vtd_switch_address_space(VTDAddressSpace *as) - { - bool use_iommu; -+ /* Whether we need to take the BQL on our own */ -+ bool take_bql = !qemu_mutex_iothread_locked(); - - assert(as); - -@@ -967,6 +969,15 @@ static bool vtd_switch_address_space(VTDAddressSpace *as) - VTD_PCI_FUNC(as->devfn), - use_iommu); - -+ /* -+ * It's possible that we reach here without BQL, e.g., when called -+ * from vtd_pt_enable_fast_path(). However the memory APIs need -+ * it. We'd better make sure we have had it already, or, take it. -+ */ -+ if (take_bql) { -+ qemu_mutex_lock_iothread(); -+ } -+ - /* Turn off first then on the other */ - if (use_iommu) { - memory_region_set_enabled(&as->sys_alias, false); -@@ -976,6 +987,10 @@ static bool vtd_switch_address_space(VTDAddressSpace *as) - memory_region_set_enabled(&as->sys_alias, true); - } - -+ if (take_bql) { -+ qemu_mutex_unlock_iothread(); -+ } -+ - return use_iommu; - } - --- -1.8.3.1 - diff --git a/SOURCES/kvm-io-Add-missing-GCC_FMT_ATTR-fix-Werror-suggest-attri.patch b/SOURCES/kvm-io-Add-missing-GCC_FMT_ATTR-fix-Werror-suggest-attri.patch deleted file mode 100644 index f880743..0000000 --- a/SOURCES/kvm-io-Add-missing-GCC_FMT_ATTR-fix-Werror-suggest-attri.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 14a39ceeb99060eae4088513e0e81f5946c442fd Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Wed, 20 Dec 2017 17:57:02 +0100 -Subject: [PATCH 22/42] io: Add missing GCC_FMT_ATTR (fix - -Werror=suggest-attribute=format) -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Daniel P. Berrange -Message-id: <20171220175702.29663-21-berrange@redhat.com> -Patchwork-id: 78473 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 20/20] io: Add missing GCC_FMT_ATTR (fix -Werror=suggest-attribute=format) -Bugzilla: 1518649 -RH-Acked-by: John Snow -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -From: Stefan Weil - -This fixes a compiler warning: - -/qemu/io/channel-websock.c:163:5: error: - function might be possible candidate for ‘gnu_printf’ format attribute - [-Werror=suggest-attribute=format] - -Signed-off-by: Stefan Weil -Acked-by: Daniel P. Berrange -Signed-off-by: Michael Tokarev -(cherry picked from commit 52aa5644e8e89ebfc3b1d0abdb7cc502ce9db599) -Signed-off-by: Miroslav Rezanina ---- - io/channel-websock.c | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/io/channel-websock.c b/io/channel-websock.c -index df2c3a9..87ebdeb 100644 ---- a/io/channel-websock.c -+++ b/io/channel-websock.c -@@ -152,9 +152,10 @@ enum { - QIO_CHANNEL_WEBSOCK_OPCODE_PONG = 0xA - }; - --static void qio_channel_websock_handshake_send_res(QIOChannelWebsock *ioc, -- const char *resmsg, -- ...) -+static void GCC_FMT_ATTR(2, 3) -+qio_channel_websock_handshake_send_res(QIOChannelWebsock *ioc, -+ const char *resmsg, -+ ...) - { - va_list vargs; - char *response; --- -1.8.3.1 - diff --git a/SOURCES/kvm-io-Add-support-for-fragmented-websocket-binary-frame.patch b/SOURCES/kvm-io-Add-support-for-fragmented-websocket-binary-frame.patch deleted file mode 100644 index 0a12afa..0000000 --- a/SOURCES/kvm-io-Add-support-for-fragmented-websocket-binary-frame.patch +++ /dev/null @@ -1,95 +0,0 @@ -From 6b05946c92a9fee7398d948be3505a294d27f76b Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Wed, 20 Dec 2017 17:56:48 +0100 -Subject: [PATCH 08/42] io: Add support for fragmented websocket binary frames - -RH-Author: Daniel P. Berrange -Message-id: <20171220175702.29663-7-berrange@redhat.com> -Patchwork-id: 78461 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 06/20] io: Add support for fragmented websocket binary frames -Bugzilla: 1518649 -RH-Acked-by: John Snow -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -From: Brandon Carpenter - -Allows fragmented binary frames by saving the previous opcode. Handles -the case where an intermediary (i.e., web proxy) fragments frames -originally sent unfragmented by the client. - -Signed-off-by: Brandon Carpenter -Signed-off-by: Daniel P. Berrange -(cherry picked from commit ff1300e626949fa9850b0f91dc5e8c2cb45b6a88) -Signed-off-by: Miroslav Rezanina ---- - include/io/channel-websock.h | 1 + - io/channel-websock.c | 26 ++++++++++++++++++-------- - 2 files changed, 19 insertions(+), 8 deletions(-) - -diff --git a/include/io/channel-websock.h b/include/io/channel-websock.h -index 3c9ff84..7c89655 100644 ---- a/include/io/channel-websock.h -+++ b/include/io/channel-websock.h -@@ -65,6 +65,7 @@ struct QIOChannelWebsock { - guint io_tag; - Error *io_err; - gboolean io_eof; -+ uint8_t opcode; - }; - - /** -diff --git a/io/channel-websock.c b/io/channel-websock.c -index 4e5afb2..909d636 100644 ---- a/io/channel-websock.c -+++ b/io/channel-websock.c -@@ -636,28 +636,38 @@ static int qio_channel_websock_decode_header(QIOChannelWebsock *ioc, - has_mask = header->b1 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_HAS_MASK; - payload_len = header->b1 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_PAYLOAD_LEN; - -+ /* Save or restore opcode. */ -+ if (opcode) { -+ ioc->opcode = opcode; -+ } else { -+ opcode = ioc->opcode; -+ } -+ - if (opcode == QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE) { - /* disconnect */ - return 0; - } - - /* Websocket frame sanity check: -- * * Websocket fragmentation is not supported. -- * * All websockets frames sent by a client have to be masked. -+ * * Fragmentation is only supported for binary frames. -+ * * All frames sent by a client MUST be masked. - * * Only binary encoding is supported. - */ - if (!fin) { -- error_setg(errp, "websocket fragmentation is not supported"); -- return -1; -+ if (opcode != QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) { -+ error_setg(errp, "only binary websocket frames may be fragmented"); -+ return -1; -+ } -+ } else { -+ if (opcode != QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) { -+ error_setg(errp, "only binary websocket frames are supported"); -+ return -1; -+ } - } - if (!has_mask) { - error_setg(errp, "client websocket frames must be masked"); - return -1; - } -- if (opcode != QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) { -- error_setg(errp, "only binary websocket frames are supported"); -- return -1; -- } - - if (payload_len < QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_16_BIT) { - ioc->payload_remain = payload_len; --- -1.8.3.1 - diff --git a/SOURCES/kvm-io-Allow-empty-websocket-payload.patch b/SOURCES/kvm-io-Allow-empty-websocket-payload.patch deleted file mode 100644 index ed08d1b..0000000 --- a/SOURCES/kvm-io-Allow-empty-websocket-payload.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 56192448a2221f518f3e959f511e1244100de600 Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Wed, 20 Dec 2017 17:56:49 +0100 -Subject: [PATCH 09/42] io: Allow empty websocket payload - -RH-Author: Daniel P. Berrange -Message-id: <20171220175702.29663-8-berrange@redhat.com> -Patchwork-id: 78453 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 07/20] io: Allow empty websocket payload -Bugzilla: 1518649 -RH-Acked-by: John Snow -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -From: Brandon Carpenter - -Some browsers send pings/pongs with no payload, so allow empty payloads -instead of closing the connection. - -Signed-off-by: Brandon Carpenter -Signed-off-by: Daniel P. Berrange -(cherry picked from commit 3a29640e2cbae9d47b89ffaf98ed358920eb6797) -Signed-off-by: Miroslav Rezanina ---- - io/channel-websock.c | 62 +++++++++++++++++++++++++--------------------------- - 1 file changed, 30 insertions(+), 32 deletions(-) - -diff --git a/io/channel-websock.c b/io/channel-websock.c -index 909d636..b19b5d9 100644 ---- a/io/channel-websock.c -+++ b/io/channel-websock.c -@@ -697,44 +697,42 @@ static int qio_channel_websock_decode_payload(QIOChannelWebsock *ioc, - Error **errp) - { - size_t i; -- size_t payload_len; -+ size_t payload_len = 0; - uint32_t *payload32; - -- if (!ioc->payload_remain) { -- error_setg(errp, -- "Decoding payload but no bytes of payload remain"); -- return -1; -- } -- -- /* If we aren't at the end of the payload, then drop -- * off the last bytes, so we're always multiple of 4 -- * for purpose of unmasking, except at end of payload -- */ -- if (ioc->encinput.offset < ioc->payload_remain) { -- payload_len = ioc->encinput.offset - (ioc->encinput.offset % 4); -- } else { -- payload_len = ioc->payload_remain; -- } -- if (payload_len == 0) { -- return QIO_CHANNEL_ERR_BLOCK; -- } -+ if (ioc->payload_remain) { -+ /* If we aren't at the end of the payload, then drop -+ * off the last bytes, so we're always multiple of 4 -+ * for purpose of unmasking, except at end of payload -+ */ -+ if (ioc->encinput.offset < ioc->payload_remain) { -+ payload_len = ioc->encinput.offset - (ioc->encinput.offset % 4); -+ } else { -+ payload_len = ioc->payload_remain; -+ } -+ if (payload_len == 0) { -+ return QIO_CHANNEL_ERR_BLOCK; -+ } - -- ioc->payload_remain -= payload_len; -+ ioc->payload_remain -= payload_len; - -- /* unmask frame */ -- /* process 1 frame (32 bit op) */ -- payload32 = (uint32_t *)ioc->encinput.buffer; -- for (i = 0; i < payload_len / 4; i++) { -- payload32[i] ^= ioc->mask.u; -- } -- /* process the remaining bytes (if any) */ -- for (i *= 4; i < payload_len; i++) { -- ioc->encinput.buffer[i] ^= ioc->mask.c[i % 4]; -+ /* unmask frame */ -+ /* process 1 frame (32 bit op) */ -+ payload32 = (uint32_t *)ioc->encinput.buffer; -+ for (i = 0; i < payload_len / 4; i++) { -+ payload32[i] ^= ioc->mask.u; -+ } -+ /* process the remaining bytes (if any) */ -+ for (i *= 4; i < payload_len; i++) { -+ ioc->encinput.buffer[i] ^= ioc->mask.c[i % 4]; -+ } - } - -- buffer_reserve(&ioc->rawinput, payload_len); -- buffer_append(&ioc->rawinput, ioc->encinput.buffer, payload_len); -- buffer_advance(&ioc->encinput, payload_len); -+ if (payload_len) { -+ buffer_reserve(&ioc->rawinput, payload_len); -+ buffer_append(&ioc->rawinput, ioc->encinput.buffer, payload_len); -+ buffer_advance(&ioc->encinput, payload_len); -+ } - return 0; - } - --- -1.8.3.1 - diff --git a/SOURCES/kvm-io-Attempt-to-send-websocket-close-messages-to-clien.patch b/SOURCES/kvm-io-Attempt-to-send-websocket-close-messages-to-clien.patch deleted file mode 100644 index 5b1a5b9..0000000 --- a/SOURCES/kvm-io-Attempt-to-send-websocket-close-messages-to-clien.patch +++ /dev/null @@ -1,163 +0,0 @@ -From b3f0cf18f87238075db4091fbfa63921852aeca6 Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Wed, 20 Dec 2017 17:56:52 +0100 -Subject: [PATCH 12/42] io: Attempt to send websocket close messages to client - -RH-Author: Daniel P. Berrange -Message-id: <20171220175702.29663-11-berrange@redhat.com> -Patchwork-id: 78463 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 10/20] io: Attempt to send websocket close messages to client -Bugzilla: 1518649 -RH-Acked-by: John Snow -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -From: Brandon Carpenter - -Make a best effort attempt to close websocket connections according to -the RFC. Sends the close message, as room permits in the socket buffer, -and immediately closes the socket. - -Signed-off-by: Brandon Carpenter -Signed-off-by: Daniel P. Berrange -(cherry picked from commit 530ca60c16c83435d4becc9916d74fa43e003815) -Signed-off-by: Miroslav Rezanina ---- - io/channel-websock.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++--- - 1 file changed, 65 insertions(+), 3 deletions(-) - -diff --git a/io/channel-websock.c b/io/channel-websock.c -index b6fc0c9..3195eb2 100644 ---- a/io/channel-websock.c -+++ b/io/channel-websock.c -@@ -188,6 +188,15 @@ static void qio_channel_websock_handshake_send_res_err(QIOChannelWebsock *ioc, - g_free(date); - } - -+enum { -+ QIO_CHANNEL_WEBSOCK_STATUS_NORMAL = 1000, -+ QIO_CHANNEL_WEBSOCK_STATUS_PROTOCOL_ERR = 1002, -+ QIO_CHANNEL_WEBSOCK_STATUS_INVALID_DATA = 1003, -+ QIO_CHANNEL_WEBSOCK_STATUS_POLICY = 1008, -+ QIO_CHANNEL_WEBSOCK_STATUS_TOO_LARGE = 1009, -+ QIO_CHANNEL_WEBSOCK_STATUS_SERVER_ERR = 1011, -+}; -+ - static size_t - qio_channel_websock_extract_headers(QIOChannelWebsock *ioc, - char *buffer, -@@ -617,6 +626,27 @@ static void qio_channel_websock_encode(QIOChannelWebsock *ioc) - } - - -+static ssize_t qio_channel_websock_write_wire(QIOChannelWebsock *, Error **); -+ -+ -+static void qio_channel_websock_write_close(QIOChannelWebsock *ioc, -+ uint16_t code, const char *reason) -+{ -+ buffer_reserve(&ioc->rawoutput, 2 + (reason ? strlen(reason) : 0)); -+ *(uint16_t *)(ioc->rawoutput.buffer + ioc->rawoutput.offset) = -+ cpu_to_be16(code); -+ ioc->rawoutput.offset += 2; -+ if (reason) { -+ buffer_append(&ioc->rawoutput, reason, strlen(reason)); -+ } -+ qio_channel_websock_encode_buffer( -+ &ioc->encoutput, QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE, &ioc->rawoutput); -+ buffer_reset(&ioc->rawoutput); -+ qio_channel_websock_write_wire(ioc, NULL); -+ qio_channel_shutdown(ioc->master, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); -+} -+ -+ - static int qio_channel_websock_decode_header(QIOChannelWebsock *ioc, - Error **errp) - { -@@ -630,6 +660,9 @@ static int qio_channel_websock_decode_header(QIOChannelWebsock *ioc, - error_setg(errp, - "Decoding header but %zu bytes of payload remain", - ioc->payload_remain); -+ qio_channel_websock_write_close( -+ ioc, QIO_CHANNEL_WEBSOCK_STATUS_SERVER_ERR, -+ "internal server error"); - return -1; - } - if (ioc->encinput.offset < QIO_CHANNEL_WEBSOCK_HEADER_LEN_7_BIT) { -@@ -662,19 +695,29 @@ static int qio_channel_websock_decode_header(QIOChannelWebsock *ioc, - if (!fin) { - if (opcode != QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) { - error_setg(errp, "only binary websocket frames may be fragmented"); -+ qio_channel_websock_write_close( -+ ioc, QIO_CHANNEL_WEBSOCK_STATUS_POLICY , -+ "only binary frames may be fragmented"); - return -1; - } - } else { - if (opcode != QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME && -+ opcode != QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE && - opcode != QIO_CHANNEL_WEBSOCK_OPCODE_PING && - opcode != QIO_CHANNEL_WEBSOCK_OPCODE_PONG) { -- error_setg(errp, "unsupported opcode: %#04x; only binary, ping, " -- "and pong websocket frames are supported", opcode); -+ error_setg(errp, "unsupported opcode: %#04x; only binary, close, " -+ "ping, and pong websocket frames are supported", opcode); -+ qio_channel_websock_write_close( -+ ioc, QIO_CHANNEL_WEBSOCK_STATUS_INVALID_DATA , -+ "only binary, close, ping, and pong frames are supported"); - return -1; - } - } - if (!has_mask) { - error_setg(errp, "client websocket frames must be masked"); -+ qio_channel_websock_write_close( -+ ioc, QIO_CHANNEL_WEBSOCK_STATUS_PROTOCOL_ERR, -+ "client frames must be masked"); - return -1; - } - -@@ -684,6 +727,9 @@ static int qio_channel_websock_decode_header(QIOChannelWebsock *ioc, - ioc->mask = header->u.m; - } else if (opcode & QIO_CHANNEL_WEBSOCK_CONTROL_OPCODE_MASK) { - error_setg(errp, "websocket control frame is too large"); -+ qio_channel_websock_write_close( -+ ioc, QIO_CHANNEL_WEBSOCK_STATUS_PROTOCOL_ERR, -+ "control frame is too large"); - return -1; - } else if (payload_len == QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_16_BIT && - ioc->encinput.offset >= QIO_CHANNEL_WEBSOCK_HEADER_LEN_16_BIT) { -@@ -701,7 +747,7 @@ static int qio_channel_websock_decode_header(QIOChannelWebsock *ioc, - } - - buffer_advance(&ioc->encinput, header_size); -- return 1; -+ return 0; - } - - -@@ -751,6 +797,22 @@ static int qio_channel_websock_decode_payload(QIOChannelWebsock *ioc, - buffer_reserve(&ioc->rawinput, payload_len); - buffer_append(&ioc->rawinput, ioc->encinput.buffer, payload_len); - } -+ } else if (ioc->opcode == QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE) { -+ /* close frames are echoed back */ -+ error_setg(errp, "websocket closed by peer"); -+ if (payload_len) { -+ /* echo client status */ -+ qio_channel_websock_encode_buffer( -+ &ioc->encoutput, QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE, -+ &ioc->encinput); -+ qio_channel_websock_write_wire(ioc, NULL); -+ qio_channel_shutdown(ioc->master, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); -+ } else { -+ /* send our own status */ -+ qio_channel_websock_write_close( -+ ioc, QIO_CHANNEL_WEBSOCK_STATUS_NORMAL, "peer requested close"); -+ } -+ return -1; - } else if (ioc->opcode == QIO_CHANNEL_WEBSOCK_OPCODE_PING) { - /* ping frames produce an immediate reply */ - buffer_reset(&ioc->ping_reply); --- -1.8.3.1 - diff --git a/SOURCES/kvm-io-Ignore-websocket-PING-and-PONG-frames.patch b/SOURCES/kvm-io-Ignore-websocket-PING-and-PONG-frames.patch deleted file mode 100644 index 59758f8..0000000 --- a/SOURCES/kvm-io-Ignore-websocket-PING-and-PONG-frames.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 137479576664767db121c512db49f4c40789fa52 Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Wed, 20 Dec 2017 17:56:50 +0100 -Subject: [PATCH 10/42] io: Ignore websocket PING and PONG frames - -RH-Author: Daniel P. Berrange -Message-id: <20171220175702.29663-9-berrange@redhat.com> -Patchwork-id: 78460 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 08/20] io: Ignore websocket PING and PONG frames -Bugzilla: 1518649 -RH-Acked-by: John Snow -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -From: Brandon Carpenter - -Keep pings and gratuitous pongs generated by web browsers from killing -websocket connections. - -Signed-off-by: Brandon Carpenter -Signed-off-by: Daniel P. Berrange -(cherry picked from commit 01af17fc002414ee1ac0800babfb0edc2bef1a7d) -Signed-off-by: Miroslav Rezanina ---- - io/channel-websock.c | 21 +++++++++++++++++---- - 1 file changed, 17 insertions(+), 4 deletions(-) - -diff --git a/io/channel-websock.c b/io/channel-websock.c -index b19b5d9..bfe4008 100644 ---- a/io/channel-websock.c -+++ b/io/channel-websock.c -@@ -115,6 +115,7 @@ - #define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE 0x0f - #define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_HAS_MASK 0x80 - #define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_PAYLOAD_LEN 0x7f -+#define QIO_CHANNEL_WEBSOCK_CONTROL_OPCODE_MASK 0x8 - - typedef struct QIOChannelWebsockHeader QIOChannelWebsockHeader; - -@@ -659,8 +660,11 @@ static int qio_channel_websock_decode_header(QIOChannelWebsock *ioc, - return -1; - } - } else { -- if (opcode != QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) { -- error_setg(errp, "only binary websocket frames are supported"); -+ if (opcode != QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME && -+ opcode != QIO_CHANNEL_WEBSOCK_OPCODE_PING && -+ opcode != QIO_CHANNEL_WEBSOCK_OPCODE_PONG) { -+ error_setg(errp, "unsupported opcode: %#04x; only binary, ping, " -+ "and pong websocket frames are supported", opcode); - return -1; - } - } -@@ -673,6 +677,9 @@ static int qio_channel_websock_decode_header(QIOChannelWebsock *ioc, - ioc->payload_remain = payload_len; - header_size = QIO_CHANNEL_WEBSOCK_HEADER_LEN_7_BIT; - ioc->mask = header->u.m; -+ } else if (opcode & QIO_CHANNEL_WEBSOCK_CONTROL_OPCODE_MASK) { -+ error_setg(errp, "websocket control frame is too large"); -+ return -1; - } else if (payload_len == QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_16_BIT && - ioc->encinput.offset >= QIO_CHANNEL_WEBSOCK_HEADER_LEN_16_BIT) { - ioc->payload_remain = be16_to_cpu(header->u.s16.l16); -@@ -728,9 +735,15 @@ static int qio_channel_websock_decode_payload(QIOChannelWebsock *ioc, - } - } - -+ /* Drop the payload of ping/pong packets */ -+ if (ioc->opcode == QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) { -+ if (payload_len) { -+ buffer_reserve(&ioc->rawinput, payload_len); -+ buffer_append(&ioc->rawinput, ioc->encinput.buffer, payload_len); -+ } -+ } -+ - if (payload_len) { -- buffer_reserve(&ioc->rawinput, payload_len); -- buffer_append(&ioc->rawinput, ioc->encinput.buffer, payload_len); - buffer_advance(&ioc->encinput, payload_len); - } - return 0; --- -1.8.3.1 - diff --git a/SOURCES/kvm-io-Reply-to-ping-frames.patch b/SOURCES/kvm-io-Reply-to-ping-frames.patch deleted file mode 100644 index fef8711..0000000 --- a/SOURCES/kvm-io-Reply-to-ping-frames.patch +++ /dev/null @@ -1,185 +0,0 @@ -From 9fb29da8bb32eeead15ac4038cb9cbfca11066f5 Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Wed, 20 Dec 2017 17:56:51 +0100 -Subject: [PATCH 11/42] io: Reply to ping frames - -RH-Author: Daniel P. Berrange -Message-id: <20171220175702.29663-10-berrange@redhat.com> -Patchwork-id: 78462 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 09/20] io: Reply to ping frames -Bugzilla: 1518649 -RH-Acked-by: John Snow -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -From: Brandon Carpenter - -Add an immediate ping reply (pong) to the outgoing stream when a ping -is received. Unsolicited pongs are ignored. - -Signed-off-by: Brandon Carpenter -Signed-off-by: Daniel P. Berrange -(cherry picked from commit 268a53f50de795481dd73ffd0e0c1339ad3dc44b) -Signed-off-by: Miroslav Rezanina ---- - include/io/channel-websock.h | 1 + - io/channel-websock.c | 66 +++++++++++++++++++++++++++++--------------- - 2 files changed, 45 insertions(+), 22 deletions(-) - -diff --git a/include/io/channel-websock.h b/include/io/channel-websock.h -index 7c89655..ff32d86 100644 ---- a/include/io/channel-websock.h -+++ b/include/io/channel-websock.h -@@ -60,6 +60,7 @@ struct QIOChannelWebsock { - Buffer encoutput; - Buffer rawinput; - Buffer rawoutput; -+ Buffer ping_reply; - size_t payload_remain; - QIOChannelWebsockMask mask; - guint io_tag; -diff --git a/io/channel-websock.c b/io/channel-websock.c -index bfe4008..b6fc0c9 100644 ---- a/io/channel-websock.c -+++ b/io/channel-websock.c -@@ -573,7 +573,8 @@ static gboolean qio_channel_websock_handshake_io(QIOChannel *ioc, - } - - --static void qio_channel_websock_encode(QIOChannelWebsock *ioc) -+static void qio_channel_websock_encode_buffer(Buffer *output, -+ uint8_t opcode, Buffer *buffer) - { - size_t header_size; - union { -@@ -581,33 +582,37 @@ static void qio_channel_websock_encode(QIOChannelWebsock *ioc) - QIOChannelWebsockHeader ws; - } header; - -- if (!ioc->rawoutput.offset) { -- return; -- } -- - header.ws.b0 = QIO_CHANNEL_WEBSOCK_HEADER_FIELD_FIN | -- (QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME & -- QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE); -- if (ioc->rawoutput.offset < -- QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_THRESHOLD_7_BIT) { -- header.ws.b1 = (uint8_t)ioc->rawoutput.offset; -+ (opcode & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE); -+ if (buffer->offset < QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_THRESHOLD_7_BIT) { -+ header.ws.b1 = (uint8_t)buffer->offset; - header_size = QIO_CHANNEL_WEBSOCK_HEADER_LEN_7_BIT; -- } else if (ioc->rawoutput.offset < -+ } else if (buffer->offset < - QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_THRESHOLD_16_BIT) { - header.ws.b1 = QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_16_BIT; -- header.ws.u.s16.l16 = cpu_to_be16((uint16_t)ioc->rawoutput.offset); -+ header.ws.u.s16.l16 = cpu_to_be16((uint16_t)buffer->offset); - header_size = QIO_CHANNEL_WEBSOCK_HEADER_LEN_16_BIT; - } else { - header.ws.b1 = QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_64_BIT; -- header.ws.u.s64.l64 = cpu_to_be64(ioc->rawoutput.offset); -+ header.ws.u.s64.l64 = cpu_to_be64(buffer->offset); - header_size = QIO_CHANNEL_WEBSOCK_HEADER_LEN_64_BIT; - } - header_size -= QIO_CHANNEL_WEBSOCK_HEADER_LEN_MASK; - -- buffer_reserve(&ioc->encoutput, header_size + ioc->rawoutput.offset); -- buffer_append(&ioc->encoutput, header.buf, header_size); -- buffer_append(&ioc->encoutput, ioc->rawoutput.buffer, -- ioc->rawoutput.offset); -+ buffer_reserve(output, header_size + buffer->offset); -+ buffer_append(output, header.buf, header_size); -+ buffer_append(output, buffer->buffer, buffer->offset); -+} -+ -+ -+static void qio_channel_websock_encode(QIOChannelWebsock *ioc) -+{ -+ if (!ioc->rawoutput.offset) { -+ return; -+ } -+ qio_channel_websock_encode_buffer( -+ &ioc->encoutput, QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME, -+ &ioc->rawoutput); - buffer_reset(&ioc->rawoutput); - } - -@@ -652,7 +657,7 @@ static int qio_channel_websock_decode_header(QIOChannelWebsock *ioc, - /* Websocket frame sanity check: - * * Fragmentation is only supported for binary frames. - * * All frames sent by a client MUST be masked. -- * * Only binary encoding is supported. -+ * * Only binary and ping/pong encoding is supported. - */ - if (!fin) { - if (opcode != QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) { -@@ -713,6 +718,11 @@ static int qio_channel_websock_decode_payload(QIOChannelWebsock *ioc, - * for purpose of unmasking, except at end of payload - */ - if (ioc->encinput.offset < ioc->payload_remain) { -+ /* Wait for the entire payload before processing control frames -+ * because the payload will most likely be echoed back. */ -+ if (ioc->opcode & QIO_CHANNEL_WEBSOCK_CONTROL_OPCODE_MASK) { -+ return QIO_CHANNEL_ERR_BLOCK; -+ } - payload_len = ioc->encinput.offset - (ioc->encinput.offset % 4); - } else { - payload_len = ioc->payload_remain; -@@ -735,13 +745,18 @@ static int qio_channel_websock_decode_payload(QIOChannelWebsock *ioc, - } - } - -- /* Drop the payload of ping/pong packets */ - if (ioc->opcode == QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) { - if (payload_len) { -+ /* binary frames are passed on */ - buffer_reserve(&ioc->rawinput, payload_len); - buffer_append(&ioc->rawinput, ioc->encinput.buffer, payload_len); - } -- } -+ } else if (ioc->opcode == QIO_CHANNEL_WEBSOCK_OPCODE_PING) { -+ /* ping frames produce an immediate reply */ -+ buffer_reset(&ioc->ping_reply); -+ qio_channel_websock_encode_buffer( -+ &ioc->ping_reply, QIO_CHANNEL_WEBSOCK_OPCODE_PONG, &ioc->encinput); -+ } /* pong frames are ignored */ - - if (payload_len) { - buffer_advance(&ioc->encinput, payload_len); -@@ -799,6 +814,7 @@ static void qio_channel_websock_finalize(Object *obj) - buffer_free(&ioc->encoutput); - buffer_free(&ioc->rawinput); - buffer_free(&ioc->rawoutput); -+ buffer_free(&ioc->ping_reply); - object_unref(OBJECT(ioc->master)); - if (ioc->io_tag) { - g_source_remove(ioc->io_tag); -@@ -855,7 +871,13 @@ static ssize_t qio_channel_websock_write_wire(QIOChannelWebsock *ioc, - { - ssize_t ret; - ssize_t done = 0; -- qio_channel_websock_encode(ioc); -+ -+ /* ping replies take priority over binary data */ -+ if (!ioc->ping_reply.offset) { -+ qio_channel_websock_encode(ioc); -+ } else if (!ioc->encoutput.offset) { -+ buffer_move_empty(&ioc->encoutput, &ioc->ping_reply); -+ } - - while (ioc->encoutput.offset > 0) { - ret = qio_channel_write(ioc->master, -@@ -930,7 +952,7 @@ static void qio_channel_websock_set_watch(QIOChannelWebsock *ioc) - return; - } - -- if (ioc->encoutput.offset) { -+ if (ioc->encoutput.offset || ioc->ping_reply.offset) { - cond |= G_IO_OUT; - } - if (ioc->encinput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER && --- -1.8.3.1 - diff --git a/SOURCES/kvm-io-Small-updates-in-preparation-for-websocket-change.patch b/SOURCES/kvm-io-Small-updates-in-preparation-for-websocket-change.patch deleted file mode 100644 index 4bebe90..0000000 --- a/SOURCES/kvm-io-Small-updates-in-preparation-for-websocket-change.patch +++ /dev/null @@ -1,195 +0,0 @@ -From 977ae916454f470780f7562b61c98718e2d0d49c Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Wed, 20 Dec 2017 17:56:47 +0100 -Subject: [PATCH 07/42] io: Small updates in preparation for websocket changes - -RH-Author: Daniel P. Berrange -Message-id: <20171220175702.29663-6-berrange@redhat.com> -Patchwork-id: 78459 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 05/20] io: Small updates in preparation for websocket changes -Bugzilla: 1518649 -RH-Acked-by: John Snow -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -From: Brandon Carpenter - -Gets rid of unnecessary bit shifting and performs proper EOF checking to -avoid a large number of repeated calls to recvmsg() when a client -abruptly terminates a connection (bug fix). - -Signed-off-by: Brandon Carpenter -Signed-off-by: Daniel P. Berrange -(cherry picked from commit eefa3d8ef649f9055611361e2201cca49f8c3433) -Signed-off-by: Miroslav Rezanina ---- - io/channel-websock.c | 64 ++++++++++++++++------------------------------------ - 1 file changed, 19 insertions(+), 45 deletions(-) - -diff --git a/io/channel-websock.c b/io/channel-websock.c -index 2258557..4e5afb2 100644 ---- a/io/channel-websock.c -+++ b/io/channel-websock.c -@@ -110,13 +110,11 @@ - /* Magic 7-bit length to indicate use of 64-bit payload length */ - #define QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_64_BIT 127 - --/* Bitmasks & shifts for accessing header fields */ -+/* Bitmasks for accessing header fields */ - #define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_FIN 0x80 - #define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE 0x0f - #define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_HAS_MASK 0x80 - #define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_PAYLOAD_LEN 0x7f --#define QIO_CHANNEL_WEBSOCK_HEADER_SHIFT_FIN 7 --#define QIO_CHANNEL_WEBSOCK_HEADER_SHIFT_HAS_MASK 7 - - typedef struct QIOChannelWebsockHeader QIOChannelWebsockHeader; - -@@ -586,7 +584,7 @@ static void qio_channel_websock_encode(QIOChannelWebsock *ioc) - return; - } - -- header.ws.b0 = (1 << QIO_CHANNEL_WEBSOCK_HEADER_SHIFT_FIN) | -+ header.ws.b0 = QIO_CHANNEL_WEBSOCK_HEADER_FIELD_FIN | - (QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME & - QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE); - if (ioc->rawoutput.offset < -@@ -613,8 +611,8 @@ static void qio_channel_websock_encode(QIOChannelWebsock *ioc) - } - - --static ssize_t qio_channel_websock_decode_header(QIOChannelWebsock *ioc, -- Error **errp) -+static int qio_channel_websock_decode_header(QIOChannelWebsock *ioc, -+ Error **errp) - { - unsigned char opcode, fin, has_mask; - size_t header_size; -@@ -633,11 +631,9 @@ static ssize_t qio_channel_websock_decode_header(QIOChannelWebsock *ioc, - return QIO_CHANNEL_ERR_BLOCK; - } - -- fin = (header->b0 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_FIN) >> -- QIO_CHANNEL_WEBSOCK_HEADER_SHIFT_FIN; -+ fin = header->b0 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_FIN; - opcode = header->b0 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE; -- has_mask = (header->b1 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_HAS_MASK) >> -- QIO_CHANNEL_WEBSOCK_HEADER_SHIFT_HAS_MASK; -+ has_mask = header->b1 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_HAS_MASK; - payload_len = header->b1 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_PAYLOAD_LEN; - - if (opcode == QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE) { -@@ -655,7 +651,7 @@ static ssize_t qio_channel_websock_decode_header(QIOChannelWebsock *ioc, - return -1; - } - if (!has_mask) { -- error_setg(errp, "websocket frames must be masked"); -+ error_setg(errp, "client websocket frames must be masked"); - return -1; - } - if (opcode != QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) { -@@ -687,8 +683,8 @@ static ssize_t qio_channel_websock_decode_header(QIOChannelWebsock *ioc, - } - - --static ssize_t qio_channel_websock_decode_payload(QIOChannelWebsock *ioc, -- Error **errp) -+static int qio_channel_websock_decode_payload(QIOChannelWebsock *ioc, -+ Error **errp) - { - size_t i; - size_t payload_len; -@@ -729,7 +725,7 @@ static ssize_t qio_channel_websock_decode_payload(QIOChannelWebsock *ioc, - buffer_reserve(&ioc->rawinput, payload_len); - buffer_append(&ioc->rawinput, ioc->encinput.buffer, payload_len); - buffer_advance(&ioc->encinput, payload_len); -- return payload_len; -+ return 0; - } - - -@@ -809,8 +805,8 @@ static ssize_t qio_channel_websock_read_wire(QIOChannelWebsock *ioc, - if (ret < 0) { - return ret; - } -- if (ret == 0 && -- ioc->encinput.offset == 0) { -+ if (ret == 0 && ioc->encinput.offset == 0) { -+ ioc->io_eof = TRUE; - return 0; - } - ioc->encinput.offset += ret; -@@ -822,10 +818,6 @@ static ssize_t qio_channel_websock_read_wire(QIOChannelWebsock *ioc, - if (ret < 0) { - return ret; - } -- if (ret == 0) { -- ioc->io_eof = TRUE; -- break; -- } - } - - ret = qio_channel_websock_decode_payload(ioc, errp); -@@ -1090,14 +1082,12 @@ struct QIOChannelWebsockSource { - }; - - static gboolean --qio_channel_websock_source_prepare(GSource *source, -- gint *timeout) -+qio_channel_websock_source_check(GSource *source) - { - QIOChannelWebsockSource *wsource = (QIOChannelWebsockSource *)source; - GIOCondition cond = 0; -- *timeout = -1; - -- if (wsource->wioc->rawinput.offset) { -+ if (wsource->wioc->rawinput.offset || wsource->wioc->io_eof) { - cond |= G_IO_IN; - } - if (wsource->wioc->rawoutput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER) { -@@ -1108,19 +1098,11 @@ qio_channel_websock_source_prepare(GSource *source, - } - - static gboolean --qio_channel_websock_source_check(GSource *source) -+qio_channel_websock_source_prepare(GSource *source, -+ gint *timeout) - { -- QIOChannelWebsockSource *wsource = (QIOChannelWebsockSource *)source; -- GIOCondition cond = 0; -- -- if (wsource->wioc->rawinput.offset) { -- cond |= G_IO_IN; -- } -- if (wsource->wioc->rawoutput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER) { -- cond |= G_IO_OUT; -- } -- -- return cond & wsource->condition; -+ *timeout = -1; -+ return qio_channel_websock_source_check(source); - } - - static gboolean -@@ -1130,17 +1112,9 @@ qio_channel_websock_source_dispatch(GSource *source, - { - QIOChannelFunc func = (QIOChannelFunc)callback; - QIOChannelWebsockSource *wsource = (QIOChannelWebsockSource *)source; -- GIOCondition cond = 0; -- -- if (wsource->wioc->rawinput.offset) { -- cond |= G_IO_IN; -- } -- if (wsource->wioc->rawoutput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER) { -- cond |= G_IO_OUT; -- } - - return (*func)(QIO_CHANNEL(wsource->wioc), -- (cond & wsource->condition), -+ qio_channel_websock_source_check(source), - user_data); - } - --- -1.8.3.1 - diff --git a/SOURCES/kvm-io-Yield-rather-than-wait-when-already-in-coroutine.patch b/SOURCES/kvm-io-Yield-rather-than-wait-when-already-in-coroutine.patch deleted file mode 100644 index e42bb27..0000000 --- a/SOURCES/kvm-io-Yield-rather-than-wait-when-already-in-coroutine.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 280e240cfa8e633dd062791b1d0d62fe0e642d46 Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Sat, 2 Dec 2017 12:19:38 +0100 -Subject: [PATCH 12/36] io: Yield rather than wait when already in coroutine - -RH-Author: Paolo Bonzini -Message-id: <20171202121953.13317-3-pbonzini@redhat.com> -Patchwork-id: 78076 -O-Subject: [RHEL7.4 qemu-kvm-rhev PATCH 02/17] io: Yield rather than wait when already in coroutine -Bugzilla: 1464908 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: John Snow - -From: Eric Blake - -The new qio_channel_{read,write}{,v}_all functions are documented -as yielding until data is available. When used on a blocking -channel, this yield is done via qio_channel_wait() which spawns -a nested event loop under the hood (so it is that secondary loop -which yields as needed); but if we are already in a coroutine (at -which point QIO_CHANNEL_ERR_BLOCK is only possible if we are a -non-blocking channel), we want to yield the current coroutine -instead of spawning a nested event loop. - -Signed-off-by: Eric Blake -Message-Id: <20170905191114.5959-2-eblake@redhat.com> -Acked-by: Daniel P. Berrange -[commit message updated] -Signed-off-by: Eric Blake -(cherry picked from commit 9ffb8270205a274a18ee4f8a735e2fccaf957246) - -Signed-off-by: Miroslav Rezanina ---- - io/channel.c | 12 ++++++++++-- - 1 file changed, 10 insertions(+), 2 deletions(-) - -diff --git a/io/channel.c b/io/channel.c -index 5e8c2f0..9e62794 100644 ---- a/io/channel.c -+++ b/io/channel.c -@@ -105,7 +105,11 @@ int qio_channel_readv_all(QIOChannel *ioc, - ssize_t len; - len = qio_channel_readv(ioc, local_iov, nlocal_iov, errp); - if (len == QIO_CHANNEL_ERR_BLOCK) { -- qio_channel_wait(ioc, G_IO_IN); -+ if (qemu_in_coroutine()) { -+ qio_channel_yield(ioc, G_IO_IN); -+ } else { -+ qio_channel_wait(ioc, G_IO_IN); -+ } - continue; - } else if (len < 0) { - goto cleanup; -@@ -143,7 +147,11 @@ int qio_channel_writev_all(QIOChannel *ioc, - ssize_t len; - len = qio_channel_writev(ioc, local_iov, nlocal_iov, errp); - if (len == QIO_CHANNEL_ERR_BLOCK) { -- qio_channel_wait(ioc, G_IO_OUT); -+ if (qemu_in_coroutine()) { -+ qio_channel_yield(ioc, G_IO_OUT); -+ } else { -+ qio_channel_wait(ioc, G_IO_OUT); -+ } - continue; - } - if (len < 0) { --- -1.8.3.1 - diff --git a/SOURCES/kvm-io-add-new-qio_channel_-readv-writev-read-write-_all.patch b/SOURCES/kvm-io-add-new-qio_channel_-readv-writev-read-write-_all.patch deleted file mode 100644 index f4b242b..0000000 --- a/SOURCES/kvm-io-add-new-qio_channel_-readv-writev-read-write-_all.patch +++ /dev/null @@ -1,397 +0,0 @@ -From 1bafd8e2d09bfdf4bb2098b82537a9baa170aabc Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Sat, 2 Dec 2017 12:19:37 +0100 -Subject: [PATCH 11/36] io: add new qio_channel_{readv, writev, read, - write}_all functions - -RH-Author: Paolo Bonzini -Message-id: <20171202121953.13317-2-pbonzini@redhat.com> -Patchwork-id: 78074 -O-Subject: [RHEL7.4 qemu-kvm-rhev PATCH 01/17] io: add new qio_channel_{readv, writev, read, write}_all functions -Bugzilla: 1464908 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: John Snow - -From: "Daniel P. Berrange" - -These functions wait until they are able to read / write the full -requested data buffer(s). - -Reviewed-by: Eric Blake -Signed-off-by: Daniel P. Berrange -(cherry picked from commit d4622e55883211072621958d39ddaa73483d201e) -Signed-off-by: Miroslav Rezanina ---- - include/io/channel.h | 90 +++++++++++++++++++++++++++++++++++++++ - io/channel.c | 94 +++++++++++++++++++++++++++++++++++++++++ - tests/io-channel-helpers.c | 102 ++++----------------------------------------- - 3 files changed, 193 insertions(+), 93 deletions(-) - -diff --git a/include/io/channel.h b/include/io/channel.h -index db9bb02..e11a62e 100644 ---- a/include/io/channel.h -+++ b/include/io/channel.h -@@ -269,6 +269,58 @@ ssize_t qio_channel_writev_full(QIOChannel *ioc, - Error **errp); - - /** -+ * qio_channel_readv_all: -+ * @ioc: the channel object -+ * @iov: the array of memory regions to read data into -+ * @niov: the length of the @iov array -+ * @errp: pointer to a NULL-initialized error object -+ * -+ * Read data from the IO channel, storing it in the -+ * memory regions referenced by @iov. Each element -+ * in the @iov will be fully populated with data -+ * before the next one is used. The @niov parameter -+ * specifies the total number of elements in @iov. -+ * -+ * The function will wait for all requested data -+ * to be read, yielding from the current coroutine -+ * if required. -+ * -+ * If end-of-file occurs before all requested data -+ * has been read, an error will be reported. -+ * -+ * Returns: 0 if all bytes were read, or -1 on error -+ */ -+int qio_channel_readv_all(QIOChannel *ioc, -+ const struct iovec *iov, -+ size_t niov, -+ Error **errp); -+ -+ -+/** -+ * qio_channel_writev_all: -+ * @ioc: the channel object -+ * @iov: the array of memory regions to write data from -+ * @niov: the length of the @iov array -+ * @errp: pointer to a NULL-initialized error object -+ * -+ * Write data to the IO channel, reading it from the -+ * memory regions referenced by @iov. Each element -+ * in the @iov will be fully sent, before the next -+ * one is used. The @niov parameter specifies the -+ * total number of elements in @iov. -+ * -+ * The function will wait for all requested data -+ * to be written, yielding from the current coroutine -+ * if required. -+ * -+ * Returns: 0 if all bytes were written, or -1 on error -+ */ -+int qio_channel_writev_all(QIOChannel *ioc, -+ const struct iovec *iov, -+ size_t niov, -+ Error **erp); -+ -+/** - * qio_channel_readv: - * @ioc: the channel object - * @iov: the array of memory regions to read data into -@@ -331,6 +383,44 @@ ssize_t qio_channel_write(QIOChannel *ioc, - Error **errp); - - /** -+ * qio_channel_read_all: -+ * @ioc: the channel object -+ * @buf: the memory region to read data into -+ * @buflen: the number of bytes to @buf -+ * @errp: pointer to a NULL-initialized error object -+ * -+ * Reads @buflen bytes into @buf, possibly blocking or (if the -+ * channel is non-blocking) yielding from the current coroutine -+ * multiple times until the entire content is read. If end-of-file -+ * occurs it will return an error rather than a short-read. Otherwise -+ * behaves as qio_channel_read(). -+ * -+ * Returns: 0 if all bytes were read, or -1 on error -+ */ -+int qio_channel_read_all(QIOChannel *ioc, -+ char *buf, -+ size_t buflen, -+ Error **errp); -+/** -+ * qio_channel_write_all: -+ * @ioc: the channel object -+ * @buf: the memory region to write data into -+ * @buflen: the number of bytes to @buf -+ * @errp: pointer to a NULL-initialized error object -+ * -+ * Writes @buflen bytes from @buf, possibly blocking or (if the -+ * channel is non-blocking) yielding from the current coroutine -+ * multiple times until the entire content is written. Otherwise -+ * behaves as qio_channel_write(). -+ * -+ * Returns: 0 if all bytes were written, or -1 on error -+ */ -+int qio_channel_write_all(QIOChannel *ioc, -+ const char *buf, -+ size_t buflen, -+ Error **errp); -+ -+/** - * qio_channel_set_blocking: - * @ioc: the channel object - * @enabled: the blocking flag state -diff --git a/io/channel.c b/io/channel.c -index 1cfb8b3..5e8c2f0 100644 ---- a/io/channel.c -+++ b/io/channel.c -@@ -22,6 +22,7 @@ - #include "io/channel.h" - #include "qapi/error.h" - #include "qemu/main-loop.h" -+#include "qemu/iov.h" - - bool qio_channel_has_feature(QIOChannel *ioc, - QIOChannelFeature feature) -@@ -85,6 +86,79 @@ ssize_t qio_channel_writev_full(QIOChannel *ioc, - } - - -+ -+int qio_channel_readv_all(QIOChannel *ioc, -+ const struct iovec *iov, -+ size_t niov, -+ Error **errp) -+{ -+ int ret = -1; -+ struct iovec *local_iov = g_new(struct iovec, niov); -+ struct iovec *local_iov_head = local_iov; -+ unsigned int nlocal_iov = niov; -+ -+ nlocal_iov = iov_copy(local_iov, nlocal_iov, -+ iov, niov, -+ 0, iov_size(iov, niov)); -+ -+ while (nlocal_iov > 0) { -+ ssize_t len; -+ len = qio_channel_readv(ioc, local_iov, nlocal_iov, errp); -+ if (len == QIO_CHANNEL_ERR_BLOCK) { -+ qio_channel_wait(ioc, G_IO_IN); -+ continue; -+ } else if (len < 0) { -+ goto cleanup; -+ } else if (len == 0) { -+ error_setg(errp, -+ "Unexpected end-of-file before all bytes were read"); -+ goto cleanup; -+ } -+ -+ iov_discard_front(&local_iov, &nlocal_iov, len); -+ } -+ -+ ret = 0; -+ -+ cleanup: -+ g_free(local_iov_head); -+ return ret; -+} -+ -+int qio_channel_writev_all(QIOChannel *ioc, -+ const struct iovec *iov, -+ size_t niov, -+ Error **errp) -+{ -+ int ret = -1; -+ struct iovec *local_iov = g_new(struct iovec, niov); -+ struct iovec *local_iov_head = local_iov; -+ unsigned int nlocal_iov = niov; -+ -+ nlocal_iov = iov_copy(local_iov, nlocal_iov, -+ iov, niov, -+ 0, iov_size(iov, niov)); -+ -+ while (nlocal_iov > 0) { -+ ssize_t len; -+ len = qio_channel_writev(ioc, local_iov, nlocal_iov, errp); -+ if (len == QIO_CHANNEL_ERR_BLOCK) { -+ qio_channel_wait(ioc, G_IO_OUT); -+ continue; -+ } -+ if (len < 0) { -+ goto cleanup; -+ } -+ -+ iov_discard_front(&local_iov, &nlocal_iov, len); -+ } -+ -+ ret = 0; -+ cleanup: -+ g_free(local_iov_head); -+ return ret; -+} -+ - ssize_t qio_channel_readv(QIOChannel *ioc, - const struct iovec *iov, - size_t niov, -@@ -123,6 +197,26 @@ ssize_t qio_channel_write(QIOChannel *ioc, - } - - -+int qio_channel_read_all(QIOChannel *ioc, -+ char *buf, -+ size_t buflen, -+ Error **errp) -+{ -+ struct iovec iov = { .iov_base = buf, .iov_len = buflen }; -+ return qio_channel_readv_all(ioc, &iov, 1, errp); -+} -+ -+ -+int qio_channel_write_all(QIOChannel *ioc, -+ const char *buf, -+ size_t buflen, -+ Error **errp) -+{ -+ struct iovec iov = { .iov_base = (char *)buf, .iov_len = buflen }; -+ return qio_channel_writev_all(ioc, &iov, 1, errp); -+} -+ -+ - int qio_channel_set_blocking(QIOChannel *ioc, - bool enabled, - Error **errp) -diff --git a/tests/io-channel-helpers.c b/tests/io-channel-helpers.c -index 05e5579..5430e13 100644 ---- a/tests/io-channel-helpers.c -+++ b/tests/io-channel-helpers.c -@@ -21,6 +21,7 @@ - #include "qemu/osdep.h" - #include "io-channel-helpers.h" - #include "qapi/error.h" -+#include "qemu/iov.h" - - struct QIOChannelTest { - QIOChannel *src; -@@ -37,77 +38,17 @@ struct QIOChannelTest { - }; - - --static void test_skip_iovec(struct iovec **iov, -- size_t *niov, -- size_t skip, -- struct iovec *old) --{ -- size_t offset = 0; -- size_t i; -- -- for (i = 0; i < *niov; i++) { -- if (skip < (*iov)[i].iov_len) { -- old->iov_len = (*iov)[i].iov_len; -- old->iov_base = (*iov)[i].iov_base; -- -- (*iov)[i].iov_len -= skip; -- (*iov)[i].iov_base += skip; -- break; -- } else { -- skip -= (*iov)[i].iov_len; -- -- if (i == 0 && old->iov_base) { -- (*iov)[i].iov_len = old->iov_len; -- (*iov)[i].iov_base = old->iov_base; -- old->iov_len = 0; -- old->iov_base = NULL; -- } -- -- offset++; -- } -- } -- -- *iov = *iov + offset; -- *niov -= offset; --} -- -- - /* This thread sends all data using iovecs */ - static gpointer test_io_thread_writer(gpointer opaque) - { - QIOChannelTest *data = opaque; -- struct iovec *iov = data->inputv; -- size_t niov = data->niov; -- struct iovec old = { 0 }; - - qio_channel_set_blocking(data->src, data->blocking, NULL); - -- while (niov) { -- ssize_t ret; -- ret = qio_channel_writev(data->src, -- iov, -- niov, -- &data->writeerr); -- if (ret == QIO_CHANNEL_ERR_BLOCK) { -- if (data->blocking) { -- error_setg(&data->writeerr, -- "Unexpected I/O blocking"); -- break; -- } else { -- qio_channel_wait(data->src, -- G_IO_OUT); -- continue; -- } -- } else if (ret < 0) { -- break; -- } else if (ret == 0) { -- error_setg(&data->writeerr, -- "Unexpected zero length write"); -- break; -- } -- -- test_skip_iovec(&iov, &niov, ret, &old); -- } -+ qio_channel_writev_all(data->src, -+ data->inputv, -+ data->niov, -+ &data->writeerr); - - return NULL; - } -@@ -117,38 +58,13 @@ static gpointer test_io_thread_writer(gpointer opaque) - static gpointer test_io_thread_reader(gpointer opaque) - { - QIOChannelTest *data = opaque; -- struct iovec *iov = data->outputv; -- size_t niov = data->niov; -- struct iovec old = { 0 }; - - qio_channel_set_blocking(data->dst, data->blocking, NULL); - -- while (niov) { -- ssize_t ret; -- -- ret = qio_channel_readv(data->dst, -- iov, -- niov, -- &data->readerr); -- -- if (ret == QIO_CHANNEL_ERR_BLOCK) { -- if (data->blocking) { -- error_setg(&data->readerr, -- "Unexpected I/O blocking"); -- break; -- } else { -- qio_channel_wait(data->dst, -- G_IO_IN); -- continue; -- } -- } else if (ret < 0) { -- break; -- } else if (ret == 0) { -- break; -- } -- -- test_skip_iovec(&iov, &niov, ret, &old); -- } -+ qio_channel_readv_all(data->dst, -+ data->outputv, -+ data->niov, -+ &data->readerr); - - return NULL; - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-io-add-trace-events-for-websockets-frame-handling.patch b/SOURCES/kvm-io-add-trace-events-for-websockets-frame-handling.patch deleted file mode 100644 index d2d5f2f..0000000 --- a/SOURCES/kvm-io-add-trace-events-for-websockets-frame-handling.patch +++ /dev/null @@ -1,142 +0,0 @@ -From 3b740258b14da87d647beb87275bf16136a00985 Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Wed, 20 Dec 2017 17:56:53 +0100 -Subject: [PATCH 13/42] io: add trace events for websockets frame handling - -RH-Author: Daniel P. Berrange -Message-id: <20171220175702.29663-12-berrange@redhat.com> -Patchwork-id: 78464 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 11/20] io: add trace events for websockets frame handling -Bugzilla: 1518649 -RH-Acked-by: John Snow -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -It is useful to trace websockets frame encoding/decoding when debugging -problems. - -Reviewed-by: Stefan Hajnoczi -Signed-off-by: Daniel P. Berrange -(cherry picked from commit 59f183bbd54eecffb8915bffe03f9c2720b28bcc) -Signed-off-by: Miroslav Rezanina ---- - io/channel-websock.c | 23 ++++++++++++++++++----- - io/trace-events | 5 +++++ - 2 files changed, 23 insertions(+), 5 deletions(-) - -diff --git a/io/channel-websock.c b/io/channel-websock.c -index 3195eb2..d1d471f 100644 ---- a/io/channel-websock.c -+++ b/io/channel-websock.c -@@ -582,7 +582,8 @@ static gboolean qio_channel_websock_handshake_io(QIOChannel *ioc, - } - - --static void qio_channel_websock_encode_buffer(Buffer *output, -+static void qio_channel_websock_encode_buffer(QIOChannelWebsock *ioc, -+ Buffer *output, - uint8_t opcode, Buffer *buffer) - { - size_t header_size; -@@ -608,6 +609,7 @@ static void qio_channel_websock_encode_buffer(Buffer *output, - } - header_size -= QIO_CHANNEL_WEBSOCK_HEADER_LEN_MASK; - -+ trace_qio_channel_websock_encode(ioc, opcode, header_size, buffer->offset); - buffer_reserve(output, header_size + buffer->offset); - buffer_append(output, header.buf, header_size); - buffer_append(output, buffer->buffer, buffer->offset); -@@ -620,7 +622,7 @@ static void qio_channel_websock_encode(QIOChannelWebsock *ioc) - return; - } - qio_channel_websock_encode_buffer( -- &ioc->encoutput, QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME, -+ ioc, &ioc->encoutput, QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME, - &ioc->rawoutput); - buffer_reset(&ioc->rawoutput); - } -@@ -640,7 +642,8 @@ static void qio_channel_websock_write_close(QIOChannelWebsock *ioc, - buffer_append(&ioc->rawoutput, reason, strlen(reason)); - } - qio_channel_websock_encode_buffer( -- &ioc->encoutput, QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE, &ioc->rawoutput); -+ ioc, &ioc->encoutput, QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE, -+ &ioc->rawoutput); - buffer_reset(&ioc->rawoutput); - qio_channel_websock_write_wire(ioc, NULL); - qio_channel_shutdown(ioc->master, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); -@@ -682,6 +685,9 @@ static int qio_channel_websock_decode_header(QIOChannelWebsock *ioc, - opcode = ioc->opcode; - } - -+ trace_qio_channel_websock_header_partial_decode(ioc, payload_len, -+ fin, opcode, (int)has_mask); -+ - if (opcode == QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE) { - /* disconnect */ - return 0; -@@ -746,6 +752,8 @@ static int qio_channel_websock_decode_header(QIOChannelWebsock *ioc, - return QIO_CHANNEL_ERR_BLOCK; - } - -+ trace_qio_channel_websock_header_full_decode( -+ ioc, header_size, ioc->payload_remain, ioc->mask.u); - buffer_advance(&ioc->encinput, header_size); - return 0; - } -@@ -791,6 +799,9 @@ static int qio_channel_websock_decode_payload(QIOChannelWebsock *ioc, - } - } - -+ trace_qio_channel_websock_payload_decode( -+ ioc, ioc->opcode, ioc->payload_remain); -+ - if (ioc->opcode == QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) { - if (payload_len) { - /* binary frames are passed on */ -@@ -803,7 +814,7 @@ static int qio_channel_websock_decode_payload(QIOChannelWebsock *ioc, - if (payload_len) { - /* echo client status */ - qio_channel_websock_encode_buffer( -- &ioc->encoutput, QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE, -+ ioc, &ioc->encoutput, QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE, - &ioc->encinput); - qio_channel_websock_write_wire(ioc, NULL); - qio_channel_shutdown(ioc->master, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); -@@ -817,7 +828,8 @@ static int qio_channel_websock_decode_payload(QIOChannelWebsock *ioc, - /* ping frames produce an immediate reply */ - buffer_reset(&ioc->ping_reply); - qio_channel_websock_encode_buffer( -- &ioc->ping_reply, QIO_CHANNEL_WEBSOCK_OPCODE_PONG, &ioc->encinput); -+ ioc, &ioc->ping_reply, QIO_CHANNEL_WEBSOCK_OPCODE_PONG, -+ &ioc->encinput); - } /* pong frames are ignored */ - - if (payload_len) { -@@ -1176,6 +1188,7 @@ static int qio_channel_websock_close(QIOChannel *ioc, - { - QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc); - -+ trace_qio_channel_websock_close(ioc); - return qio_channel_close(wioc->master, errp); - } - -diff --git a/io/trace-events b/io/trace-events -index 6459f71..801b5dc 100644 ---- a/io/trace-events -+++ b/io/trace-events -@@ -48,6 +48,11 @@ qio_channel_websock_handshake_pending(void *ioc, int status) "Websock handshake - qio_channel_websock_handshake_reply(void *ioc) "Websock handshake reply ioc=%p" - qio_channel_websock_handshake_fail(void *ioc, const char *msg) "Websock handshake fail ioc=%p err=%s" - qio_channel_websock_handshake_complete(void *ioc) "Websock handshake complete ioc=%p" -+qio_channel_websock_header_partial_decode(void *ioc, size_t payloadlen, unsigned char fin, unsigned char opcode, unsigned char has_mask) "Websocket header decoded ioc=%p payload-len=%zu fin=0x%x opcode=0x%x has_mask=0x%x" -+qio_channel_websock_header_full_decode(void *ioc, size_t headerlen, size_t payloadlen, uint32_t mask) "Websocket header decoded ioc=%p header-len=%zu payload-len=%zu mask=0x%x" -+qio_channel_websock_payload_decode(void *ioc, uint8_t opcode, size_t payload_remain) "Websocket header decoded ioc=%p opcode=0x%x payload-remain=%zu" -+qio_channel_websock_encode(void *ioc, uint8_t opcode, size_t payloadlen, size_t headerlen) "Websocket encoded ioc=%p opcode=0x%x header-len=%zu payload-len=%zu" -+qio_channel_websock_close(void *ioc) "Websocket close ioc=%p" - - # io/channel-command.c - qio_channel_command_new_pid(void *ioc, int writefd, int readfd, int pid) "Command new pid ioc=%p writefd=%d readfd=%d pid=%d" --- -1.8.3.1 - diff --git a/SOURCES/kvm-io-add-trace-points-for-websocket-HTTP-protocol-head.patch b/SOURCES/kvm-io-add-trace-points-for-websocket-HTTP-protocol-head.patch deleted file mode 100644 index 6ca9d28..0000000 --- a/SOURCES/kvm-io-add-trace-points-for-websocket-HTTP-protocol-head.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 8043361fbb2617010aeb3d4009cd05636e2ff715 Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Wed, 20 Dec 2017 17:57:00 +0100 -Subject: [PATCH 20/42] io: add trace points for websocket HTTP protocol - headers - -RH-Author: Daniel P. Berrange -Message-id: <20171220175702.29663-19-berrange@redhat.com> -Patchwork-id: 78471 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 18/20] io: add trace points for websocket HTTP protocol headers -Bugzilla: 1518649 -RH-Acked-by: John Snow -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -Reviewed-by: Eric Blake -Signed-off-by: Daniel P. Berrange -(cherry picked from commit 0efd6c9ec19a1ea6c413424fbea54e1dfe471026) -Signed-off-by: Miroslav Rezanina ---- - io/channel-websock.c | 4 ++++ - io/trace-events | 2 ++ - 2 files changed, 6 insertions(+) - -diff --git a/io/channel-websock.c b/io/channel-websock.c -index 0354845..aa35ef3 100644 ---- a/io/channel-websock.c -+++ b/io/channel-websock.c -@@ -224,6 +224,7 @@ qio_channel_websock_extract_headers(QIOChannelWebsock *ioc, - goto bad_request; - } - *nl = '\0'; -+ trace_qio_channel_websock_http_greeting(ioc, buffer); - - tmp = strchr(buffer, ' '); - if (!tmp) { -@@ -425,6 +426,9 @@ static void qio_channel_websock_handshake_process(QIOChannelWebsock *ioc, - goto bad_request; - } - -+ trace_qio_channel_websock_http_request(ioc, protocols, version, -+ host, connection, upgrade, key); -+ - if (!g_strrstr(protocols, QIO_CHANNEL_WEBSOCK_PROTOCOL_BINARY)) { - error_setg(errp, "No '%s' protocol is supported by client '%s'", - QIO_CHANNEL_WEBSOCK_PROTOCOL_BINARY, protocols); -diff --git a/io/trace-events b/io/trace-events -index 801b5dc..f70bad7 100644 ---- a/io/trace-events -+++ b/io/trace-events -@@ -48,6 +48,8 @@ qio_channel_websock_handshake_pending(void *ioc, int status) "Websock handshake - qio_channel_websock_handshake_reply(void *ioc) "Websock handshake reply ioc=%p" - qio_channel_websock_handshake_fail(void *ioc, const char *msg) "Websock handshake fail ioc=%p err=%s" - qio_channel_websock_handshake_complete(void *ioc) "Websock handshake complete ioc=%p" -+qio_channel_websock_http_greeting(void *ioc, const char *greeting) "Websocket HTTP request ioc=%p greeting='%s'" -+qio_channel_websock_http_request(void *ioc, const char *protocols, const char *version, const char *host, const char *connection, const char *upgrade, const char *key) "Websocket HTTP request ioc=%p protocols='%s' version='%s' host='%s' connection='%s' upgrade='%s' key='%s'" - qio_channel_websock_header_partial_decode(void *ioc, size_t payloadlen, unsigned char fin, unsigned char opcode, unsigned char has_mask) "Websocket header decoded ioc=%p payload-len=%zu fin=0x%x opcode=0x%x has_mask=0x%x" - qio_channel_websock_header_full_decode(void *ioc, size_t headerlen, size_t payloadlen, uint32_t mask) "Websocket header decoded ioc=%p header-len=%zu payload-len=%zu mask=0x%x" - qio_channel_websock_payload_decode(void *ioc, uint8_t opcode, size_t payload_remain) "Websocket header decoded ioc=%p opcode=0x%x payload-remain=%zu" --- -1.8.3.1 - diff --git a/SOURCES/kvm-io-cope-with-websock-Connection-header-having-multip.patch b/SOURCES/kvm-io-cope-with-websock-Connection-header-having-multip.patch deleted file mode 100644 index 3704a20..0000000 --- a/SOURCES/kvm-io-cope-with-websock-Connection-header-having-multip.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 16063b60ae69a93169ab06265dc597072d9bd8ed Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Wed, 20 Dec 2017 17:56:59 +0100 -Subject: [PATCH 19/42] io: cope with websock 'Connection' header having - multiple values - -RH-Author: Daniel P. Berrange -Message-id: <20171220175702.29663-18-berrange@redhat.com> -Patchwork-id: 78470 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 17/20] io: cope with websock 'Connection' header having multiple values -Bugzilla: 1518649 -RH-Acked-by: John Snow -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -The noVNC server sends a header "Connection: keep-alive, Upgrade" which -fails our simple equality test. Split the header on ',', trim whitespace -and then check for 'upgrade' token. - -Reviewed-by: Eric Blake -Signed-off-by: Daniel P. Berrange -(cherry picked from commit 6d5d23b00709510d55711661c7ca41408fd9934e) -Signed-off-by: Miroslav Rezanina ---- - io/channel-websock.c | 14 +++++++++++++- - 1 file changed, 13 insertions(+), 1 deletion(-) - -diff --git a/io/channel-websock.c b/io/channel-websock.c -index e82b1be..0354845 100644 ---- a/io/channel-websock.c -+++ b/io/channel-websock.c -@@ -374,6 +374,9 @@ static void qio_channel_websock_handshake_process(QIOChannelWebsock *ioc, - size_t nhdrs = G_N_ELEMENTS(hdrs); - const char *protocols = NULL, *version = NULL, *key = NULL, - *host = NULL, *connection = NULL, *upgrade = NULL; -+ char **connectionv; -+ bool upgraded = false; -+ size_t i; - - nhdrs = qio_channel_websock_extract_headers(ioc, buffer, hdrs, nhdrs, errp); - if (!nhdrs) { -@@ -440,7 +443,16 @@ static void qio_channel_websock_handshake_process(QIOChannelWebsock *ioc, - goto bad_request; - } - -- if (strcasecmp(connection, QIO_CHANNEL_WEBSOCK_CONNECTION_UPGRADE) != 0) { -+ connectionv = g_strsplit(connection, ",", 0); -+ for (i = 0; connectionv != NULL && connectionv[i] != NULL; i++) { -+ g_strstrip(connectionv[i]); -+ if (strcasecmp(connectionv[i], -+ QIO_CHANNEL_WEBSOCK_CONNECTION_UPGRADE) == 0) { -+ upgraded = true; -+ } -+ } -+ g_strfreev(connectionv); -+ if (!upgraded) { - error_setg(errp, "No connection upgrade requested '%s'", connection); - goto bad_request; - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-io-fix-mem-leak-in-websock-error-path.patch b/SOURCES/kvm-io-fix-mem-leak-in-websock-error-path.patch deleted file mode 100644 index dd6c9c9..0000000 --- a/SOURCES/kvm-io-fix-mem-leak-in-websock-error-path.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 65fbe38c421960d5ad73e25b58593f58411422b8 Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Wed, 20 Dec 2017 17:57:01 +0100 -Subject: [PATCH 21/42] io: fix mem leak in websock error path - -RH-Author: Daniel P. Berrange -Message-id: <20171220175702.29663-20-berrange@redhat.com> -Patchwork-id: 78472 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 19/20] io: fix mem leak in websock error path -Bugzilla: 1518649 -RH-Acked-by: John Snow -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -Coverity pointed out the 'date' is not free()d in the error -path - -Reviewed-by: Eric Blake -Signed-off-by: Daniel P. Berrange -(cherry picked from commit 7fc3fcefe2fc5966c6aa1ef4f10e9740d8d73bf2) -Signed-off-by: Miroslav Rezanina ---- - io/channel-websock.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/io/channel-websock.c b/io/channel-websock.c -index aa35ef3..df2c3a9 100644 ---- a/io/channel-websock.c -+++ b/io/channel-websock.c -@@ -341,7 +341,7 @@ static void qio_channel_websock_handshake_send_res_ok(QIOChannelWebsock *ioc, - char combined_key[QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN + - QIO_CHANNEL_WEBSOCK_GUID_LEN + 1]; - char *accept = NULL; -- char *date = qio_channel_websock_date_str(); -+ char *date = NULL; - - g_strlcpy(combined_key, key, QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN + 1); - g_strlcat(combined_key, QIO_CHANNEL_WEBSOCK_GUID, -@@ -360,6 +360,7 @@ static void qio_channel_websock_handshake_send_res_ok(QIOChannelWebsock *ioc, - return; - } - -+ date = qio_channel_websock_date_str(); - qio_channel_websock_handshake_send_res( - ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_OK, date, accept); - --- -1.8.3.1 - diff --git a/SOURCES/kvm-io-get-rid-of-bounce-buffering-in-websock-write-path.patch b/SOURCES/kvm-io-get-rid-of-bounce-buffering-in-websock-write-path.patch deleted file mode 100644 index da22dee..0000000 --- a/SOURCES/kvm-io-get-rid-of-bounce-buffering-in-websock-write-path.patch +++ /dev/null @@ -1,164 +0,0 @@ -From 4550459a8e915a74dfbeb97ab4b645f72165079c Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Wed, 20 Dec 2017 17:56:58 +0100 -Subject: [PATCH 18/42] io: get rid of bounce buffering in websock write path - -RH-Author: Daniel P. Berrange -Message-id: <20171220175702.29663-17-berrange@redhat.com> -Patchwork-id: 78469 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 16/20] io: get rid of bounce buffering in websock write path -Bugzilla: 1518649 -RH-Acked-by: John Snow -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -Currently most outbound I/O on the websock channel gets copied into the -rawoutput buffer, and then immediately copied again into the encoutput -buffer, with a header prepended. Now that qio_channel_websock_encode -accepts a struct iovec, we can trivially remove this bounce buffering -and write directly to encoutput. - -In doing so, we also now correctly validate the encoutput size against -the QIO_CHANNEL_WEBSOCK_MAX_BUFFER limit. - -Reviewed-by: Eric Blake -Signed-off-by: Daniel P. Berrange -(cherry picked from commit 8dfd5f96515ca20c4eb109cb0ee28e2bb32fc505) - -NB, include of iov.h was pushed into previous patch to fix bisect -buld. - -Signed-off-by: Miroslav Rezanina ---- - include/io/channel-websock.h | 1 - - io/channel-websock.c | 63 +++++++++++++++++++------------------------- - 2 files changed, 27 insertions(+), 37 deletions(-) - -diff --git a/include/io/channel-websock.h b/include/io/channel-websock.h -index 3762707..a7e5e92 100644 ---- a/include/io/channel-websock.h -+++ b/include/io/channel-websock.h -@@ -59,7 +59,6 @@ struct QIOChannelWebsock { - Buffer encinput; - Buffer encoutput; - Buffer rawinput; -- Buffer rawoutput; - size_t payload_remain; - size_t pong_remain; - QIOChannelWebsockMask mask; -diff --git a/io/channel-websock.c b/io/channel-websock.c -index 11b6039..e82b1be 100644 ---- a/io/channel-websock.c -+++ b/io/channel-websock.c -@@ -634,19 +634,22 @@ static ssize_t qio_channel_websock_write_wire(QIOChannelWebsock *, Error **); - static void qio_channel_websock_write_close(QIOChannelWebsock *ioc, - uint16_t code, const char *reason) - { -- struct iovec iov; -- buffer_reserve(&ioc->rawoutput, 2 + (reason ? strlen(reason) : 0)); -- *(uint16_t *)(ioc->rawoutput.buffer + ioc->rawoutput.offset) = -- cpu_to_be16(code); -- ioc->rawoutput.offset += 2; -+ struct iovec iov[2] = { -+ { .iov_base = &code, .iov_len = sizeof(code) }, -+ }; -+ size_t niov = 1; -+ size_t size = iov[0].iov_len; -+ -+ cpu_to_be16s(&code); -+ - if (reason) { -- buffer_append(&ioc->rawoutput, reason, strlen(reason)); -+ iov[1].iov_base = (void *)reason; -+ iov[1].iov_len = strlen(reason); -+ size += iov[1].iov_len; -+ niov++; - } -- iov.iov_base = ioc->rawoutput.buffer; -- iov.iov_len = ioc->rawoutput.offset; - qio_channel_websock_encode(ioc, QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE, -- &iov, 1, iov.iov_len); -- buffer_reset(&ioc->rawoutput); -+ iov, niov, size); - qio_channel_websock_write_wire(ioc, NULL); - qio_channel_shutdown(ioc->master, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); - } -@@ -894,7 +897,6 @@ static void qio_channel_websock_finalize(Object *obj) - buffer_free(&ioc->encinput); - buffer_free(&ioc->encoutput); - buffer_free(&ioc->rawinput); -- buffer_free(&ioc->rawoutput); - object_unref(OBJECT(ioc->master)); - if (ioc->io_tag) { - g_source_remove(ioc->io_tag); -@@ -1104,8 +1106,8 @@ static ssize_t qio_channel_websock_writev(QIOChannel *ioc, - Error **errp) - { - QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc); -- size_t i; -- ssize_t done = 0; -+ ssize_t want = iov_size(iov, niov); -+ ssize_t avail; - ssize_t ret; - - if (wioc->io_err) { -@@ -1118,32 +1120,21 @@ static ssize_t qio_channel_websock_writev(QIOChannel *ioc, - return -1; - } - -- for (i = 0; i < niov; i++) { -- size_t want = iov[i].iov_len; -- if ((want + wioc->rawoutput.offset) > QIO_CHANNEL_WEBSOCK_MAX_BUFFER) { -- want = (QIO_CHANNEL_WEBSOCK_MAX_BUFFER - wioc->rawoutput.offset); -- } -- if (want == 0) { -- goto done; -- } -- -- buffer_reserve(&wioc->rawoutput, want); -- buffer_append(&wioc->rawoutput, iov[i].iov_base, want); -- done += want; -- if (want < iov[i].iov_len) { -- break; -- } -+ avail = wioc->encoutput.offset >= QIO_CHANNEL_WEBSOCK_MAX_BUFFER ? -+ 0 : (QIO_CHANNEL_WEBSOCK_MAX_BUFFER - wioc->encoutput.offset); -+ if (want > avail) { -+ want = avail; - } - -- done: -- if (wioc->rawoutput.offset) { -- struct iovec iov = { .iov_base = wioc->rawoutput.buffer, -- .iov_len = wioc->rawoutput.offset }; -+ if (want) { - qio_channel_websock_encode(wioc, - QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME, -- &iov, 1, iov.iov_len); -- buffer_reset(&wioc->rawoutput); -+ iov, niov, want); - } -+ -+ /* Even if want == 0, we'll try write_wire in case there's -+ * pending data we could usefully flush out -+ */ - ret = qio_channel_websock_write_wire(wioc, errp); - if (ret < 0 && - ret != QIO_CHANNEL_ERR_BLOCK) { -@@ -1153,11 +1144,11 @@ static ssize_t qio_channel_websock_writev(QIOChannel *ioc, - - qio_channel_websock_set_watch(wioc); - -- if (done == 0) { -+ if (want == 0) { - return QIO_CHANNEL_ERR_BLOCK; - } - -- return done; -+ return want; - } - - static int qio_channel_websock_set_blocking(QIOChannel *ioc, --- -1.8.3.1 - diff --git a/SOURCES/kvm-io-get-rid-of-qio_channel_websock_encode-helper-meth.patch b/SOURCES/kvm-io-get-rid-of-qio_channel_websock_encode-helper-meth.patch deleted file mode 100644 index 9916af1..0000000 --- a/SOURCES/kvm-io-get-rid-of-qio_channel_websock_encode-helper-meth.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 87e23865f2383a8befcba2908dcd56c708a2fbb8 Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Wed, 20 Dec 2017 17:56:56 +0100 -Subject: [PATCH 16/42] io: get rid of qio_channel_websock_encode helper method - -RH-Author: Daniel P. Berrange -Message-id: <20171220175702.29663-15-berrange@redhat.com> -Patchwork-id: 78467 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 14/20] io: get rid of qio_channel_websock_encode helper method -Bugzilla: 1518649 -RH-Acked-by: John Snow -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -The qio_channel_websock_encode method is only used in one place, -everything else calls qio_channel_websock_encode_buffer directly. -It can also be pushed up a level into the qio_channel_websock_writev -method, since every other caller of qio_channel_websock_write_wire -has already filled encoutput. - -Reviewed-by: Eric Blake -Signed-off-by: Daniel P. Berrange -(cherry picked from commit bac6c95415788c03590542eb244c723a18d0771c) - -NB, in qio_channel_websock_writev s/ioc/wioc/ to fix a typo -upstream that would break builds during git bisect. - -Signed-off-by: Miroslav Rezanina ---- - io/channel-websock.c | 20 ++++++-------------- - 1 file changed, 6 insertions(+), 14 deletions(-) - -diff --git a/io/channel-websock.c b/io/channel-websock.c -index 6083f74..403b72b 100644 ---- a/io/channel-websock.c -+++ b/io/channel-websock.c -@@ -616,18 +616,6 @@ static void qio_channel_websock_encode_buffer(QIOChannelWebsock *ioc, - } - - --static void qio_channel_websock_encode(QIOChannelWebsock *ioc) --{ -- if (!ioc->rawoutput.offset) { -- return; -- } -- qio_channel_websock_encode_buffer( -- ioc, &ioc->encoutput, QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME, -- &ioc->rawoutput); -- buffer_reset(&ioc->rawoutput); --} -- -- - static ssize_t qio_channel_websock_write_wire(QIOChannelWebsock *, Error **); - - -@@ -948,8 +936,6 @@ static ssize_t qio_channel_websock_write_wire(QIOChannelWebsock *ioc, - ssize_t ret; - ssize_t done = 0; - -- qio_channel_websock_encode(ioc); -- - while (ioc->encoutput.offset > 0) { - ret = qio_channel_write(ioc->master, - (char *)ioc->encoutput.buffer, -@@ -1134,6 +1120,12 @@ static ssize_t qio_channel_websock_writev(QIOChannel *ioc, - } - - done: -+ if (wioc->rawoutput.offset) { -+ qio_channel_websock_encode_buffer( -+ wioc, &wioc->encoutput, QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME, -+ &wioc->rawoutput); -+ buffer_reset(&wioc->rawoutput); -+ } - ret = qio_channel_websock_write_wire(wioc, errp); - if (ret < 0 && - ret != QIO_CHANNEL_ERR_BLOCK) { --- -1.8.3.1 - diff --git a/SOURCES/kvm-io-include-full-error-message-in-websocket-handshake.patch b/SOURCES/kvm-io-include-full-error-message-in-websocket-handshake.patch deleted file mode 100644 index be16f1e..0000000 --- a/SOURCES/kvm-io-include-full-error-message-in-websocket-handshake.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 0ac33e4a0edae8877e2d400b9a3c5e7af902668f Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Wed, 20 Dec 2017 17:56:44 +0100 -Subject: [PATCH 04/42] io: include full error message in websocket handshake - trace -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Daniel P. Berrange -Message-id: <20171220175702.29663-3-berrange@redhat.com> -Patchwork-id: 78458 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 02/20] io: include full error message in websocket handshake trace -Bugzilla: 1518649 -RH-Acked-by: John Snow -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -When the websocket handshake fails it is useful to log the real -error message via the trace points for debugging purposes. - -Fixes bug: #1715186 - -Reviewed-by: Philippe Mathieu-Daudé -Signed-off-by: Daniel P. Berrange -(cherry picked from commit 3a3f8705962c8c8a47a9b981ffd5aab7274ad508) -Signed-off-by: Miroslav Rezanina ---- - io/channel-websock.c | 7 ++++--- - io/trace-events | 2 +- - 2 files changed, 5 insertions(+), 4 deletions(-) - -diff --git a/io/channel-websock.c b/io/channel-websock.c -index f5fac5b..6ddcec1 100644 ---- a/io/channel-websock.c -+++ b/io/channel-websock.c -@@ -507,7 +507,7 @@ static gboolean qio_channel_websock_handshake_send(QIOChannel *ioc, - &err); - - if (ret < 0) { -- trace_qio_channel_websock_handshake_fail(ioc); -+ trace_qio_channel_websock_handshake_fail(ioc, error_get_pretty(err)); - qio_task_set_error(task, err); - qio_task_complete(task); - return FALSE; -@@ -516,7 +516,8 @@ static gboolean qio_channel_websock_handshake_send(QIOChannel *ioc, - buffer_advance(&wioc->encoutput, ret); - if (wioc->encoutput.offset == 0) { - if (wioc->io_err) { -- trace_qio_channel_websock_handshake_fail(ioc); -+ trace_qio_channel_websock_handshake_fail( -+ ioc, error_get_pretty(wioc->io_err)); - qio_task_set_error(task, wioc->io_err); - wioc->io_err = NULL; - qio_task_complete(task); -@@ -547,7 +548,7 @@ static gboolean qio_channel_websock_handshake_io(QIOChannel *ioc, - * client connection, as most of the time we have an - * HTTP 4xx err response to send instead - */ -- trace_qio_channel_websock_handshake_fail(ioc); -+ trace_qio_channel_websock_handshake_fail(ioc, error_get_pretty(err)); - qio_task_set_error(task, err); - qio_task_complete(task); - return FALSE; -diff --git a/io/trace-events b/io/trace-events -index 3d23369..6459f71 100644 ---- a/io/trace-events -+++ b/io/trace-events -@@ -46,7 +46,7 @@ qio_channel_websock_new_server(void *ioc, void *master) "Websock new client ioc= - qio_channel_websock_handshake_start(void *ioc) "Websock handshake start ioc=%p" - qio_channel_websock_handshake_pending(void *ioc, int status) "Websock handshake pending ioc=%p status=%d" - qio_channel_websock_handshake_reply(void *ioc) "Websock handshake reply ioc=%p" --qio_channel_websock_handshake_fail(void *ioc) "Websock handshake fail ioc=%p" -+qio_channel_websock_handshake_fail(void *ioc, const char *msg) "Websock handshake fail ioc=%p err=%s" - qio_channel_websock_handshake_complete(void *ioc) "Websock handshake complete ioc=%p" - - # io/channel-command.c --- -1.8.3.1 - diff --git a/SOURCES/kvm-io-monitor-encoutput-buffer-size-from-websocket-GSou.patch b/SOURCES/kvm-io-monitor-encoutput-buffer-size-from-websocket-GSou.patch deleted file mode 100644 index 481d9fa..0000000 --- a/SOURCES/kvm-io-monitor-encoutput-buffer-size-from-websocket-GSou.patch +++ /dev/null @@ -1,66 +0,0 @@ -From c3a99fb2c831c2f3da069359a9a8a0c734923669 Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Wed, 20 Dec 2017 17:56:54 +0100 -Subject: [PATCH 14/42] io: monitor encoutput buffer size from websocket - GSource - -RH-Author: Daniel P. Berrange -Message-id: <20171220175702.29663-13-berrange@redhat.com> -Patchwork-id: 78466 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 12/20] io: monitor encoutput buffer size from websocket GSource -Bugzilla: 1518650 -RH-Acked-by: John Snow -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -The websocket GSource is monitoring the size of the rawoutput -buffer to determine if the channel can accepts more writes. -The rawoutput buffer, however, is merely a temporary staging -buffer before data is copied into the encoutput buffer. Thus -its size will always be zero when the GSource runs. - -This flaw causes the encoutput buffer to grow without bound -if the other end of the underlying data channel doesn't -read data being sent. This can be seen with VNC if a client -is on a slow WAN link and the guest OS is sending many screen -updates. A malicious VNC client can act like it is on a slow -link by playing a video in the guest and then reading data -very slowly, causing QEMU host memory to expand arbitrarily. - -This issue is assigned CVE-2017-15268, publically reported in - - https://bugs.launchpad.net/qemu/+bug/1718964 - -Reviewed-by: Eric Blake -Signed-off-by: Daniel P. Berrange -(cherry picked from commit a7b20a8efa28e5f22c26c06cd06c2f12bc863493) -Signed-off-by: Miroslav Rezanina ---- - io/channel-websock.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/io/channel-websock.c b/io/channel-websock.c -index d1d471f..04bcc05 100644 ---- a/io/channel-websock.c -+++ b/io/channel-websock.c -@@ -28,7 +28,7 @@ - #include - - --/* Max amount to allow in rawinput/rawoutput buffers */ -+/* Max amount to allow in rawinput/encoutput buffers */ - #define QIO_CHANNEL_WEBSOCK_MAX_BUFFER 8192 - - #define QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN 24 -@@ -1208,7 +1208,7 @@ qio_channel_websock_source_check(GSource *source) - if (wsource->wioc->rawinput.offset || wsource->wioc->io_eof) { - cond |= G_IO_IN; - } -- if (wsource->wioc->rawoutput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER) { -+ if (wsource->wioc->encoutput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER) { - cond |= G_IO_OUT; - } - --- -1.8.3.1 - diff --git a/SOURCES/kvm-io-pass-a-struct-iovec-into-qio_channel_websock_enco.patch b/SOURCES/kvm-io-pass-a-struct-iovec-into-qio_channel_websock_enco.patch deleted file mode 100644 index 25feaa5..0000000 --- a/SOURCES/kvm-io-pass-a-struct-iovec-into-qio_channel_websock_enco.patch +++ /dev/null @@ -1,172 +0,0 @@ -From 33c5c11a12bba1c60e75f716d7ddf09b99dc372a Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Wed, 20 Dec 2017 17:56:57 +0100 -Subject: [PATCH 17/42] io: pass a struct iovec into qio_channel_websock_encode - -RH-Author: Daniel P. Berrange -Message-id: <20171220175702.29663-16-berrange@redhat.com> -Patchwork-id: 78468 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 15/20] io: pass a struct iovec into qio_channel_websock_encode -Bugzilla: 1518649 -RH-Acked-by: John Snow -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -Instead of requiring use of another Buffer, pass a struct iovec -into qio_channel_websock_encode, which gives callers more -flexibility in how they process data. - -Reviewed-by: Eric Blake -Signed-off-by: Daniel P. Berrange -(cherry picked from commit fb74e5903914b9ec8c80b6f7a35da000f9f92ae7) - -NB, slight context difference due to typo fixup in previous -patch. Also pulled in iov.h include, again, to fix bisect build - -Signed-off-by: Miroslav Rezanina ---- - io/channel-websock.c | 68 +++++++++++++++++++++++++++++++++------------------- - 1 file changed, 43 insertions(+), 25 deletions(-) - -diff --git a/io/channel-websock.c b/io/channel-websock.c -index 403b72b..11b6039 100644 ---- a/io/channel-websock.c -+++ b/io/channel-websock.c -@@ -24,6 +24,7 @@ - #include "io/channel-websock.h" - #include "crypto/hash.h" - #include "trace.h" -+#include "qemu/iov.h" - - #include - -@@ -582,37 +583,48 @@ static gboolean qio_channel_websock_handshake_io(QIOChannel *ioc, - } - - --static void qio_channel_websock_encode_buffer(QIOChannelWebsock *ioc, -- Buffer *output, -- uint8_t opcode, Buffer *buffer) -+static void qio_channel_websock_encode(QIOChannelWebsock *ioc, -+ uint8_t opcode, -+ const struct iovec *iov, -+ size_t niov, -+ size_t size) - { - size_t header_size; -+ size_t i; - union { - char buf[QIO_CHANNEL_WEBSOCK_HEADER_LEN_64_BIT]; - QIOChannelWebsockHeader ws; - } header; - -+ assert(size <= iov_size(iov, niov)); -+ - header.ws.b0 = QIO_CHANNEL_WEBSOCK_HEADER_FIELD_FIN | - (opcode & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE); -- if (buffer->offset < QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_THRESHOLD_7_BIT) { -- header.ws.b1 = (uint8_t)buffer->offset; -+ if (size < QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_THRESHOLD_7_BIT) { -+ header.ws.b1 = (uint8_t)size; - header_size = QIO_CHANNEL_WEBSOCK_HEADER_LEN_7_BIT; -- } else if (buffer->offset < -- QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_THRESHOLD_16_BIT) { -+ } else if (size < QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_THRESHOLD_16_BIT) { - header.ws.b1 = QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_16_BIT; -- header.ws.u.s16.l16 = cpu_to_be16((uint16_t)buffer->offset); -+ header.ws.u.s16.l16 = cpu_to_be16((uint16_t)size); - header_size = QIO_CHANNEL_WEBSOCK_HEADER_LEN_16_BIT; - } else { - header.ws.b1 = QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_64_BIT; -- header.ws.u.s64.l64 = cpu_to_be64(buffer->offset); -+ header.ws.u.s64.l64 = cpu_to_be64(size); - header_size = QIO_CHANNEL_WEBSOCK_HEADER_LEN_64_BIT; - } - header_size -= QIO_CHANNEL_WEBSOCK_HEADER_LEN_MASK; - -- trace_qio_channel_websock_encode(ioc, opcode, header_size, buffer->offset); -- buffer_reserve(output, header_size + buffer->offset); -- buffer_append(output, header.buf, header_size); -- buffer_append(output, buffer->buffer, buffer->offset); -+ trace_qio_channel_websock_encode(ioc, opcode, header_size, size); -+ buffer_reserve(&ioc->encoutput, header_size + size); -+ buffer_append(&ioc->encoutput, header.buf, header_size); -+ for (i = 0; i < niov && size != 0; i++) { -+ size_t want = iov[i].iov_len; -+ if (want > size) { -+ want = size; -+ } -+ buffer_append(&ioc->encoutput, iov[i].iov_base, want); -+ size -= want; -+ } - } - - -@@ -622,6 +634,7 @@ static ssize_t qio_channel_websock_write_wire(QIOChannelWebsock *, Error **); - static void qio_channel_websock_write_close(QIOChannelWebsock *ioc, - uint16_t code, const char *reason) - { -+ struct iovec iov; - buffer_reserve(&ioc->rawoutput, 2 + (reason ? strlen(reason) : 0)); - *(uint16_t *)(ioc->rawoutput.buffer + ioc->rawoutput.offset) = - cpu_to_be16(code); -@@ -629,9 +642,10 @@ static void qio_channel_websock_write_close(QIOChannelWebsock *ioc, - if (reason) { - buffer_append(&ioc->rawoutput, reason, strlen(reason)); - } -- qio_channel_websock_encode_buffer( -- ioc, &ioc->encoutput, QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE, -- &ioc->rawoutput); -+ iov.iov_base = ioc->rawoutput.buffer; -+ iov.iov_len = ioc->rawoutput.offset; -+ qio_channel_websock_encode(ioc, QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE, -+ &iov, 1, iov.iov_len); - buffer_reset(&ioc->rawoutput); - qio_channel_websock_write_wire(ioc, NULL); - qio_channel_shutdown(ioc->master, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); -@@ -801,9 +815,10 @@ static int qio_channel_websock_decode_payload(QIOChannelWebsock *ioc, - error_setg(errp, "websocket closed by peer"); - if (payload_len) { - /* echo client status */ -- qio_channel_websock_encode_buffer( -- ioc, &ioc->encoutput, QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE, -- &ioc->encinput); -+ struct iovec iov = { .iov_base = ioc->encinput.buffer, -+ .iov_len = ioc->encinput.offset }; -+ qio_channel_websock_encode(ioc, QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE, -+ &iov, 1, iov.iov_len); - qio_channel_websock_write_wire(ioc, NULL); - qio_channel_shutdown(ioc->master, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); - } else { -@@ -816,9 +831,10 @@ static int qio_channel_websock_decode_payload(QIOChannelWebsock *ioc, - /* ping frames produce an immediate reply, as long as we've not still - * got a previous pong queued, in which case we drop the new pong */ - if (ioc->pong_remain == 0) { -- qio_channel_websock_encode_buffer( -- ioc, &ioc->encoutput, QIO_CHANNEL_WEBSOCK_OPCODE_PONG, -- &ioc->encinput); -+ struct iovec iov = { .iov_base = ioc->encinput.buffer, -+ .iov_len = ioc->encinput.offset }; -+ qio_channel_websock_encode(ioc, QIO_CHANNEL_WEBSOCK_OPCODE_PONG, -+ &iov, 1, iov.iov_len); - ioc->pong_remain = ioc->encoutput.offset; - } - } /* pong frames are ignored */ -@@ -1121,9 +1137,11 @@ static ssize_t qio_channel_websock_writev(QIOChannel *ioc, - - done: - if (wioc->rawoutput.offset) { -- qio_channel_websock_encode_buffer( -- wioc, &wioc->encoutput, QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME, -- &wioc->rawoutput); -+ struct iovec iov = { .iov_base = wioc->rawoutput.buffer, -+ .iov_len = wioc->rawoutput.offset }; -+ qio_channel_websock_encode(wioc, -+ QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME, -+ &iov, 1, iov.iov_len); - buffer_reset(&wioc->rawoutput); - } - ret = qio_channel_websock_write_wire(wioc, errp); --- -1.8.3.1 - diff --git a/SOURCES/kvm-io-send-proper-HTTP-response-for-websocket-errors.patch b/SOURCES/kvm-io-send-proper-HTTP-response-for-websocket-errors.patch deleted file mode 100644 index 6bc8594..0000000 --- a/SOURCES/kvm-io-send-proper-HTTP-response-for-websocket-errors.patch +++ /dev/null @@ -1,435 +0,0 @@ -From 062b6fd62b387f4ea67f800ca956c87b28451a9c Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Wed, 20 Dec 2017 17:56:43 +0100 -Subject: [PATCH 03/42] io: send proper HTTP response for websocket errors -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Daniel P. Berrange -Message-id: <20171220175702.29663-2-berrange@redhat.com> -Patchwork-id: 78454 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 01/20] io: send proper HTTP response for websocket errors -Bugzilla: 1518649 -RH-Acked-by: John Snow -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -When any error occurs while processing the websockets handshake, -QEMU just terminates the connection abruptly. This is in violation -of the HTTP specs and does not help the client understand what they -did wrong. This is particularly bad when the client gives the wrong -path, as a "404 Not Found" would be very helpful. - -Refactor the handshake code so that it always sends a response to -the client unless there was an I/O error. - -Fixes bug: #1715186 - -Reviewed-by: Philippe Mathieu-Daudé -Signed-off-by: Daniel P. Berrange -(cherry picked from commit f69a8bde29354493ff8aea64cc9cb3b531d16337) -Signed-off-by: Miroslav Rezanina ---- - io/channel-websock.c | 185 ++++++++++++++++++++++++++++++++++++++------------- - 1 file changed, 139 insertions(+), 46 deletions(-) - -diff --git a/io/channel-websock.c b/io/channel-websock.c -index 5a3badb..f5fac5b 100644 ---- a/io/channel-websock.c -+++ b/io/channel-websock.c -@@ -25,6 +25,8 @@ - #include "crypto/hash.h" - #include "trace.h" - -+#include -+ - - /* Max amount to allow in rawinput/rawoutput buffers */ - #define QIO_CHANNEL_WEBSOCK_MAX_BUFFER 8192 -@@ -44,13 +46,40 @@ - #define QIO_CHANNEL_WEBSOCK_CONNECTION_UPGRADE "Upgrade" - #define QIO_CHANNEL_WEBSOCK_UPGRADE_WEBSOCKET "websocket" - --#define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RESPONSE \ -+#define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON \ -+ "Server: QEMU VNC\r\n" \ -+ "Date: %s\r\n" -+ -+#define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_OK \ - "HTTP/1.1 101 Switching Protocols\r\n" \ -+ QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON \ - "Upgrade: websocket\r\n" \ - "Connection: Upgrade\r\n" \ - "Sec-WebSocket-Accept: %s\r\n" \ - "Sec-WebSocket-Protocol: binary\r\n" \ - "\r\n" -+#define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_NOT_FOUND \ -+ "HTTP/1.1 404 Not Found\r\n" \ -+ QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON \ -+ "Connection: close\r\n" \ -+ "\r\n" -+#define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_BAD_REQUEST \ -+ "HTTP/1.1 400 Bad Request\r\n" \ -+ QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON \ -+ "Connection: close\r\n" \ -+ "Sec-WebSocket-Version: " \ -+ QIO_CHANNEL_WEBSOCK_SUPPORTED_VERSION \ -+ "\r\n" -+#define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_SERVER_ERR \ -+ "HTTP/1.1 500 Internal Server Error\r\n" \ -+ QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON \ -+ "Connection: close\r\n" \ -+ "\r\n" -+#define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_TOO_LARGE \ -+ "HTTP/1.1 403 Request Entity Too Large\r\n" \ -+ QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON \ -+ "Connection: close\r\n" \ -+ "\r\n" - #define QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM "\r\n" - #define QIO_CHANNEL_WEBSOCK_HANDSHAKE_END "\r\n\r\n" - #define QIO_CHANNEL_WEBSOCK_SUPPORTED_VERSION "13" -@@ -123,8 +152,46 @@ enum { - QIO_CHANNEL_WEBSOCK_OPCODE_PONG = 0xA - }; - -+static void qio_channel_websock_handshake_send_res(QIOChannelWebsock *ioc, -+ const char *resmsg, -+ ...) -+{ -+ va_list vargs; -+ char *response; -+ size_t responselen; -+ -+ va_start(vargs, resmsg); -+ response = g_strdup_vprintf(resmsg, vargs); -+ responselen = strlen(response); -+ buffer_reserve(&ioc->encoutput, responselen); -+ buffer_append(&ioc->encoutput, response, responselen); -+ va_end(vargs); -+} -+ -+static gchar *qio_channel_websock_date_str(void) -+{ -+ struct tm tm; -+ time_t now = time(NULL); -+ char datebuf[128]; -+ -+ gmtime_r(&now, &tm); -+ -+ strftime(datebuf, sizeof(datebuf), "%a, %d %b %Y %H:%M:%S GMT", &tm); -+ -+ return g_strdup(datebuf); -+} -+ -+static void qio_channel_websock_handshake_send_res_err(QIOChannelWebsock *ioc, -+ const char *resdata) -+{ -+ char *date = qio_channel_websock_date_str(); -+ qio_channel_websock_handshake_send_res(ioc, resdata, date); -+ g_free(date); -+} -+ - static size_t --qio_channel_websock_extract_headers(char *buffer, -+qio_channel_websock_extract_headers(QIOChannelWebsock *ioc, -+ char *buffer, - QIOChannelWebsockHTTPHeader *hdrs, - size_t nhdrsalloc, - Error **errp) -@@ -145,7 +212,7 @@ qio_channel_websock_extract_headers(char *buffer, - nl = strstr(buffer, QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM); - if (!nl) { - error_setg(errp, "Missing HTTP header delimiter"); -- return 0; -+ goto bad_request; - } - *nl = '\0'; - -@@ -158,18 +225,20 @@ qio_channel_websock_extract_headers(char *buffer, - - if (!g_str_equal(buffer, QIO_CHANNEL_WEBSOCK_HTTP_METHOD)) { - error_setg(errp, "Unsupported HTTP method %s", buffer); -- return 0; -+ goto bad_request; - } - - buffer = tmp + 1; - tmp = strchr(buffer, ' '); - if (!tmp) { - error_setg(errp, "Missing HTTP version delimiter"); -- return 0; -+ goto bad_request; - } - *tmp = '\0'; - - if (!g_str_equal(buffer, QIO_CHANNEL_WEBSOCK_HTTP_PATH)) { -+ qio_channel_websock_handshake_send_res_err( -+ ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_NOT_FOUND); - error_setg(errp, "Unexpected HTTP path %s", buffer); - return 0; - } -@@ -178,7 +247,7 @@ qio_channel_websock_extract_headers(char *buffer, - - if (!g_str_equal(buffer, QIO_CHANNEL_WEBSOCK_HTTP_VERSION)) { - error_setg(errp, "Unsupported HTTP version %s", buffer); -- return 0; -+ goto bad_request; - } - - buffer = nl + strlen(QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM); -@@ -203,7 +272,7 @@ qio_channel_websock_extract_headers(char *buffer, - sep = strchr(buffer, ':'); - if (!sep) { - error_setg(errp, "Malformed HTTP header"); -- return 0; -+ goto bad_request; - } - *sep = '\0'; - sep++; -@@ -213,7 +282,7 @@ qio_channel_websock_extract_headers(char *buffer, - - if (nhdrs >= nhdrsalloc) { - error_setg(errp, "Too many HTTP headers"); -- return 0; -+ goto bad_request; - } - - hdr = &hdrs[nhdrs++]; -@@ -231,6 +300,11 @@ qio_channel_websock_extract_headers(char *buffer, - } while (nl != NULL); - - return nhdrs; -+ -+ bad_request: -+ qio_channel_websock_handshake_send_res_err( -+ ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_BAD_REQUEST); -+ return 0; - } - - static const char * -@@ -250,14 +324,14 @@ qio_channel_websock_find_header(QIOChannelWebsockHTTPHeader *hdrs, - } - - --static int qio_channel_websock_handshake_send_response(QIOChannelWebsock *ioc, -- const char *key, -- Error **errp) -+static void qio_channel_websock_handshake_send_res_ok(QIOChannelWebsock *ioc, -+ const char *key, -+ Error **errp) - { - char combined_key[QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN + - QIO_CHANNEL_WEBSOCK_GUID_LEN + 1]; -- char *accept = NULL, *response = NULL; -- size_t responselen; -+ char *accept = NULL; -+ char *date = qio_channel_websock_date_str(); - - g_strlcpy(combined_key, key, QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN + 1); - g_strlcat(combined_key, QIO_CHANNEL_WEBSOCK_GUID, -@@ -271,105 +345,108 @@ static int qio_channel_websock_handshake_send_response(QIOChannelWebsock *ioc, - QIO_CHANNEL_WEBSOCK_GUID_LEN, - &accept, - errp) < 0) { -- return -1; -+ qio_channel_websock_handshake_send_res_err( -+ ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_SERVER_ERR); -+ return; - } - -- response = g_strdup_printf(QIO_CHANNEL_WEBSOCK_HANDSHAKE_RESPONSE, accept); -- responselen = strlen(response); -- buffer_reserve(&ioc->encoutput, responselen); -- buffer_append(&ioc->encoutput, response, responselen); -+ qio_channel_websock_handshake_send_res( -+ ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_OK, date, accept); - -+ g_free(date); - g_free(accept); -- g_free(response); -- -- return 0; - } - --static int qio_channel_websock_handshake_process(QIOChannelWebsock *ioc, -- char *buffer, -- Error **errp) -+static void qio_channel_websock_handshake_process(QIOChannelWebsock *ioc, -+ char *buffer, -+ Error **errp) - { - QIOChannelWebsockHTTPHeader hdrs[32]; - size_t nhdrs = G_N_ELEMENTS(hdrs); - const char *protocols = NULL, *version = NULL, *key = NULL, - *host = NULL, *connection = NULL, *upgrade = NULL; - -- nhdrs = qio_channel_websock_extract_headers(buffer, hdrs, nhdrs, errp); -+ nhdrs = qio_channel_websock_extract_headers(ioc, buffer, hdrs, nhdrs, errp); - if (!nhdrs) { -- return -1; -+ return; - } - - protocols = qio_channel_websock_find_header( - hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_PROTOCOL); - if (!protocols) { - error_setg(errp, "Missing websocket protocol header data"); -- return -1; -+ goto bad_request; - } - - version = qio_channel_websock_find_header( - hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_VERSION); - if (!version) { - error_setg(errp, "Missing websocket version header data"); -- return -1; -+ goto bad_request; - } - - key = qio_channel_websock_find_header( - hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_KEY); - if (!key) { - error_setg(errp, "Missing websocket key header data"); -- return -1; -+ goto bad_request; - } - - host = qio_channel_websock_find_header( - hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_HOST); - if (!host) { - error_setg(errp, "Missing websocket host header data"); -- return -1; -+ goto bad_request; - } - - connection = qio_channel_websock_find_header( - hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_CONNECTION); - if (!connection) { - error_setg(errp, "Missing websocket connection header data"); -- return -1; -+ goto bad_request; - } - - upgrade = qio_channel_websock_find_header( - hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_UPGRADE); - if (!upgrade) { - error_setg(errp, "Missing websocket upgrade header data"); -- return -1; -+ goto bad_request; - } - - if (!g_strrstr(protocols, QIO_CHANNEL_WEBSOCK_PROTOCOL_BINARY)) { - error_setg(errp, "No '%s' protocol is supported by client '%s'", - QIO_CHANNEL_WEBSOCK_PROTOCOL_BINARY, protocols); -- return -1; -+ goto bad_request; - } - - if (!g_str_equal(version, QIO_CHANNEL_WEBSOCK_SUPPORTED_VERSION)) { - error_setg(errp, "Version '%s' is not supported by client '%s'", - QIO_CHANNEL_WEBSOCK_SUPPORTED_VERSION, version); -- return -1; -+ goto bad_request; - } - - if (strlen(key) != QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN) { - error_setg(errp, "Key length '%zu' was not as expected '%d'", - strlen(key), QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN); -- return -1; -+ goto bad_request; - } - - if (!g_strrstr(connection, QIO_CHANNEL_WEBSOCK_CONNECTION_UPGRADE)) { - error_setg(errp, "No connection upgrade requested '%s'", connection); -- return -1; -+ goto bad_request; - } - - if (!g_str_equal(upgrade, QIO_CHANNEL_WEBSOCK_UPGRADE_WEBSOCKET)) { - error_setg(errp, "Incorrect upgrade method '%s'", upgrade); -- return -1; -+ goto bad_request; - } - -- return qio_channel_websock_handshake_send_response(ioc, key, errp); -+ qio_channel_websock_handshake_send_res_ok(ioc, key, errp); -+ return; -+ -+ bad_request: -+ qio_channel_websock_handshake_send_res_err( -+ ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_BAD_REQUEST); - } - - static int qio_channel_websock_handshake_read(QIOChannelWebsock *ioc, -@@ -393,20 +470,20 @@ static int qio_channel_websock_handshake_read(QIOChannelWebsock *ioc, - QIO_CHANNEL_WEBSOCK_HANDSHAKE_END); - if (!handshake_end) { - if (ioc->encinput.offset >= 4096) { -+ qio_channel_websock_handshake_send_res_err( -+ ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_TOO_LARGE); - error_setg(errp, - "End of headers not found in first 4096 bytes"); -- return -1; -+ return 1; - } else { - return 0; - } - } - *handshake_end = '\0'; - -- if (qio_channel_websock_handshake_process(ioc, -- (char *)ioc->encinput.buffer, -- errp) < 0) { -- return -1; -- } -+ qio_channel_websock_handshake_process(ioc, -+ (char *)ioc->encinput.buffer, -+ errp); - - buffer_advance(&ioc->encinput, - handshake_end - (char *)ioc->encinput.buffer + -@@ -438,8 +515,15 @@ static gboolean qio_channel_websock_handshake_send(QIOChannel *ioc, - - buffer_advance(&wioc->encoutput, ret); - if (wioc->encoutput.offset == 0) { -- trace_qio_channel_websock_handshake_complete(ioc); -- qio_task_complete(task); -+ if (wioc->io_err) { -+ trace_qio_channel_websock_handshake_fail(ioc); -+ qio_task_set_error(task, wioc->io_err); -+ wioc->io_err = NULL; -+ qio_task_complete(task); -+ } else { -+ trace_qio_channel_websock_handshake_complete(ioc); -+ qio_task_complete(task); -+ } - return FALSE; - } - trace_qio_channel_websock_handshake_pending(ioc, G_IO_OUT); -@@ -458,6 +542,11 @@ static gboolean qio_channel_websock_handshake_io(QIOChannel *ioc, - - ret = qio_channel_websock_handshake_read(wioc, &err); - if (ret < 0) { -+ /* -+ * We only take this path on a fatal I/O error reading from -+ * client connection, as most of the time we have an -+ * HTTP 4xx err response to send instead -+ */ - trace_qio_channel_websock_handshake_fail(ioc); - qio_task_set_error(task, err); - qio_task_complete(task); -@@ -469,6 +558,10 @@ static gboolean qio_channel_websock_handshake_io(QIOChannel *ioc, - return TRUE; - } - -+ if (err) { -+ error_propagate(&wioc->io_err, err); -+ } -+ - trace_qio_channel_websock_handshake_reply(ioc); - qio_channel_add_watch( - wioc->master, --- -1.8.3.1 - diff --git a/SOURCES/kvm-io-simplify-websocket-ping-reply-handling.patch b/SOURCES/kvm-io-simplify-websocket-ping-reply-handling.patch deleted file mode 100644 index 6ae67ee..0000000 --- a/SOURCES/kvm-io-simplify-websocket-ping-reply-handling.patch +++ /dev/null @@ -1,121 +0,0 @@ -From d467ff7abd1aa30dca064883071bdd74d238567e Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Wed, 20 Dec 2017 17:56:55 +0100 -Subject: [PATCH 15/42] io: simplify websocket ping reply handling - -RH-Author: Daniel P. Berrange -Message-id: <20171220175702.29663-14-berrange@redhat.com> -Patchwork-id: 78465 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 13/20] io: simplify websocket ping reply handling -Bugzilla: 1518649 -RH-Acked-by: John Snow -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -We must ensure we don't get flooded with ping replies if the outbound -channel is slow. Currently we do this by keeping the ping reply in a -separate temporary buffer and only writing it if the encoutput buffer -is completely empty. This is overly pessimistic, as it is reasonable -to add a ping reply to the encoutput buffer even if it has previous -data in it, as long as that previous data doesn't include a ping -reply. - -To track this better, put the ping reply directly into the encoutput -buffer, and then record the size of encoutput at this time in -pong_remain. As we write encoutput to the underlying channel, we -can decrement the pong_remain counter. Once it hits zero, we can -accept further ping replies for transmission. - -Reviewed-by: Eric Blake -Signed-off-by: Daniel P. Berrange -(cherry picked from commit 57b0cdf152b7266e68bfa3e84635d4bdb64ef2cd) -Signed-off-by: Miroslav Rezanina ---- - include/io/channel-websock.h | 2 +- - io/channel-websock.c | 28 +++++++++++++++------------- - 2 files changed, 16 insertions(+), 14 deletions(-) - -diff --git a/include/io/channel-websock.h b/include/io/channel-websock.h -index ff32d86..3762707 100644 ---- a/include/io/channel-websock.h -+++ b/include/io/channel-websock.h -@@ -60,8 +60,8 @@ struct QIOChannelWebsock { - Buffer encoutput; - Buffer rawinput; - Buffer rawoutput; -- Buffer ping_reply; - size_t payload_remain; -+ size_t pong_remain; - QIOChannelWebsockMask mask; - guint io_tag; - Error *io_err; -diff --git a/io/channel-websock.c b/io/channel-websock.c -index 04bcc05..6083f74 100644 ---- a/io/channel-websock.c -+++ b/io/channel-websock.c -@@ -825,11 +825,14 @@ static int qio_channel_websock_decode_payload(QIOChannelWebsock *ioc, - } - return -1; - } else if (ioc->opcode == QIO_CHANNEL_WEBSOCK_OPCODE_PING) { -- /* ping frames produce an immediate reply */ -- buffer_reset(&ioc->ping_reply); -- qio_channel_websock_encode_buffer( -- ioc, &ioc->ping_reply, QIO_CHANNEL_WEBSOCK_OPCODE_PONG, -- &ioc->encinput); -+ /* ping frames produce an immediate reply, as long as we've not still -+ * got a previous pong queued, in which case we drop the new pong */ -+ if (ioc->pong_remain == 0) { -+ qio_channel_websock_encode_buffer( -+ ioc, &ioc->encoutput, QIO_CHANNEL_WEBSOCK_OPCODE_PONG, -+ &ioc->encinput); -+ ioc->pong_remain = ioc->encoutput.offset; -+ } - } /* pong frames are ignored */ - - if (payload_len) { -@@ -888,7 +891,6 @@ static void qio_channel_websock_finalize(Object *obj) - buffer_free(&ioc->encoutput); - buffer_free(&ioc->rawinput); - buffer_free(&ioc->rawoutput); -- buffer_free(&ioc->ping_reply); - object_unref(OBJECT(ioc->master)); - if (ioc->io_tag) { - g_source_remove(ioc->io_tag); -@@ -946,12 +948,7 @@ static ssize_t qio_channel_websock_write_wire(QIOChannelWebsock *ioc, - ssize_t ret; - ssize_t done = 0; - -- /* ping replies take priority over binary data */ -- if (!ioc->ping_reply.offset) { -- qio_channel_websock_encode(ioc); -- } else if (!ioc->encoutput.offset) { -- buffer_move_empty(&ioc->encoutput, &ioc->ping_reply); -- } -+ qio_channel_websock_encode(ioc); - - while (ioc->encoutput.offset > 0) { - ret = qio_channel_write(ioc->master, -@@ -968,6 +965,11 @@ static ssize_t qio_channel_websock_write_wire(QIOChannelWebsock *ioc, - } - buffer_advance(&ioc->encoutput, ret); - done += ret; -+ if (ioc->pong_remain < ret) { -+ ioc->pong_remain = 0; -+ } else { -+ ioc->pong_remain -= ret; -+ } - } - return done; - } -@@ -1026,7 +1028,7 @@ static void qio_channel_websock_set_watch(QIOChannelWebsock *ioc) - return; - } - -- if (ioc->encoutput.offset || ioc->ping_reply.offset) { -+ if (ioc->encoutput.offset) { - cond |= G_IO_OUT; - } - if (ioc->encinput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER && --- -1.8.3.1 - diff --git a/SOURCES/kvm-io-use-case-insensitive-check-for-Connection-Upgrade.patch b/SOURCES/kvm-io-use-case-insensitive-check-for-Connection-Upgrade.patch deleted file mode 100644 index 1dd540b..0000000 --- a/SOURCES/kvm-io-use-case-insensitive-check-for-Connection-Upgrade.patch +++ /dev/null @@ -1,49 +0,0 @@ -From dad42ba543ed6ed3db06e33a08466c7a912b777e Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Wed, 20 Dec 2017 17:56:45 +0100 -Subject: [PATCH 05/42] io: use case insensitive check for Connection & Upgrade - websock headers - -RH-Author: Daniel P. Berrange -Message-id: <20171220175702.29663-4-berrange@redhat.com> -Patchwork-id: 78456 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 03/20] io: use case insensitive check for Connection & Upgrade websock headers -Bugzilla: 1518649 -RH-Acked-by: John Snow -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -When checking the value of the Connection and Upgrade HTTP headers -the websock RFC (6455) requires the comparison to be case insensitive. -The Connection value should be an exact match not a substring. - -Reviewed-by: Eric Blake -Signed-off-by: Daniel P. Berrange -(cherry picked from commit 33badfd1e3735b877e41939100511c65572be6b9) -Signed-off-by: Miroslav Rezanina ---- - io/channel-websock.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/io/channel-websock.c b/io/channel-websock.c -index 6ddcec1..2258557 100644 ---- a/io/channel-websock.c -+++ b/io/channel-websock.c -@@ -431,12 +431,12 @@ static void qio_channel_websock_handshake_process(QIOChannelWebsock *ioc, - goto bad_request; - } - -- if (!g_strrstr(connection, QIO_CHANNEL_WEBSOCK_CONNECTION_UPGRADE)) { -+ if (strcasecmp(connection, QIO_CHANNEL_WEBSOCK_CONNECTION_UPGRADE) != 0) { - error_setg(errp, "No connection upgrade requested '%s'", connection); - goto bad_request; - } - -- if (!g_str_equal(upgrade, QIO_CHANNEL_WEBSOCK_UPGRADE_WEBSOCKET)) { -+ if (strcasecmp(upgrade, QIO_CHANNEL_WEBSOCK_UPGRADE_WEBSOCKET) != 0) { - error_setg(errp, "Incorrect upgrade method '%s'", upgrade); - goto bad_request; - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-iotests-222-Don-t-run-with-luks.patch b/SOURCES/kvm-iotests-222-Don-t-run-with-luks.patch new file mode 100644 index 0000000..f327c98 --- /dev/null +++ b/SOURCES/kvm-iotests-222-Don-t-run-with-luks.patch @@ -0,0 +1,44 @@ +From cd3796e20a98a0a6274514005bec886e291b1984 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 18 Jul 2018 22:54:54 +0200 +Subject: [PATCH 69/89] iotests: 222: Don't run with luks + +RH-Author: John Snow +Message-id: <20180718225511.14878-19-jsnow@redhat.com> +Patchwork-id: 81422 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 18/35] iotests: 222: Don't run with luks +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Fam Zheng + +Luks needs special parameters to operate the image. Since this test is +focusing on image fleecing, skip skip that format. + +Signed-off-by: Fam Zheng +Signed-off-by: Kevin Wolf +(cherry picked from commit e79c4cd1909c05a2cab6517a9c00445bd2d880a6) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/222 | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tests/qemu-iotests/222 b/tests/qemu-iotests/222 +index ff3bfc1..0ead56d 100644 +--- a/tests/qemu-iotests/222 ++++ b/tests/qemu-iotests/222 +@@ -25,6 +25,8 @@ import iotests + from iotests import log, qemu_img, qemu_io, qemu_io_silent + + iotests.verify_platform(['linux']) ++iotests.verify_image_format(supported_fmts=['qcow2', 'qcow', 'qed', 'vmdk', ++ 'vhdx', 'raw']) + + patterns = [("0x5d", "0", "64k"), + ("0xd5", "1M", "64k"), +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Add-case-for-a-corrupted-inactive-image.patch b/SOURCES/kvm-iotests-Add-case-for-a-corrupted-inactive-image.patch new file mode 100644 index 0000000..5a3446f --- /dev/null +++ b/SOURCES/kvm-iotests-Add-case-for-a-corrupted-inactive-image.patch @@ -0,0 +1,95 @@ +From e9dd4092392c53954bbd394e4286f3ac431f47aa Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 18:00:55 +0200 +Subject: [PATCH 49/54] iotests: Add case for a corrupted inactive image + +RH-Author: Max Reitz +Message-id: <20180618180055.22739-4-mreitz@redhat.com> +Patchwork-id: 80794 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 3/3] iotests: Add case for a corrupted inactive image +Bugzilla: 1588039 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf +RH-Acked-by: John Snow + +Reviewed-by: John Snow +Tested-by: Jeff Cody +Reviewed-by: Jeff Cody +Signed-off-by: Max Reitz +Message-id: 20180606193702.7113-4-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit c50abd175a88cd41c2c08339de91f6f6e4a7b162) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/060 | 30 ++++++++++++++++++++++++++++++ + tests/qemu-iotests/060.out | 14 ++++++++++++++ + 2 files changed, 44 insertions(+) + +diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060 +index 6c7407f..7bdf609 100755 +--- a/tests/qemu-iotests/060 ++++ b/tests/qemu-iotests/060 +@@ -440,6 +440,36 @@ echo "{'execute': 'qmp_capabilities'} + -drive if=none,node-name=drive,file="$TEST_IMG",driver=qcow2 \ + | _filter_qmp | _filter_qemu_io + ++echo ++echo "=== Testing incoming inactive corrupted image ===" ++echo ++ ++_make_test_img 64M ++# Create an unaligned L1 entry, so qemu will signal a corruption when ++# reading from the covered area ++poke_file "$TEST_IMG" "$l1_offset" "\x00\x00\x00\x00\x2a\x2a\x2a\x2a" ++ ++# Inactive images are effectively read-only images, so this should be a ++# non-fatal corruption (which does not modify the image) ++echo "{'execute': 'qmp_capabilities'} ++ {'execute': 'human-monitor-command', ++ 'arguments': {'command-line': 'qemu-io drive \"read 0 512\"'}} ++ {'execute': 'quit'}" \ ++ | $QEMU -qmp stdio -nographic -nodefaults \ ++ -blockdev "{'node-name': 'drive', ++ 'driver': 'qcow2', ++ 'file': { ++ 'driver': 'file', ++ 'filename': '$TEST_IMG' ++ }}" \ ++ -incoming exec:'cat /dev/null' \ ++ 2>&1 \ ++ | _filter_qmp | _filter_qemu_io ++ ++echo ++# Image should not have been marked corrupt ++_img_info --format-specific | grep 'corrupt:' ++ + # success, all done + echo "*** done" + rm -f $seq.full +diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out +index 25d5c39..99234fb 100644 +--- a/tests/qemu-iotests/060.out ++++ b/tests/qemu-iotests/060.out +@@ -420,4 +420,18 @@ write failed: Input/output error + {"return": ""} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} ++ ++=== Testing incoming inactive corrupted image === ++ ++Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 ++QMP_VERSION ++{"return": {}} ++qcow2: Image is corrupt: L2 table offset 0x2a2a2a00 unaligned (L1 index: 0); further non-fatal corruption events will be suppressed ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_IMAGE_CORRUPTED", "data": {"device": "", "msg": "L2 table offset 0x2a2a2a00 unaligned (L1 index: 0)", "node-name": "drive", "fatal": false}} ++read failed: Input/output error ++{"return": ""} ++{"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} ++ ++ corrupt: false + *** done +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Add-cluster_size-64k-to-125.patch b/SOURCES/kvm-iotests-Add-cluster_size-64k-to-125.patch deleted file mode 100644 index 65385eb..0000000 --- a/SOURCES/kvm-iotests-Add-cluster_size-64k-to-125.patch +++ /dev/null @@ -1,882 +0,0 @@ -From 8e88c188f93cf53c2b1f411520eedd82a8ed72a0 Mon Sep 17 00:00:00 2001 -From: Max Reitz -Date: Mon, 27 Nov 2017 16:19:59 +0100 -Subject: [PATCH 04/21] iotests: Add cluster_size=64k to 125 - -RH-Author: Max Reitz -Message-id: <20171127161959.13234-5-mreitz@redhat.com> -Patchwork-id: 77914 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH 4/4] iotests: Add cluster_size=64k to 125 -Bugzilla: 1414049 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Fam Zheng -RH-Acked-by: John Snow - -Apparently it would be a good idea to test that, too. - -Signed-off-by: Max Reitz -Message-id: 20171009215533.12530-4-mreitz@redhat.com -Reviewed-by: Eric Blake -Reviewed-by: Jeff Cody -Reviewed-by: Stefan Hajnoczi -Signed-off-by: Max Reitz -(cherry picked from commit 4c112a397c2f61038914fa315a7896ce6d645d18) -Signed-off-by: Max Reitz -Signed-off-by: Miroslav Rezanina ---- - tests/qemu-iotests/125 | 7 +- - tests/qemu-iotests/125.out | 480 ++++++++++++++++++++++++++++++++++++++++----- - 2 files changed, 437 insertions(+), 50 deletions(-) - -diff --git a/tests/qemu-iotests/125 b/tests/qemu-iotests/125 -index 9424313..c20c715 100755 ---- a/tests/qemu-iotests/125 -+++ b/tests/qemu-iotests/125 -@@ -69,13 +69,15 @@ fi - # in B - CREATION_SIZE=$((2 * 1024 * 1024 - 48 * 1024)) - -+# 512 is the actual test -- but it's good to test 64k as well, just to be sure. -+for cluster_size in 512 64k; do - # in kB - for GROWTH_SIZE in 16 48 80; do - for create_mode in off metadata falloc full; do - for growth_mode in off metadata falloc full; do -- echo "--- growth_size=$GROWTH_SIZE create_mode=$create_mode growth_mode=$growth_mode ---" -+ echo "--- cluster_size=$cluster_size growth_size=$GROWTH_SIZE create_mode=$create_mode growth_mode=$growth_mode ---" - -- IMGOPTS="preallocation=$create_mode,cluster_size=512" _make_test_img ${CREATION_SIZE} -+ IMGOPTS="preallocation=$create_mode,cluster_size=$cluster_size" _make_test_img ${CREATION_SIZE} - $QEMU_IMG resize -f "$IMGFMT" --preallocation=$growth_mode "$TEST_IMG" +${GROWTH_SIZE}K - - host_size_0=$(get_image_size_on_host) -@@ -123,6 +125,7 @@ for GROWTH_SIZE in 16 48 80; do - done - done - done -+done - - # success, all done - echo '*** done' -diff --git a/tests/qemu-iotests/125.out b/tests/qemu-iotests/125.out -index 3f4d6e3..596905f 100644 ---- a/tests/qemu-iotests/125.out -+++ b/tests/qemu-iotests/125.out -@@ -1,5 +1,5 @@ - QA output created by 125 ----- growth_size=16 create_mode=off growth_mode=off --- -+--- cluster_size=512 growth_size=16 create_mode=off growth_mode=off --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -7,7 +7,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 16384/16384 bytes at offset 2048000 - 16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=16 create_mode=off growth_mode=metadata --- -+--- cluster_size=512 growth_size=16 create_mode=off growth_mode=metadata --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -15,7 +15,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 16384/16384 bytes at offset 2048000 - 16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=16 create_mode=off growth_mode=falloc --- -+--- cluster_size=512 growth_size=16 create_mode=off growth_mode=falloc --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -23,7 +23,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 16384/16384 bytes at offset 2048000 - 16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=16 create_mode=off growth_mode=full --- -+--- cluster_size=512 growth_size=16 create_mode=off growth_mode=full --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -31,7 +31,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 16384/16384 bytes at offset 2048000 - 16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=16 create_mode=metadata growth_mode=off --- -+--- cluster_size=512 growth_size=16 create_mode=metadata growth_mode=off --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -39,7 +39,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 16384/16384 bytes at offset 2048000 - 16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=16 create_mode=metadata growth_mode=metadata --- -+--- cluster_size=512 growth_size=16 create_mode=metadata growth_mode=metadata --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -47,7 +47,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 16384/16384 bytes at offset 2048000 - 16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=16 create_mode=metadata growth_mode=falloc --- -+--- cluster_size=512 growth_size=16 create_mode=metadata growth_mode=falloc --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -55,7 +55,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 16384/16384 bytes at offset 2048000 - 16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=16 create_mode=metadata growth_mode=full --- -+--- cluster_size=512 growth_size=16 create_mode=metadata growth_mode=full --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -63,7 +63,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 16384/16384 bytes at offset 2048000 - 16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=16 create_mode=falloc growth_mode=off --- -+--- cluster_size=512 growth_size=16 create_mode=falloc growth_mode=off --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -71,7 +71,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 16384/16384 bytes at offset 2048000 - 16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=16 create_mode=falloc growth_mode=metadata --- -+--- cluster_size=512 growth_size=16 create_mode=falloc growth_mode=metadata --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -79,7 +79,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 16384/16384 bytes at offset 2048000 - 16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=16 create_mode=falloc growth_mode=falloc --- -+--- cluster_size=512 growth_size=16 create_mode=falloc growth_mode=falloc --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -87,7 +87,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 16384/16384 bytes at offset 2048000 - 16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=16 create_mode=falloc growth_mode=full --- -+--- cluster_size=512 growth_size=16 create_mode=falloc growth_mode=full --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -95,7 +95,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 16384/16384 bytes at offset 2048000 - 16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=16 create_mode=full growth_mode=off --- -+--- cluster_size=512 growth_size=16 create_mode=full growth_mode=off --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -103,7 +103,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 16384/16384 bytes at offset 2048000 - 16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=16 create_mode=full growth_mode=metadata --- -+--- cluster_size=512 growth_size=16 create_mode=full growth_mode=metadata --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -111,7 +111,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 16384/16384 bytes at offset 2048000 - 16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=16 create_mode=full growth_mode=falloc --- -+--- cluster_size=512 growth_size=16 create_mode=full growth_mode=falloc --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -119,7 +119,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 16384/16384 bytes at offset 2048000 - 16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=16 create_mode=full growth_mode=full --- -+--- cluster_size=512 growth_size=16 create_mode=full growth_mode=full --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -127,7 +127,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 16384/16384 bytes at offset 2048000 - 16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=48 create_mode=off growth_mode=off --- -+--- cluster_size=512 growth_size=48 create_mode=off growth_mode=off --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -135,7 +135,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 49152/49152 bytes at offset 2048000 - 48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=48 create_mode=off growth_mode=metadata --- -+--- cluster_size=512 growth_size=48 create_mode=off growth_mode=metadata --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -143,7 +143,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 49152/49152 bytes at offset 2048000 - 48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=48 create_mode=off growth_mode=falloc --- -+--- cluster_size=512 growth_size=48 create_mode=off growth_mode=falloc --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -151,7 +151,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 49152/49152 bytes at offset 2048000 - 48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=48 create_mode=off growth_mode=full --- -+--- cluster_size=512 growth_size=48 create_mode=off growth_mode=full --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -159,7 +159,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 49152/49152 bytes at offset 2048000 - 48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=48 create_mode=metadata growth_mode=off --- -+--- cluster_size=512 growth_size=48 create_mode=metadata growth_mode=off --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -167,7 +167,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 49152/49152 bytes at offset 2048000 - 48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=48 create_mode=metadata growth_mode=metadata --- -+--- cluster_size=512 growth_size=48 create_mode=metadata growth_mode=metadata --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -175,7 +175,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 49152/49152 bytes at offset 2048000 - 48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=48 create_mode=metadata growth_mode=falloc --- -+--- cluster_size=512 growth_size=48 create_mode=metadata growth_mode=falloc --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -183,7 +183,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 49152/49152 bytes at offset 2048000 - 48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=48 create_mode=metadata growth_mode=full --- -+--- cluster_size=512 growth_size=48 create_mode=metadata growth_mode=full --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -191,7 +191,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 49152/49152 bytes at offset 2048000 - 48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=48 create_mode=falloc growth_mode=off --- -+--- cluster_size=512 growth_size=48 create_mode=falloc growth_mode=off --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -199,7 +199,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 49152/49152 bytes at offset 2048000 - 48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=48 create_mode=falloc growth_mode=metadata --- -+--- cluster_size=512 growth_size=48 create_mode=falloc growth_mode=metadata --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -207,7 +207,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 49152/49152 bytes at offset 2048000 - 48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=48 create_mode=falloc growth_mode=falloc --- -+--- cluster_size=512 growth_size=48 create_mode=falloc growth_mode=falloc --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -215,7 +215,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 49152/49152 bytes at offset 2048000 - 48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=48 create_mode=falloc growth_mode=full --- -+--- cluster_size=512 growth_size=48 create_mode=falloc growth_mode=full --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -223,7 +223,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 49152/49152 bytes at offset 2048000 - 48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=48 create_mode=full growth_mode=off --- -+--- cluster_size=512 growth_size=48 create_mode=full growth_mode=off --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -231,7 +231,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 49152/49152 bytes at offset 2048000 - 48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=48 create_mode=full growth_mode=metadata --- -+--- cluster_size=512 growth_size=48 create_mode=full growth_mode=metadata --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -239,7 +239,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 49152/49152 bytes at offset 2048000 - 48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=48 create_mode=full growth_mode=falloc --- -+--- cluster_size=512 growth_size=48 create_mode=full growth_mode=falloc --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -247,7 +247,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 49152/49152 bytes at offset 2048000 - 48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=48 create_mode=full growth_mode=full --- -+--- cluster_size=512 growth_size=48 create_mode=full growth_mode=full --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -255,7 +255,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 49152/49152 bytes at offset 2048000 - 48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=80 create_mode=off growth_mode=off --- -+--- cluster_size=512 growth_size=80 create_mode=off growth_mode=off --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -263,7 +263,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 81920/81920 bytes at offset 2048000 - 80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=80 create_mode=off growth_mode=metadata --- -+--- cluster_size=512 growth_size=80 create_mode=off growth_mode=metadata --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -271,7 +271,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 81920/81920 bytes at offset 2048000 - 80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=80 create_mode=off growth_mode=falloc --- -+--- cluster_size=512 growth_size=80 create_mode=off growth_mode=falloc --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -279,7 +279,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 81920/81920 bytes at offset 2048000 - 80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=80 create_mode=off growth_mode=full --- -+--- cluster_size=512 growth_size=80 create_mode=off growth_mode=full --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -287,7 +287,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 81920/81920 bytes at offset 2048000 - 80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=80 create_mode=metadata growth_mode=off --- -+--- cluster_size=512 growth_size=80 create_mode=metadata growth_mode=off --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -295,7 +295,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 81920/81920 bytes at offset 2048000 - 80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=80 create_mode=metadata growth_mode=metadata --- -+--- cluster_size=512 growth_size=80 create_mode=metadata growth_mode=metadata --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -303,7 +303,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 81920/81920 bytes at offset 2048000 - 80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=80 create_mode=metadata growth_mode=falloc --- -+--- cluster_size=512 growth_size=80 create_mode=metadata growth_mode=falloc --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -311,7 +311,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 81920/81920 bytes at offset 2048000 - 80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=80 create_mode=metadata growth_mode=full --- -+--- cluster_size=512 growth_size=80 create_mode=metadata growth_mode=full --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -319,7 +319,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 81920/81920 bytes at offset 2048000 - 80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=80 create_mode=falloc growth_mode=off --- -+--- cluster_size=512 growth_size=80 create_mode=falloc growth_mode=off --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -327,7 +327,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 81920/81920 bytes at offset 2048000 - 80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=80 create_mode=falloc growth_mode=metadata --- -+--- cluster_size=512 growth_size=80 create_mode=falloc growth_mode=metadata --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -335,7 +335,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 81920/81920 bytes at offset 2048000 - 80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=80 create_mode=falloc growth_mode=falloc --- -+--- cluster_size=512 growth_size=80 create_mode=falloc growth_mode=falloc --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -343,7 +343,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 81920/81920 bytes at offset 2048000 - 80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=80 create_mode=falloc growth_mode=full --- -+--- cluster_size=512 growth_size=80 create_mode=falloc growth_mode=full --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -351,7 +351,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 81920/81920 bytes at offset 2048000 - 80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=80 create_mode=full growth_mode=off --- -+--- cluster_size=512 growth_size=80 create_mode=full growth_mode=off --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -359,7 +359,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 81920/81920 bytes at offset 2048000 - 80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=80 create_mode=full growth_mode=metadata --- -+--- cluster_size=512 growth_size=80 create_mode=full growth_mode=metadata --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -367,7 +367,7 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 81920/81920 bytes at offset 2048000 - 80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=80 create_mode=full growth_mode=falloc --- -+--- cluster_size=512 growth_size=80 create_mode=full growth_mode=falloc --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full - Image resized. - wrote 2048000/2048000 bytes at offset 0 -@@ -375,7 +375,391 @@ wrote 2048000/2048000 bytes at offset 0 - wrote 81920/81920 bytes at offset 2048000 - 80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - ----- growth_size=80 create_mode=full growth_mode=full --- -+--- cluster_size=512 growth_size=80 create_mode=full growth_mode=full --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 81920/81920 bytes at offset 2048000 -+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=16 create_mode=off growth_mode=off --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 16384/16384 bytes at offset 2048000 -+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=16 create_mode=off growth_mode=metadata --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 16384/16384 bytes at offset 2048000 -+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=16 create_mode=off growth_mode=falloc --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 16384/16384 bytes at offset 2048000 -+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=16 create_mode=off growth_mode=full --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 16384/16384 bytes at offset 2048000 -+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=16 create_mode=metadata growth_mode=off --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 16384/16384 bytes at offset 2048000 -+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=16 create_mode=metadata growth_mode=metadata --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 16384/16384 bytes at offset 2048000 -+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=16 create_mode=metadata growth_mode=falloc --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 16384/16384 bytes at offset 2048000 -+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=16 create_mode=metadata growth_mode=full --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 16384/16384 bytes at offset 2048000 -+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=16 create_mode=falloc growth_mode=off --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 16384/16384 bytes at offset 2048000 -+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=16 create_mode=falloc growth_mode=metadata --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 16384/16384 bytes at offset 2048000 -+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=16 create_mode=falloc growth_mode=falloc --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 16384/16384 bytes at offset 2048000 -+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=16 create_mode=falloc growth_mode=full --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 16384/16384 bytes at offset 2048000 -+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=16 create_mode=full growth_mode=off --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 16384/16384 bytes at offset 2048000 -+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=16 create_mode=full growth_mode=metadata --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 16384/16384 bytes at offset 2048000 -+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=16 create_mode=full growth_mode=falloc --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 16384/16384 bytes at offset 2048000 -+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=16 create_mode=full growth_mode=full --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 16384/16384 bytes at offset 2048000 -+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=48 create_mode=off growth_mode=off --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 49152/49152 bytes at offset 2048000 -+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=48 create_mode=off growth_mode=metadata --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 49152/49152 bytes at offset 2048000 -+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=48 create_mode=off growth_mode=falloc --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 49152/49152 bytes at offset 2048000 -+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=48 create_mode=off growth_mode=full --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 49152/49152 bytes at offset 2048000 -+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=48 create_mode=metadata growth_mode=off --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 49152/49152 bytes at offset 2048000 -+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=48 create_mode=metadata growth_mode=metadata --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 49152/49152 bytes at offset 2048000 -+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=48 create_mode=metadata growth_mode=falloc --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 49152/49152 bytes at offset 2048000 -+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=48 create_mode=metadata growth_mode=full --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 49152/49152 bytes at offset 2048000 -+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=48 create_mode=falloc growth_mode=off --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 49152/49152 bytes at offset 2048000 -+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=48 create_mode=falloc growth_mode=metadata --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 49152/49152 bytes at offset 2048000 -+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=48 create_mode=falloc growth_mode=falloc --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 49152/49152 bytes at offset 2048000 -+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=48 create_mode=falloc growth_mode=full --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 49152/49152 bytes at offset 2048000 -+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=48 create_mode=full growth_mode=off --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 49152/49152 bytes at offset 2048000 -+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=48 create_mode=full growth_mode=metadata --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 49152/49152 bytes at offset 2048000 -+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=48 create_mode=full growth_mode=falloc --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 49152/49152 bytes at offset 2048000 -+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=48 create_mode=full growth_mode=full --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 49152/49152 bytes at offset 2048000 -+48 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=80 create_mode=off growth_mode=off --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 81920/81920 bytes at offset 2048000 -+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=80 create_mode=off growth_mode=metadata --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 81920/81920 bytes at offset 2048000 -+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=80 create_mode=off growth_mode=falloc --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 81920/81920 bytes at offset 2048000 -+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=80 create_mode=off growth_mode=full --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=off -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 81920/81920 bytes at offset 2048000 -+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=80 create_mode=metadata growth_mode=off --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 81920/81920 bytes at offset 2048000 -+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=80 create_mode=metadata growth_mode=metadata --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 81920/81920 bytes at offset 2048000 -+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=80 create_mode=metadata growth_mode=falloc --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 81920/81920 bytes at offset 2048000 -+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=80 create_mode=metadata growth_mode=full --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=metadata -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 81920/81920 bytes at offset 2048000 -+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=80 create_mode=falloc growth_mode=off --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 81920/81920 bytes at offset 2048000 -+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=80 create_mode=falloc growth_mode=metadata --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 81920/81920 bytes at offset 2048000 -+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=80 create_mode=falloc growth_mode=falloc --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 81920/81920 bytes at offset 2048000 -+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=80 create_mode=falloc growth_mode=full --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=falloc -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 81920/81920 bytes at offset 2048000 -+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=80 create_mode=full growth_mode=off --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 81920/81920 bytes at offset 2048000 -+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=80 create_mode=full growth_mode=metadata --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 81920/81920 bytes at offset 2048000 -+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=80 create_mode=full growth_mode=falloc --- -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full -+Image resized. -+wrote 2048000/2048000 bytes at offset 0 -+1.953 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+wrote 81920/81920 bytes at offset 2048000 -+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+--- cluster_size=64k growth_size=80 create_mode=full growth_mode=full --- - Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2048000 preallocation=full - Image resized. - wrote 2048000/2048000 bytes at offset 0 --- -1.8.3.1 - diff --git a/SOURCES/kvm-iotests-Add-creation-test-to-153.patch b/SOURCES/kvm-iotests-Add-creation-test-to-153.patch new file mode 100644 index 0000000..af4bb84 --- /dev/null +++ b/SOURCES/kvm-iotests-Add-creation-test-to-153.patch @@ -0,0 +1,101 @@ +From e37408d4eee39e39d653ac2ce35155bed6db9a9e Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 14:53:37 +0200 +Subject: [PATCH 08/57] iotests: Add creation test to 153 + +RH-Author: Max Reitz +Message-id: <20180618145337.633-4-mreitz@redhat.com> +Patchwork-id: 80752 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 3/3] iotests: Add creation test to 153 +Bugzilla: 1519144 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng +RH-Acked-by: Miroslav Rezanina + +This patch adds a test case to 153 which tries to overwrite an image +(using qemu-img create) while it is in use. Without the original user +explicitly sharing the necessary permissions (writing and truncation), +this should not be allowed. + +Signed-off-by: Max Reitz +Reviewed-by: Fam Zheng +Message-id: 20180509215336.31304-4-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit f45b638f9f967cdbea4e24704bd16a858ddcde03) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/153 | 18 ++++++++++++++++++ + tests/qemu-iotests/153.out | 13 +++++++++++++ + 2 files changed, 31 insertions(+) + +diff --git a/tests/qemu-iotests/153 b/tests/qemu-iotests/153 +index ec508c7..673813c 100755 +--- a/tests/qemu-iotests/153 ++++ b/tests/qemu-iotests/153 +@@ -137,6 +137,24 @@ for opts1 in "" "read-only=on" "read-only=on,force-share=on"; do + _run_cmd $QEMU_IMG dd $L if="${TEST_IMG}" of="${TEST_IMG}.convert" bs=512 count=1 + _run_cmd $QEMU_IMG bench $L -c 1 "${TEST_IMG}" + _run_cmd $QEMU_IMG bench $L -w -c 1 "${TEST_IMG}" ++ ++ # qemu-img create does not support -U ++ if [ -z "$L" ]; then ++ _run_cmd $QEMU_IMG create -f $IMGFMT "${TEST_IMG}" \ ++ -b ${TEST_IMG}.base ++ # Read the file format. It used to be the case that ++ # file-posix simply truncated the file, but the qcow2 ++ # driver then failed to format it because it was unable ++ # to acquire the necessary WRITE permission. However, the ++ # truncation was already wrong, and the whole process ++ # resulted in the file being completely empty and thus its ++ # format would be detected to be raw. ++ # So we read it here to see that creation either completed ++ # successfully (thus the format is qcow2) or it aborted ++ # before the file was changed at all (thus the format stays ++ # qcow2). ++ _img_info -U | grep 'file format' ++ fi + done + _send_qemu_cmd $h "{ 'execute': 'quit', }" "" + echo +diff --git a/tests/qemu-iotests/153.out b/tests/qemu-iotests/153.out +index 2510762..3492ba7 100644 +--- a/tests/qemu-iotests/153.out ++++ b/tests/qemu-iotests/153.out +@@ -92,6 +92,11 @@ _qemu_img_wrapper bench -w -c 1 TEST_DIR/t.qcow2 + qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get "write" lock + Is another process using the image? + ++_qemu_img_wrapper create -f qcow2 TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base ++qemu-img: TEST_DIR/t.qcow2: Failed to get "write" lock ++Is another process using the image? ++file format: IMGFMT ++ + == Running utility commands -U == + + _qemu_io_wrapper -U -c read 0 512 TEST_DIR/t.qcow2 +@@ -209,6 +214,11 @@ _qemu_img_wrapper bench -w -c 1 TEST_DIR/t.qcow2 + qemu-img: Could not open 'TEST_DIR/t.qcow2': Failed to get "write" lock + Is another process using the image? + ++_qemu_img_wrapper create -f qcow2 TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base ++qemu-img: TEST_DIR/t.qcow2: Failed to get "write" lock ++Is another process using the image? ++file format: IMGFMT ++ + == Running utility commands -U == + + _qemu_io_wrapper -U -c read 0 512 TEST_DIR/t.qcow2 +@@ -309,6 +319,9 @@ _qemu_img_wrapper bench -c 1 TEST_DIR/t.qcow2 + + _qemu_img_wrapper bench -w -c 1 TEST_DIR/t.qcow2 + ++_qemu_img_wrapper create -f qcow2 TEST_DIR/t.qcow2 -b TEST_DIR/t.qcow2.base ++file format: IMGFMT ++ + == Running utility commands -U == + + _qemu_io_wrapper -U -c read 0 512 TEST_DIR/t.qcow2 +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Add-failure-matching-to-common.qemu.patch b/SOURCES/kvm-iotests-Add-failure-matching-to-common.qemu.patch new file mode 100644 index 0000000..72d80a5 --- /dev/null +++ b/SOURCES/kvm-iotests-Add-failure-matching-to-common.qemu.patch @@ -0,0 +1,156 @@ +From 2ffef795b5aed20b6fc2fba3951ff8f5c97cef5a Mon Sep 17 00:00:00 2001 +From: Jeffrey Cody +Date: Tue, 28 Aug 2018 21:08:17 +0200 +Subject: [PATCH 04/29] iotests: Add failure matching to common.qemu + +RH-Author: Jeffrey Cody +Message-id: <7850ea2daac60087a2cd5e300f8b7042b167ef24.1535490170.git.jcody@redhat.com> +Patchwork-id: 81955 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 2/3] iotests: Add failure matching to common.qemu +Bugzilla: 1605026 +RH-Acked-by: Max Reitz +RH-Acked-by: John Snow +RH-Acked-by: Miroslav Rezanina + +From: Max Reitz + +Currently, common.qemu only allows to match for results indicating +success. The only way to fail is by provoking a timeout. However, +sometimes we do have a defined failure output and can match for that, +which saves us from having to wait for the timeout in case of failure. +Because failure can sometimes just result in a _notrun in the test, it +is actually important to care about being able to fail quickly. + +Also, sometimes we simply do not get any specific output in case of +success. The only way to handle this currently would be to define an +error message as the string to look for, which means that actual success +results in a timeout. This is really bad because it unnecessarily slows +down a succeeding test. + +Therefore, this patch adds a new parameter $success_or_failure to +_timed_wait_for and _send_qemu_cmd. Setting this to a non-empty string +makes both commands expect two match parameters: If the first matches, +the function succeeds. If the second matches, the function fails. + +Signed-off-by: Max Reitz +Message-id: 20180406151731.4285-2-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit 81c6ddf49a76a663cea16c07a07d51b67c853209) +Signed-off-by: Jeff Cody +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/common.qemu | 58 +++++++++++++++++++++++++++++++++++++----- + 1 file changed, 51 insertions(+), 7 deletions(-) + +diff --git a/tests/qemu-iotests/common.qemu b/tests/qemu-iotests/common.qemu +index 85f66b8..f285484 100644 +--- a/tests/qemu-iotests/common.qemu ++++ b/tests/qemu-iotests/common.qemu +@@ -52,11 +52,29 @@ _in_fd=4 + # response is not echoed out. + # If $mismatch_only is set, only non-matching responses will + # be echoed. ++# ++# If $success_or_failure is set, the meaning of the arguments is ++# changed as follows: ++# $2: A string to search for in the response; if found, this indicates ++# success and ${QEMU_STATUS[$1]} is set to 0. ++# $3: A string to search for in the response; if found, this indicates ++# failure and the test is either aborted (if $qemu_error_no_exit ++# is not set) or ${QEMU_STATUS[$1]} is set to -1 (otherwise). + function _timed_wait_for() + { + local h=${1} + shift + ++ if [ -z "${success_or_failure}" ]; then ++ success_match=${*} ++ failure_match= ++ else ++ success_match=${1} ++ failure_match=${2} ++ fi ++ ++ timeout=yes ++ + QEMU_STATUS[$h]=0 + while IFS= read -t ${QEMU_COMM_TIMEOUT} resp <&${QEMU_OUT[$h]} + do +@@ -64,10 +82,18 @@ function _timed_wait_for() + echo "${resp}" | _filter_testdir | _filter_qemu \ + | _filter_qemu_io | _filter_qmp | _filter_hmp + fi +- grep -q "${*}" < <(echo "${resp}") ++ if [ -n "${failure_match}" ]; then ++ grep -q "${failure_match}" < <(echo "${resp}") ++ if [ $? -eq 0 ]; then ++ timeout= ++ break ++ fi ++ fi ++ grep -q "${success_match}" < <(echo "${resp}") + if [ $? -eq 0 ]; then + return +- elif [ -z "${silent}" ] && [ -n "${mismatch_only}" ]; then ++ fi ++ if [ -z "${silent}" ] && [ -n "${mismatch_only}" ]; then + echo "${resp}" | _filter_testdir | _filter_qemu \ + | _filter_qemu_io | _filter_qmp | _filter_hmp + fi +@@ -75,8 +101,12 @@ function _timed_wait_for() + done + QEMU_STATUS[$h]=-1 + if [ -z "${qemu_error_no_exit}" ]; then +- echo "Timeout waiting for ${*} on handle ${h}" +- exit 1 # Timeout means the test failed ++ if [ -n "${timeout}" ]; then ++ echo "Timeout waiting for ${success_match} on handle ${h}" ++ else ++ echo "Wrong response matching ${failure_match} on handle ${h}" ++ fi ++ exit 1 # Timeout or wrong match mean the test failed + fi + } + +@@ -96,6 +126,11 @@ function _timed_wait_for() + # If $qemu_error_no_exit is set, then even if the expected response + # is not seen, we will not exit. $QEMU_STATUS[$1] will be set it -1 in + # that case. ++# ++# If $success_or_failure is set, then the last two strings are the ++# strings the response will be scanned for. The first of the two ++# indicates success, the latter indicates failure. Failure is handled ++# like a timeout. + function _send_qemu_cmd() + { + local h=${1} +@@ -109,14 +144,23 @@ function _send_qemu_cmd() + use_error="no" + fi + # This array element extraction is done to accommodate pathnames with spaces +- cmd=${@: 1:${#@}-1} +- shift $(($# - 1)) ++ if [ -z "${success_or_failure}" ]; then ++ cmd=${@: 1:${#@}-1} ++ shift $(($# - 1)) ++ else ++ cmd=${@: 1:${#@}-2} ++ shift $(($# - 2)) ++ fi + + while [ ${count} -gt 0 ] + do + echo "${cmd}" >&${QEMU_IN[${h}]} + if [ -n "${1}" ]; then +- qemu_error_no_exit=${use_error} _timed_wait_for ${h} "${1}" ++ if [ -z "${success_or_failure}" ]; then ++ qemu_error_no_exit=${use_error} _timed_wait_for ${h} "${1}" ++ else ++ qemu_error_no_exit=${use_error} _timed_wait_for ${h} "${1}" "${2}" ++ fi + if [ ${QEMU_STATUS[$h]} -eq 0 ]; then + return + fi +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Add-regression-test-for-commit-base-locking.patch b/SOURCES/kvm-iotests-Add-regression-test-for-commit-base-locking.patch deleted file mode 100644 index 3effa27..0000000 --- a/SOURCES/kvm-iotests-Add-regression-test-for-commit-base-locking.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 9cac958ac666c9095490cf6814110c8083ad8929 Mon Sep 17 00:00:00 2001 -From: Fam Zheng -Date: Tue, 13 Mar 2018 15:27:55 +0100 -Subject: [PATCH 2/4] iotests: Add regression test for commit base locking - -RH-Author: Fam Zheng -Message-id: <20180313152755.31475-3-famz@redhat.com> -Patchwork-id: 79276 -O-Subject: [RHV7.5 qemu-kvm-ma PATCH v4 2/2] iotests: Add regression test for commit base locking -Bugzilla: 1557206 -RH-Acked-by: Max Reitz -RH-Acked-by: Kevin Wolf -RH-Acked-by: Stefan Hajnoczi - -Signed-off-by: Fam Zheng -Reviewed-by: Max Reitz -Signed-off-by: Kevin Wolf -Signed-off-by: Fam Zheng -Signed-off-by: Miroslav Rezanina ---- - tests/qemu-iotests/153 | 11 +++++++++++ - tests/qemu-iotests/153.out | 4 ++++ - 2 files changed, 15 insertions(+) - -diff --git a/tests/qemu-iotests/153 b/tests/qemu-iotests/153 -index fa25eb2..0b62ac9 100755 ---- a/tests/qemu-iotests/153 -+++ b/tests/qemu-iotests/153 -@@ -178,6 +178,17 @@ ln -s ${TEST_IMG} "${TEST_IMG}.lnk" || echo "Failed to create link" - _run_qemu_with_images "${TEST_IMG}.lnk" "${TEST_IMG}" - - echo -+echo "== Active commit to intermediate layer should work when base in use ==" -+_launch_qemu -drive format=$IMGFMT,file="${TEST_IMG}.a",id=drive0,if=none \ -+ -device virtio-blk,drive=drive0 -+ -+_send_qemu_cmd $QEMU_HANDLE \ -+ "{ 'execute': 'qmp_capabilities' }" \ -+ 'return' -+_run_cmd $QEMU_IMG commit -b "${TEST_IMG}.b" "${TEST_IMG}.c" -+ -+_cleanup_qemu -+ - echo "== Closing an image should unlock it ==" - _launch_qemu - -diff --git a/tests/qemu-iotests/153.out b/tests/qemu-iotests/153.out -index 5b917b1..3f19afb 100644 ---- a/tests/qemu-iotests/153.out -+++ b/tests/qemu-iotests/153.out -@@ -373,6 +373,10 @@ Is another process using the image? - QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2: Failed to get "write" lock - Is another process using the image? - -+== Active commit to intermediate layer should work when base in use == -+{"return": {}} -+ -+_qemu_img_wrapper commit -b TEST_DIR/t.qcow2.b TEST_DIR/t.qcow2.c - == Closing an image should unlock it == - {"return": {}} - Adding drive --- -1.8.3.1 - diff --git a/SOURCES/kvm-iotests-Add-test-221-to-catch-qemu-img-map-regressio.patch b/SOURCES/kvm-iotests-Add-test-221-to-catch-qemu-img-map-regressio.patch new file mode 100644 index 0000000..074fcc9 --- /dev/null +++ b/SOURCES/kvm-iotests-Add-test-221-to-catch-qemu-img-map-regressio.patch @@ -0,0 +1,142 @@ +From 267cb4b010be63dd4d8af995f496ae03cffe5f8f Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 6 Aug 2018 16:35:53 +0200 +Subject: [PATCH 04/13] iotests: Add test 221 to catch qemu-img map regression + +RH-Author: Max Reitz +Message-id: <20180806163553.13344-3-mreitz@redhat.com> +Patchwork-id: 81649 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 2/2] iotests: Add test 221 to catch qemu-img map regression +Bugzilla: 1601310 +RH-Acked-by: Eric Blake +RH-Acked-by: Kevin Wolf +RH-Acked-by: John Snow + +From: Eric Blake + +Although qemu-img creates aligned files (by rounding up), it +must also gracefully handle files that are not sector-aligned. +Test that the bug fixed in the previous patch does not recur. + +It's a bit annoying that we can see the (implicit) hole past +the end of the file on to the next sector boundary, so if we +ever reach the point where we report a byte-accurate size rather +than our current behavior of always rounding up, this test will +probably need a slight modification. + +Signed-off-by: Eric Blake +Signed-off-by: Kevin Wolf +(cherry picked from commit c6a9d2f6f9bc0c163b3a3073126464a2446bad5f) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/221 | 60 ++++++++++++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/221.out | 16 +++++++++++++ + tests/qemu-iotests/group | 1 + + 3 files changed, 77 insertions(+) + create mode 100755 tests/qemu-iotests/221 + create mode 100644 tests/qemu-iotests/221.out + +diff --git a/tests/qemu-iotests/221 b/tests/qemu-iotests/221 +new file mode 100755 +index 0000000..41c4e4b +--- /dev/null ++++ b/tests/qemu-iotests/221 +@@ -0,0 +1,60 @@ ++#!/bin/bash ++# ++# Test qemu-img vs. unaligned images ++# ++# Copyright (C) 2018 Red Hat, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++ ++seq="$(basename $0)" ++echo "QA output created by $seq" ++ ++here="$PWD" ++status=1 # failure is the default! ++ ++_cleanup() ++{ ++ _cleanup_test_img ++} ++trap "_cleanup; exit \$status" 0 1 2 3 15 ++ ++# get standard environment, filters and checks ++. ./common.rc ++. ./common.filter ++ ++_supported_fmt raw ++_supported_proto file ++_supported_os Linux ++ ++echo ++echo "=== Check mapping of unaligned raw image ===" ++echo ++ ++_make_test_img 43009 # qemu-img create rounds size up ++$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map ++ ++truncate --size=43009 "$TEST_IMG" # so we resize it and check again ++$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map ++ ++$QEMU_IO -c 'w 43008 1' "$TEST_IMG" | _filter_qemu_io # writing also rounds up ++$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map ++ ++truncate --size=43009 "$TEST_IMG" # so we resize it and check again ++$QEMU_IMG map --output=json "$TEST_IMG" | _filter_qemu_img_map ++ ++# success, all done ++echo '*** done' ++rm -f $seq.full ++status=0 +diff --git a/tests/qemu-iotests/221.out b/tests/qemu-iotests/221.out +new file mode 100644 +index 0000000..a9c0190 +--- /dev/null ++++ b/tests/qemu-iotests/221.out +@@ -0,0 +1,16 @@ ++QA output created by 221 ++ ++=== Check mapping of unaligned raw image === ++ ++Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=43009 ++[{ "start": 0, "length": 43520, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] ++[{ "start": 0, "length": 43520, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] ++wrote 1/1 bytes at offset 43008 ++1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++[{ "start": 0, "length": 40960, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, ++{ "start": 40960, "length": 2049, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, ++{ "start": 43009, "length": 511, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] ++[{ "start": 0, "length": 40960, "depth": 0, "zero": true, "data": false, "offset": OFFSET}, ++{ "start": 40960, "length": 2049, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, ++{ "start": 43009, "length": 511, "depth": 0, "zero": true, "data": false, "offset": OFFSET}] ++*** done +diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group +index 401258f..e479fe1 100644 +--- a/tests/qemu-iotests/group ++++ b/tests/qemu-iotests/group +@@ -218,6 +218,7 @@ + 217 rw auto quick + 218 rw auto quick + 219 rw auto ++221 rw auto quick + 222 rw auto quick + 223 rw auto quick + 226 auto quick +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Add-test-for-COR-across-nodes.patch b/SOURCES/kvm-iotests-Add-test-for-COR-across-nodes.patch new file mode 100644 index 0000000..0afcad3 --- /dev/null +++ b/SOURCES/kvm-iotests-Add-test-for-COR-across-nodes.patch @@ -0,0 +1,214 @@ +From d1e2ed07917410e71f10b8dda80ef94a3d333d3c Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 16:12:12 +0200 +Subject: [PATCH 36/54] iotests: Add test for COR across nodes + +RH-Author: Max Reitz +Message-id: <20180618161212.14444-11-mreitz@redhat.com> +Patchwork-id: 80771 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 10/10] iotests: Add test for COR across nodes +Bugzilla: 1518738 +RH-Acked-by: John Snow +RH-Acked-by: Kevin Wolf +RH-Acked-by: Miroslav Rezanina + +COR across nodes (that is, you have some filter node between the +actually COR target and the node that performs the COR) cannot reliably +work together with the permission system when there is no explicit COR +node that can request the WRITE_UNCHANGED permission for its child. +This is because COR (currently) sneaks its requests by the usual +permission checks, so it can work without a WRITE* permission; but if +there is a filter node in between, that will re-issue the request, which +then passes through the usual check -- and if nobody has requested a +WRITE_UNCHANGED permission, that check will fail. + +There is no real direct fix apart from hoping that there is someone who +has requested that permission; in case of just the qemu-io HMP command +(and no guest device), however, that is not the case. The real real fix +is to implement the copy-on-read flag through an implicitly added COR +node. Such a node can request the necessary permissions as shown in +this test. + +Signed-off-by: Max Reitz +Message-id: 20180421132929.21610-10-mreitz@redhat.com +Reviewed-by: Kevin Wolf +Signed-off-by: Max Reitz +(cherry picked from commit 3e7a95feb9b5d66cff7fee38b3c423135ed245f6) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/216 | 115 +++++++++++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/216.out | 28 +++++++++++ + tests/qemu-iotests/group | 1 + + 3 files changed, 144 insertions(+) + create mode 100755 tests/qemu-iotests/216 + create mode 100644 tests/qemu-iotests/216.out + +diff --git a/tests/qemu-iotests/216 b/tests/qemu-iotests/216 +new file mode 100755 +index 0000000..ca9b47a +--- /dev/null ++++ b/tests/qemu-iotests/216 +@@ -0,0 +1,115 @@ ++#!/usr/bin/env python ++# ++# Copy-on-read tests using a COR filter node ++# ++# Copyright (C) 2018 Red Hat, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++# Creator/Owner: Max Reitz ++ ++import iotests ++from iotests import log, qemu_img_pipe, qemu_io, filter_qemu_io ++ ++# Need backing file support ++iotests.verify_image_format(supported_fmts=['qcow2', 'qcow', 'qed', 'vmdk']) ++iotests.verify_platform(['linux']) ++ ++log('') ++log('=== Copy-on-read across nodes ===') ++log('') ++ ++# The old copy-on-read mechanism without a filter node cannot request ++# WRITE_UNCHANGED permissions for its child. Therefore it just tries ++# to sneak its write by the usual permission system and holds its ++# fingers crossed. However, that sneaking does not work so well when ++# there is a filter node in the way: That will receive the write ++# request and re-issue a new one to its child, which this time is a ++# proper write request that will make the permission system cough -- ++# unless there is someone at the top (like a guest device) that has ++# requested write permissions. ++# ++# A COR filter node, however, can request the proper permissions for ++# its child and therefore is not hit by this issue. ++ ++with iotests.FilePath('base.img') as base_img_path, \ ++ iotests.FilePath('top.img') as top_img_path, \ ++ iotests.VM() as vm: ++ ++ log('--- Setting up images ---') ++ log('') ++ ++ qemu_img_pipe('create', '-f', iotests.imgfmt, base_img_path, '64M') ++ ++ log(filter_qemu_io(qemu_io(base_img_path, '-c', 'write -P 1 0M 1M'))) ++ ++ qemu_img_pipe('create', '-f', iotests.imgfmt, '-b', base_img_path, ++ top_img_path) ++ ++ log(filter_qemu_io(qemu_io(top_img_path, '-c', 'write -P 2 1M 1M'))) ++ ++ log('') ++ log('--- Doing COR ---') ++ log('') ++ ++ # Compare with e.g. the following: ++ # vm.add_drive_raw('if=none,node-name=node0,copy-on-read=on,driver=raw,' \ ++ # 'file.driver=%s,file.file.filename=%s' % ++ # (iotests.imgfmt, top_img_path)) ++ # (Remove the blockdev-add instead.) ++ # ((Not tested here because it hits an assertion in the permission ++ # system.)) ++ ++ vm.launch() ++ ++ log(vm.qmp('blockdev-add', ++ node_name='node0', ++ driver='copy-on-read', ++ file={ ++ 'driver': 'raw', ++ 'file': { ++ 'driver': 'copy-on-read', ++ 'file': { ++ 'driver': 'raw', ++ 'file': { ++ 'driver': iotests.imgfmt, ++ 'file': { ++ 'driver': 'file', ++ 'filename': top_img_path ++ }, ++ 'backing': { ++ 'driver': iotests.imgfmt, ++ 'file': { ++ 'driver': 'file', ++ 'filename': base_img_path ++ } ++ } ++ } ++ } ++ } ++ })) ++ ++ # Trigger COR ++ log(vm.qmp('human-monitor-command', ++ command_line='qemu-io node0 "read 0 64M"')) ++ ++ vm.shutdown() ++ ++ log('') ++ log('--- Checking COR result ---') ++ log('') ++ ++ log(filter_qemu_io(qemu_io(base_img_path, '-c', 'discard 0 64M'))) ++ log(filter_qemu_io(qemu_io(top_img_path, '-c', 'read -P 1 0M 1M'))) ++ log(filter_qemu_io(qemu_io(top_img_path, '-c', 'read -P 2 1M 1M'))) +diff --git a/tests/qemu-iotests/216.out b/tests/qemu-iotests/216.out +new file mode 100644 +index 0000000..d3fc590 +--- /dev/null ++++ b/tests/qemu-iotests/216.out +@@ -0,0 +1,28 @@ ++ ++=== Copy-on-read across nodes === ++ ++--- Setting up images --- ++ ++wrote 1048576/1048576 bytes at offset 0 ++1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++ ++wrote 1048576/1048576 bytes at offset 1048576 ++1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++ ++ ++--- Doing COR --- ++ ++{u'return': {}} ++{u'return': u''} ++ ++--- Checking COR result --- ++ ++discard 67108864/67108864 bytes at offset 0 ++64 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++ ++read 1048576/1048576 bytes at offset 0 ++1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++ ++read 1048576/1048576 bytes at offset 1048576 ++1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++ +diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group +index cd5d26c..d228008 100644 +--- a/tests/qemu-iotests/group ++++ b/tests/qemu-iotests/group +@@ -214,4 +214,5 @@ + 213 rw auto quick + 214 rw auto + 215 rw auto quick ++216 rw auto quick + 218 rw auto quick +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Add-test-for-U-force-share-conflicts.patch b/SOURCES/kvm-iotests-Add-test-for-U-force-share-conflicts.patch new file mode 100644 index 0000000..5916b31 --- /dev/null +++ b/SOURCES/kvm-iotests-Add-test-for-U-force-share-conflicts.patch @@ -0,0 +1,82 @@ +From 071df911bc33bc213570bf40135272c8cd3bcf77 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 16:31:06 +0200 +Subject: [PATCH 39/54] iotests: Add test for -U/force-share conflicts + +RH-Author: Max Reitz +Message-id: <20180618163106.23010-4-mreitz@redhat.com> +Patchwork-id: 80773 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 3/3] iotests: Add test for -U/force-share conflicts +Bugzilla: 1576598 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Fam Zheng +RH-Acked-by: Miroslav Rezanina + +Signed-off-by: Max Reitz +Message-id: 20180502202051.15493-4-mreitz@redhat.com +Reviewed-by: Eric Blake +Signed-off-by: Max Reitz +(cherry picked from commit 4e7d73c5fbd97e55ffe5af02f24d1f7dbe3bbf20) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/153 | 17 +++++++++++++++++ + tests/qemu-iotests/153.out | 16 ++++++++++++++++ + 2 files changed, 33 insertions(+) + +diff --git a/tests/qemu-iotests/153 b/tests/qemu-iotests/153 +index a0fd815..ec508c7 100755 +--- a/tests/qemu-iotests/153 ++++ b/tests/qemu-iotests/153 +@@ -242,6 +242,23 @@ _run_cmd $QEMU_IO "${TEST_IMG}" -c 'write 0 512' + + _cleanup_qemu + ++echo ++echo "== Detecting -U and force-share conflicts ==" ++ ++echo ++echo 'No conflict:' ++$QEMU_IMG info -U --image-opts driver=null-co,force-share=on ++echo ++echo 'Conflict:' ++$QEMU_IMG info -U --image-opts driver=null-co,force-share=off ++ ++echo ++echo 'No conflict:' ++$QEMU_IO -c 'open -r -U -o driver=null-co,force-share=on' ++echo ++echo 'Conflict:' ++$QEMU_IO -c 'open -r -U -o driver=null-co,force-share=off' ++ + # success, all done + echo "*** done" + rm -f $seq.full +diff --git a/tests/qemu-iotests/153.out b/tests/qemu-iotests/153.out +index bb721cb..2510762 100644 +--- a/tests/qemu-iotests/153.out ++++ b/tests/qemu-iotests/153.out +@@ -399,4 +399,20 @@ Is another process using the image? + Closing the other + + _qemu_io_wrapper TEST_DIR/t.qcow2 -c write 0 512 ++ ++== Detecting -U and force-share conflicts == ++ ++No conflict: ++image: null-co:// ++file format: null-co ++virtual size: 1.0G (1073741824 bytes) ++disk size: unavailable ++ ++Conflict: ++qemu-img: --force-share/-U conflicts with image options ++ ++No conflict: ++ ++Conflict: ++-U conflicts with image options + *** done +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Add-test-for-cancelling-a-mirror-job.patch b/SOURCES/kvm-iotests-Add-test-for-cancelling-a-mirror-job.patch new file mode 100644 index 0000000..e9b8aa2 --- /dev/null +++ b/SOURCES/kvm-iotests-Add-test-for-cancelling-a-mirror-job.patch @@ -0,0 +1,231 @@ +From 2476593dd4bc78bbf9183e873f2ca641ce15fddf Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 14:47:36 +0200 +Subject: [PATCH 26/54] iotests: Add test for cancelling a mirror job + +RH-Author: Max Reitz +Message-id: <20180618144736.29873-4-mreitz@redhat.com> +Patchwork-id: 80745 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 3/3] iotests: Add test for cancelling a mirror job +Bugzilla: 1572856 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf +RH-Acked-by: John Snow + +We already have an extensive mirror test (041) which does cover +cancelling a mirror job, especially after it has emitted the READY +event. However, it does not check what exact events are emitted after +block-job-cancel is executed. More importantly, it does not use +throttling to ensure that it covers the case of block-job-cancel before +READY. + +It would be possible to add this case to 041, but considering it is +already our largest test file, it makes sense to create a new file for +these cases. + +Signed-off-by: Max Reitz +Message-id: 20180501220509.14152-3-mreitz@redhat.com +Signed-off-by: Jeff Cody +(cherry picked from commit dc885fff972c447f51572afc4c921a26b880731b) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/218 | 138 +++++++++++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/218.out | 30 ++++++++++ + tests/qemu-iotests/group | 1 + + 3 files changed, 169 insertions(+) + create mode 100644 tests/qemu-iotests/218 + create mode 100644 tests/qemu-iotests/218.out + +diff --git a/tests/qemu-iotests/218 b/tests/qemu-iotests/218 +new file mode 100644 +index 0000000..92c331b +--- /dev/null ++++ b/tests/qemu-iotests/218 +@@ -0,0 +1,138 @@ ++#!/usr/bin/env python ++# ++# This test covers what happens when a mirror block job is cancelled ++# in various phases of its existence. ++# ++# Note that this test only checks the emitted events (i.e. ++# BLOCK_JOB_COMPLETED vs. BLOCK_JOB_CANCELLED), it does not compare ++# whether the target is in sync with the source when the ++# BLOCK_JOB_COMPLETED event occurs. This is covered by other tests ++# (such as 041). ++# ++# Copyright (C) 2018 Red Hat, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++# Creator/Owner: Max Reitz ++ ++import iotests ++from iotests import log ++ ++iotests.verify_platform(['linux']) ++ ++ ++# Launches the VM, adds two null-co nodes (source and target), and ++# starts a blockdev-mirror job on them. ++# ++# Either both or none of speed and buf_size must be given. ++ ++def start_mirror(vm, speed=None, buf_size=None): ++ vm.launch() ++ ++ ret = vm.qmp('blockdev-add', ++ node_name='source', ++ driver='null-co', ++ size=1048576) ++ assert ret['return'] == {} ++ ++ ret = vm.qmp('blockdev-add', ++ node_name='target', ++ driver='null-co', ++ size=1048576) ++ assert ret['return'] == {} ++ ++ if speed is not None: ++ ret = vm.qmp('blockdev-mirror', ++ job_id='mirror', ++ device='source', ++ target='target', ++ sync='full', ++ speed=speed, ++ buf_size=buf_size) ++ else: ++ ret = vm.qmp('blockdev-mirror', ++ job_id='mirror', ++ device='source', ++ target='target', ++ sync='full') ++ ++ assert ret['return'] == {} ++ ++ ++log('') ++log('=== Cancel mirror job before convergence ===') ++log('') ++ ++log('--- force=false ---') ++log('') ++ ++with iotests.VM() as vm: ++ # Low speed so it does not converge ++ start_mirror(vm, 65536, 65536) ++ ++ log('Cancelling job') ++ log(vm.qmp('block-job-cancel', device='mirror', force=False)) ++ ++ log(vm.event_wait('BLOCK_JOB_CANCELLED'), ++ filters=[iotests.filter_qmp_event]) ++ ++log('') ++log('--- force=true ---') ++log('') ++ ++with iotests.VM() as vm: ++ # Low speed so it does not converge ++ start_mirror(vm, 65536, 65536) ++ ++ log('Cancelling job') ++ log(vm.qmp('block-job-cancel', device='mirror', force=True)) ++ ++ log(vm.event_wait('BLOCK_JOB_CANCELLED'), ++ filters=[iotests.filter_qmp_event]) ++ ++ ++log('') ++log('=== Cancel mirror job after convergence ===') ++log('') ++ ++log('--- force=false ---') ++log('') ++ ++with iotests.VM() as vm: ++ start_mirror(vm) ++ ++ log(vm.event_wait('BLOCK_JOB_READY'), ++ filters=[iotests.filter_qmp_event]) ++ ++ log('Cancelling job') ++ log(vm.qmp('block-job-cancel', device='mirror', force=False)) ++ ++ log(vm.event_wait('BLOCK_JOB_COMPLETED'), ++ filters=[iotests.filter_qmp_event]) ++ ++log('') ++log('--- force=true ---') ++log('') ++ ++with iotests.VM() as vm: ++ start_mirror(vm) ++ ++ log(vm.event_wait('BLOCK_JOB_READY'), ++ filters=[iotests.filter_qmp_event]) ++ ++ log('Cancelling job') ++ log(vm.qmp('block-job-cancel', device='mirror', force=True)) ++ ++ log(vm.event_wait('BLOCK_JOB_CANCELLED'), ++ filters=[iotests.filter_qmp_event]) +diff --git a/tests/qemu-iotests/218.out b/tests/qemu-iotests/218.out +new file mode 100644 +index 0000000..7dbf78e +--- /dev/null ++++ b/tests/qemu-iotests/218.out +@@ -0,0 +1,30 @@ ++ ++=== Cancel mirror job before convergence === ++ ++--- force=false --- ++ ++Cancelling job ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'device': u'mirror', u'type': u'mirror', u'speed': 65536, u'len': 1048576, u'offset': 65536}, u'event': u'BLOCK_JOB_CANCELLED'} ++ ++--- force=true --- ++ ++Cancelling job ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'device': u'mirror', u'type': u'mirror', u'speed': 65536, u'len': 1048576, u'offset': 65536}, u'event': u'BLOCK_JOB_CANCELLED'} ++ ++=== Cancel mirror job after convergence === ++ ++--- force=false --- ++ ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'device': u'mirror', u'type': u'mirror', u'speed': 0, u'len': 1048576, u'offset': 1048576}, u'event': u'BLOCK_JOB_READY'} ++Cancelling job ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'device': u'mirror', u'type': u'mirror', u'speed': 0, u'len': 1048576, u'offset': 1048576}, u'event': u'BLOCK_JOB_COMPLETED'} ++ ++--- force=true --- ++ ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'device': u'mirror', u'type': u'mirror', u'speed': 0, u'len': 1048576, u'offset': 1048576}, u'event': u'BLOCK_JOB_READY'} ++Cancelling job ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'device': u'mirror', u'type': u'mirror', u'speed': 0, u'len': 1048576, u'offset': 1048576}, u'event': u'BLOCK_JOB_CANCELLED'} +diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group +index 99777ec..3a89aed 100644 +--- a/tests/qemu-iotests/group ++++ b/tests/qemu-iotests/group +@@ -212,3 +212,4 @@ + 211 rw auto quick + 212 rw auto quick + 213 rw auto quick ++218 rw auto quick +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Add-test-for-qemu-img-convert-C-compatibilit.patch b/SOURCES/kvm-iotests-Add-test-for-qemu-img-convert-C-compatibilit.patch new file mode 100644 index 0000000..149e0d2 --- /dev/null +++ b/SOURCES/kvm-iotests-Add-test-for-qemu-img-convert-C-compatibilit.patch @@ -0,0 +1,69 @@ +From 1ed06a7c22bbae0f9e17147c86ad2ecc69efb9bf Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Wed, 1 Aug 2018 06:35:38 +0200 +Subject: [PATCH 02/13] iotests: Add test for 'qemu-img convert -C' + compatibility + +RH-Author: Fam Zheng +Message-id: <20180801063538.32582-3-famz@redhat.com> +Patchwork-id: 81562 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 2/2] iotests: Add test for 'qemu-img convert -C' compatibility +Bugzilla: 1607774 +RH-Acked-by: Kevin Wolf +RH-Acked-by: John Snow +RH-Acked-by: Miroslav Rezanina + +Signed-off-by: Fam Zheng +Signed-off-by: Kevin Wolf +(cherry picked from commit 8ba4f10fa689251facd483c3ee0ef4dd4e9bec53) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/082 | 8 ++++++++ + tests/qemu-iotests/082.out | 11 +++++++++++ + 2 files changed, 19 insertions(+) + +diff --git a/tests/qemu-iotests/082 b/tests/qemu-iotests/082 +index a872f77..3e605d5 100755 +--- a/tests/qemu-iotests/082 ++++ b/tests/qemu-iotests/082 +@@ -158,6 +158,14 @@ run_qemu_img convert -o help + run_qemu_img convert -O bochs -o help + + echo ++echo === convert: -C and other options === ++ ++# Adding the help option to a command without other -o options ++run_qemu_img convert -C -S 4k -O $IMGFMT "$TEST_IMG" "$TEST_IMG".target ++run_qemu_img convert -C -S 8k -O $IMGFMT "$TEST_IMG" "$TEST_IMG".target ++run_qemu_img convert -C -c -O $IMGFMT "$TEST_IMG" "$TEST_IMG".target ++ ++echo + echo === amend: Options specified more than once === + + # Last -f should win +diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out +index 60ef87c..19e9fb1 100644 +--- a/tests/qemu-iotests/082.out ++++ b/tests/qemu-iotests/082.out +@@ -508,6 +508,17 @@ size Virtual disk size + Testing: convert -O bochs -o help + qemu-img: Format driver 'bochs' does not support image creation + ++=== convert: -C and other options === ++ ++Testing: convert -C -S 4k -O qcow2 TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.target ++qemu-img: Cannot enable copy offloading when -S is used ++ ++Testing: convert -C -S 8k -O qcow2 TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.target ++qemu-img: Cannot enable copy offloading when -S is used ++ ++Testing: convert -C -c -O qcow2 TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.target ++qemu-img: Cannot enable copy offloading when -c is used ++ + === amend: Options specified more than once === + + Testing: amend -f foo -f qcow2 -o lazy_refcounts=on TEST_DIR/t.qcow2 +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Add-test-for-rebasing-with-relative-paths.patch b/SOURCES/kvm-iotests-Add-test-for-rebasing-with-relative-paths.patch new file mode 100644 index 0000000..19d4eff --- /dev/null +++ b/SOURCES/kvm-iotests-Add-test-for-rebasing-with-relative-paths.patch @@ -0,0 +1,168 @@ +From f5f8208d1e759b789da9f2ae03b2320c355dbf89 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 17:48:33 +0200 +Subject: [PATCH 11/89] iotests: Add test for rebasing with relative paths + +RH-Author: Max Reitz +Message-id: <20180618174833.19439-3-mreitz@redhat.com> +Patchwork-id: 80789 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 2/2] iotests: Add test for rebasing with relative paths +Bugzilla: 1569835 +RH-Acked-by: John Snow +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi + +Signed-off-by: Max Reitz +Reviewed-by: Eric Blake +Message-id: 20180509182002.8044-3-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit 28036a7f7044fddb79819e3c8fcb4ae5605c60e0) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/024 | 82 ++++++++++++++++++++++++++++++++++++++++++++-- + tests/qemu-iotests/024.out | 30 +++++++++++++++++ + 2 files changed, 109 insertions(+), 3 deletions(-) + +diff --git a/tests/qemu-iotests/024 b/tests/qemu-iotests/024 +index e0d77ce..4071ed6 100755 +--- a/tests/qemu-iotests/024 ++++ b/tests/qemu-iotests/024 +@@ -29,9 +29,14 @@ 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" ++ _cleanup_test_img ++ rm -f "$TEST_DIR/t.$IMGFMT.base_old" ++ rm -f "$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" ++ rmdir "$TEST_DIR/subdir" 2> /dev/null + } + trap "_cleanup; exit \$status" 0 1 2 3 15 + +@@ -123,6 +128,77 @@ io_pattern readv $((13 * CLUSTER_SIZE)) $CLUSTER_SIZE 0 1 0x00 + io_pattern readv $((14 * CLUSTER_SIZE)) $CLUSTER_SIZE 0 1 0x11 + io_pattern readv $((15 * CLUSTER_SIZE)) $CLUSTER_SIZE 0 1 0x00 + ++echo ++echo "=== Test rebase in a subdirectory of the working directory ===" ++echo ++ ++# Clean up the old images beforehand so they do not interfere with ++# this test ++_cleanup ++ ++mkdir "$TEST_DIR/subdir" ++ ++# Relative to the overlay ++BASE_OLD_OREL="t.$IMGFMT.base_old" ++BASE_NEW_OREL="t.$IMGFMT.base_new" ++ ++# Relative to $TEST_DIR (which is going to be our working directory) ++OVERLAY_WREL="subdir/t.$IMGFMT" ++ ++BASE_OLD="$TEST_DIR/subdir/$BASE_OLD_OREL" ++BASE_NEW="$TEST_DIR/subdir/$BASE_NEW_OREL" ++OVERLAY="$TEST_DIR/$OVERLAY_WREL" ++ ++# Test done here: ++# ++# Backing (old): 11 11 -- 11 ++# Backing (new): -- 22 22 11 ++# Overlay: -- -- -- -- ++# ++# Rebasing works, we have verified that above. Here, we just want to ++# see that rebasing is done for the correct target backing file. ++ ++TEST_IMG=$BASE_OLD _make_test_img 1M ++TEST_IMG=$BASE_NEW _make_test_img 1M ++TEST_IMG=$OVERLAY _make_test_img -b "$BASE_OLD_OREL" 1M ++ ++echo ++ ++$QEMU_IO "$BASE_OLD" \ ++ -c "write -P 0x11 $((0 * CLUSTER_SIZE)) $((2 * CLUSTER_SIZE))" \ ++ -c "write -P 0x11 $((3 * CLUSTER_SIZE)) $((1 * CLUSTER_SIZE))" \ ++ | _filter_qemu_io ++ ++$QEMU_IO "$BASE_NEW" \ ++ -c "write -P 0x22 $((1 * CLUSTER_SIZE)) $((2 * CLUSTER_SIZE))" \ ++ -c "write -P 0x11 $((3 * CLUSTER_SIZE)) $((1 * CLUSTER_SIZE))" \ ++ | _filter_qemu_io ++ ++echo ++ ++pushd "$TEST_DIR" >/dev/null ++$QEMU_IMG rebase -f "$IMGFMT" -b "$BASE_NEW_OREL" "$OVERLAY_WREL" ++popd >/dev/null ++ ++# Verify the backing path is correct ++TEST_IMG=$OVERLAY _img_info | grep '^backing file' ++ ++echo ++ ++# Verify the data is correct ++$QEMU_IO "$OVERLAY" \ ++ -c "read -P 0x11 $((0 * CLUSTER_SIZE)) $CLUSTER_SIZE" \ ++ -c "read -P 0x11 $((1 * CLUSTER_SIZE)) $CLUSTER_SIZE" \ ++ -c "read -P 0x00 $((2 * CLUSTER_SIZE)) $CLUSTER_SIZE" \ ++ -c "read -P 0x11 $((3 * CLUSTER_SIZE)) $CLUSTER_SIZE" \ ++ | _filter_qemu_io ++ ++echo ++ ++# Verify that cluster #3 is not allocated (because it is the same in ++# $BASE_OLD and $BASE_NEW) ++$QEMU_IMG map "$OVERLAY" | _filter_qemu_img_map ++ + + # success, all done + echo "*** done" +diff --git a/tests/qemu-iotests/024.out b/tests/qemu-iotests/024.out +index 33cfaf5..024dc78 100644 +--- a/tests/qemu-iotests/024.out ++++ b/tests/qemu-iotests/024.out +@@ -141,4 +141,34 @@ read 65536/65536 bytes at offset 917504 + === IO: pattern 0x00 + read 65536/65536 bytes at offset 983040 + 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++ ++=== Test rebase in a subdirectory of the working directory === ++ ++Formatting 'TEST_DIR/subdir/t.IMGFMT.base_old', fmt=IMGFMT size=1048576 ++Formatting 'TEST_DIR/subdir/t.IMGFMT.base_new', fmt=IMGFMT size=1048576 ++Formatting 'TEST_DIR/subdir/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=t.IMGFMT.base_old ++ ++wrote 131072/131072 bytes at offset 0 ++128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++wrote 65536/65536 bytes at offset 196608 ++64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++wrote 131072/131072 bytes at offset 65536 ++128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++wrote 65536/65536 bytes at offset 196608 ++64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++ ++backing file: t.IMGFMT.base_new (actual path: TEST_DIR/subdir/t.IMGFMT.base_new) ++ ++read 65536/65536 bytes at offset 0 ++64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++read 65536/65536 bytes at offset 65536 ++64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++read 65536/65536 bytes at offset 131072 ++64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++read 65536/65536 bytes at offset 196608 ++64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++ ++Offset Length File ++0 0x30000 TEST_DIR/subdir/t.IMGFMT ++0x30000 0x10000 TEST_DIR/subdir/t.IMGFMT.base_new + *** done +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Clean-up-wrap-image-in-197.patch b/SOURCES/kvm-iotests-Clean-up-wrap-image-in-197.patch new file mode 100644 index 0000000..8ffc184 --- /dev/null +++ b/SOURCES/kvm-iotests-Clean-up-wrap-image-in-197.patch @@ -0,0 +1,42 @@ +From 4a2de12de1790d63467be43c1af8da4800b15c2c Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 16:12:10 +0200 +Subject: [PATCH 34/54] iotests: Clean up wrap image in 197 + +RH-Author: Max Reitz +Message-id: <20180618161212.14444-9-mreitz@redhat.com> +Patchwork-id: 80768 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 08/10] iotests: Clean up wrap image in 197 +Bugzilla: 1518738 +RH-Acked-by: John Snow +RH-Acked-by: Kevin Wolf +RH-Acked-by: Miroslav Rezanina + +Signed-off-by: Max Reitz +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Alberto Garcia +Message-id: 20180421132929.21610-8-mreitz@redhat.com +Reviewed-by: Kevin Wolf +Signed-off-by: Max Reitz +(cherry picked from commit 5fdc0b73eb68d107944cfa65185fb155b511e496) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/197 | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197 +index 5e869fe..3ae4975 100755 +--- a/tests/qemu-iotests/197 ++++ b/tests/qemu-iotests/197 +@@ -44,6 +44,7 @@ esac + _cleanup() + { + _cleanup_test_img ++ rm -f "$TEST_WRAP" + rm -f "$BLKDBG_CONF" + } + trap "_cleanup; exit \$status" 0 1 2 3 15 +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Copy-197-for-COR-filter-driver.patch b/SOURCES/kvm-iotests-Copy-197-for-COR-filter-driver.patch new file mode 100644 index 0000000..eafabba --- /dev/null +++ b/SOURCES/kvm-iotests-Copy-197-for-COR-filter-driver.patch @@ -0,0 +1,203 @@ +From 6acc674a6d77b4d1b36545c7f00251b264f99d78 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 16:12:11 +0200 +Subject: [PATCH 35/54] iotests: Copy 197 for COR filter driver + +RH-Author: Max Reitz +Message-id: <20180618161212.14444-10-mreitz@redhat.com> +Patchwork-id: 80769 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 09/10] iotests: Copy 197 for COR filter driver +Bugzilla: 1518738 +RH-Acked-by: John Snow +RH-Acked-by: Kevin Wolf +RH-Acked-by: Miroslav Rezanina + +iotest 197 tests copy-on-read using the (now old) copy-on-read flag. +Copy it to 215 and modify it to use the COR filter driver instead. + +Signed-off-by: Max Reitz +Message-id: 20180421132929.21610-9-mreitz@redhat.com +Reviewed-by: Kevin Wolf +Signed-off-by: Max Reitz +(cherry picked from commit a62cbac4ce2db79c14ff299e98ee556b57467c19) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/215 | 120 +++++++++++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/215.out | 26 ++++++++++ + tests/qemu-iotests/group | 1 + + 3 files changed, 147 insertions(+) + create mode 100755 tests/qemu-iotests/215 + create mode 100644 tests/qemu-iotests/215.out + +diff --git a/tests/qemu-iotests/215 b/tests/qemu-iotests/215 +new file mode 100755 +index 0000000..2e616ed +--- /dev/null ++++ b/tests/qemu-iotests/215 +@@ -0,0 +1,120 @@ ++#!/bin/bash ++# ++# Test case for copy-on-read into qcow2, using the COR filter driver ++# ++# Copyright (C) 2018 Red Hat, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++ ++seq="$(basename $0)" ++echo "QA output created by $seq" ++ ++here="$PWD" ++status=1 # failure is the default! ++ ++# get standard environment, filters and checks ++. ./common.rc ++. ./common.filter ++ ++TEST_WRAP="$TEST_DIR/t.wrap.qcow2" ++BLKDBG_CONF="$TEST_DIR/blkdebug.conf" ++ ++# Sanity check: our use of blkdebug fails if $TEST_DIR contains spaces ++# or other problems ++case "$TEST_DIR" in ++ *[^-_a-zA-Z0-9/]*) ++ _notrun "Suspicious TEST_DIR='$TEST_DIR', cowardly refusing to run" ;; ++esac ++ ++_cleanup() ++{ ++ _cleanup_test_img ++ rm -f "$TEST_WRAP" ++ rm -f "$BLKDBG_CONF" ++} ++trap "_cleanup; exit \$status" 0 1 2 3 15 ++ ++# Test is supported for any backing file; but we force qcow2 for our wrapper. ++_supported_fmt generic ++_supported_proto generic ++_supported_os Linux ++# LUKS support may be possible, but it complicates things. ++_unsupported_fmt luks ++ ++echo ++echo '=== Copy-on-read ===' ++echo ++ ++# Prep the images ++# VPC rounds image sizes to a specific geometry, force a specific size. ++if [ "$IMGFMT" = "vpc" ]; then ++ IMGOPTS=$(_optstr_add "$IMGOPTS" "force_size") ++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 ++$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, ++# does not re-write the allocated cluster ++cat > "$BLKDBG_CONF" <&1 | _filter_qemu_io) ++case $output in ++ *allocate*) ++ _notrun "Insufficent memory to run test" ;; ++ *) printf '%s\n' "$output" ;; ++esac ++$QEMU_IO \ ++ -c "open -o driver=copy-on-read,file.driver=qcow2 $TEST_WRAP" \ ++ -c "read -P 0 $((3*1024*1024*1024 + 1024)) 1k" \ ++ | _filter_qemu_io ++ ++# Copy-on-read is incompatible with read-only ++$QEMU_IO \ ++ -c "open -r -o driver=copy-on-read,file.driver=qcow2 $TEST_WRAP" \ ++ 2>&1 | _filter_testdir ++ ++# Break the backing chain, and show that images are identical, and that ++# we properly copied over explicit zeros. ++$QEMU_IMG rebase -u -b "" -f qcow2 "$TEST_WRAP" ++$QEMU_IO -f qcow2 -c map "$TEST_WRAP" ++_check_test_img ++$QEMU_IMG compare -f $IMGFMT -F qcow2 "$TEST_IMG" "$TEST_WRAP" ++ ++# success, all done ++echo '*** done' ++status=0 +diff --git a/tests/qemu-iotests/215.out b/tests/qemu-iotests/215.out +new file mode 100644 +index 0000000..70b0f5f +--- /dev/null ++++ b/tests/qemu-iotests/215.out +@@ -0,0 +1,26 @@ ++QA output created by 215 ++ ++=== Copy-on-read === ++ ++Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 ++wrote 1024/1024 bytes at offset 3221225472 ++1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++Formatting 'TEST_DIR/t.wrap.IMGFMT', fmt=IMGFMT size=4294967296 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT ++wrote 65536/65536 bytes at offset 1048576 ++64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++read 131072/131072 bytes at offset 1048576 ++128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++read 0/0 bytes at offset 0 ++0 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++read 2147483136/2147483136 bytes at offset 1024 ++2 GiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++read 1024/1024 bytes at offset 3221226496 ++1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++can't open device TEST_DIR/t.wrap.qcow2: Block node is read-only ++2 GiB (0x80010000) bytes allocated at offset 0 bytes (0x0) ++1023.938 MiB (0x3fff0000) bytes not allocated at offset 2 GiB (0x80010000) ++64 KiB (0x10000) bytes allocated at offset 3 GiB (0xc0000000) ++1023.938 MiB (0x3fff0000) bytes not allocated at offset 3 GiB (0xc0010000) ++No errors were found on the image. ++Images are identical. ++*** done +diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group +index ba7a2d1..cd5d26c 100644 +--- a/tests/qemu-iotests/group ++++ b/tests/qemu-iotests/group +@@ -213,4 +213,5 @@ + 212 rw auto quick + 213 rw auto quick + 214 rw auto ++215 rw auto quick + 218 rw auto quick +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Fix-195-if-IMGFMT-is-part-of-TEST_DIR.patch b/SOURCES/kvm-iotests-Fix-195-if-IMGFMT-is-part-of-TEST_DIR.patch deleted file mode 100644 index 7b97923..0000000 --- a/SOURCES/kvm-iotests-Fix-195-if-IMGFMT-is-part-of-TEST_DIR.patch +++ /dev/null @@ -1,67 +0,0 @@ -From d13b20d0650519722da79a9cb9e4e0a1f2bee26c Mon Sep 17 00:00:00 2001 -From: Kevin Wolf -Date: Mon, 4 Dec 2017 12:10:07 +0100 -Subject: [PATCH 36/36] iotests: Fix 195 if IMGFMT is part of TEST_DIR - -RH-Author: Kevin Wolf -Message-id: <20171204121007.12964-9-kwolf@redhat.com> -Patchwork-id: 78108 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 8/8] iotests: Fix 195 if IMGFMT is part of TEST_DIR -Bugzilla: 1492178 -RH-Acked-by: Fam Zheng -RH-Acked-by: Max Reitz -RH-Acked-by: Jeffrey Cody - -From: Max Reitz - -do_run_qemu() in iotest 195 first applies _filter_imgfmt when printing -qemu's command line and _filter_testdir only afterwards. Therefore, if -the image format is part of the test directory path, _filter_testdir -will no longer apply and the actual output will differ from the -reference output even in case of success. - -For example, TEST_DIR might be "/tmp/test-qcow2", in which case -_filter_imgfmt first transforms this to "/tmp/test-IMGFMT" which is no -longer recognized as the TEST_DIR by _filter_testdir. - -Fix this by not applying _filter_imgfmt in do_run_qemu() but in -run_qemu() instead, and only after _filter_testdir. - -Signed-off-by: Max Reitz -Message-id: 20170927211334.3988-1-mreitz@redhat.com -Reviewed-by: Eric Blake -Signed-off-by: Max Reitz -(cherry picked from commit 47500c6775813c8f2b5a5de04d84222f3cecc62d) -Signed-off-by: Kevin Wolf -Signed-off-by: Miroslav Rezanina ---- - tests/qemu-iotests/195 | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/tests/qemu-iotests/195 b/tests/qemu-iotests/195 -index 05a239c..e7a403d 100644 ---- a/tests/qemu-iotests/195 -+++ b/tests/qemu-iotests/195 -@@ -44,15 +44,16 @@ _supported_os Linux - - function do_run_qemu() - { -- echo Testing: "$@" | _filter_imgfmt -+ echo Testing: "$@" - $QEMU -nographic -qmp-pretty stdio -serial none "$@" - echo - } - - function run_qemu() - { -- do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp \ -- | _filter_qemu_io | _filter_generated_node_ids -+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_imgfmt | _filter_qemu \ -+ | _filter_qmp | _filter_qemu_io \ -+ | _filter_generated_node_ids - } - - size=64M --- -1.8.3.1 - diff --git a/SOURCES/kvm-iotests-Fix-219-s-timing.patch b/SOURCES/kvm-iotests-Fix-219-s-timing.patch new file mode 100644 index 0000000..f07a3e4 --- /dev/null +++ b/SOURCES/kvm-iotests-Fix-219-s-timing.patch @@ -0,0 +1,149 @@ +From 36d1b90499cb0b8ab992d249d742de66e6fc24b7 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:55 +0200 +Subject: [PATCH 86/89] iotests: Fix 219's timing + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-73-kwolf@redhat.com> +Patchwork-id: 81111 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 72/73] iotests: Fix 219's timing +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +From: Max Reitz + +219 has two issues that may lead to sporadic failure, both of which are +the result of issuing query-jobs too early after a job has been +modified. This can then lead to different results based on whether the +modification has taken effect already or not. + +First, query-jobs is issued right after the job has been created. +Besides its current progress possibly being in any random state (which +has already been taken care of), its total progress too is basically +arbitrary, because the job may not yet have been able to determine it. +This patch addresses this by just filtering the total progress, like +what has been done for the current progress already. However, for more +clarity, the filtering is changed to replace the values by a string +'FILTERED' instead of deleting them. + +Secondly, query-jobs is issued right after a job has been resumed. The +job may or may not yet have had the time to actually perform any I/O, +and thus its current progress may or may not have advanced. To make +sure it has indeed advanced (which is what the reference output already +assumes), keep querying it until it has. + +Signed-off-by: Max Reitz +Message-id: 20180606190628.8170-1-mreitz@redhat.com +Reviewed-by: Eric Blake +Signed-off-by: Max Reitz +(cherry picked from commit 83f90b535a0d5e64056c087aa4022ea35c59bcd0) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/219 | 26 ++++++++++++++++++++------ + tests/qemu-iotests/219.out | 10 +++++----- + 2 files changed, 25 insertions(+), 11 deletions(-) + +diff --git a/tests/qemu-iotests/219 b/tests/qemu-iotests/219 +index 898a26e..c03bbdb 100755 +--- a/tests/qemu-iotests/219 ++++ b/tests/qemu-iotests/219 +@@ -42,11 +42,24 @@ def test_pause_resume(vm): + iotests.log(vm.qmp(pause_cmd, **{pause_arg: 'job0'})) + pause_wait(vm, 'job0') + iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE'))) +- iotests.log(vm.qmp('query-jobs')) ++ result = vm.qmp('query-jobs') ++ iotests.log(result) ++ ++ old_progress = result['return'][0]['current-progress'] ++ total_progress = result['return'][0]['total-progress'] + + iotests.log(vm.qmp(resume_cmd, **{resume_arg: 'job0'})) + iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE'))) +- iotests.log(vm.qmp('query-jobs')) ++ if old_progress < total_progress: ++ # Wait for the job to advance ++ while result['return'][0]['current-progress'] == old_progress: ++ result = vm.qmp('query-jobs') ++ iotests.log(result) ++ else: ++ # Already reached the end, so the job cannot advance ++ # any further; therefore, the query-jobs result can be ++ # logged immediately ++ iotests.log(vm.qmp('query-jobs')) + + def test_job_lifecycle(vm, job, job_args, has_ready=False): + iotests.log('') +@@ -58,12 +71,13 @@ def test_job_lifecycle(vm, job, job_args, has_ready=False): + iotests.log(vm.qmp(job, job_id='job0', **job_args)) + + # Depending on the storage, the first request may or may not have completed +- # yet, so filter out the progress. Later query-job calls don't need the +- # filtering because the progress is made deterministic by the block job +- # speed ++ # yet (and the total progress may not have been fully determined yet), so ++ # filter out the progress. Later query-job calls don't need the filtering ++ # because the progress is made deterministic by the block job speed + result = vm.qmp('query-jobs') + for j in result['return']: +- del j['current-progress'] ++ j['current-progress'] = 'FILTERED' ++ j['total-progress'] = 'FILTERED' + iotests.log(result) + + # undefined -> created -> running +diff --git a/tests/qemu-iotests/219.out b/tests/qemu-iotests/219.out +index 346801b..6dc07bc 100644 +--- a/tests/qemu-iotests/219.out ++++ b/tests/qemu-iotests/219.out +@@ -3,7 +3,7 @@ Launching VM... + + Starting block job: drive-mirror (auto-finalize: True; auto-dismiss: True) + {u'return': {}} +-{u'return': [{u'status': u'running', u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} ++{u'return': [{u'status': u'running', u'current-progress': 'FILTERED', u'total-progress': 'FILTERED', u'id': u'job0', u'type': u'mirror'}]} + {u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'created', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} + {u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} + +@@ -93,7 +93,7 @@ Waiting for PENDING state... + + Starting block job: drive-backup (auto-finalize: True; auto-dismiss: True) + {u'return': {}} +-{u'return': [{u'status': u'running', u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'return': [{u'status': u'running', u'current-progress': 'FILTERED', u'total-progress': 'FILTERED', u'id': u'job0', u'type': u'backup'}]} + {u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'created', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} + {u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} + +@@ -144,7 +144,7 @@ Waiting for PENDING state... + + Starting block job: drive-backup (auto-finalize: True; auto-dismiss: False) + {u'return': {}} +-{u'return': [{u'status': u'running', u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'return': [{u'status': u'running', u'current-progress': 'FILTERED', u'total-progress': 'FILTERED', u'id': u'job0', u'type': u'backup'}]} + {u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'created', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} + {u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} + +@@ -203,7 +203,7 @@ Waiting for PENDING state... + + Starting block job: drive-backup (auto-finalize: False; auto-dismiss: True) + {u'return': {}} +-{u'return': [{u'status': u'running', u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'return': [{u'status': u'running', u'current-progress': 'FILTERED', u'total-progress': 'FILTERED', u'id': u'job0', u'type': u'backup'}]} + {u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'created', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} + {u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} + +@@ -262,7 +262,7 @@ Waiting for PENDING state... + + Starting block job: drive-backup (auto-finalize: False; auto-dismiss: False) + {u'return': {}} +-{u'return': [{u'status': u'running', u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'return': [{u'status': u'running', u'current-progress': 'FILTERED', u'total-progress': 'FILTERED', u'id': u'job0', u'type': u'backup'}]} + {u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'created', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} + {u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Let-216-make-use-of-qemu-io-s-exit-code.patch b/SOURCES/kvm-iotests-Let-216-make-use-of-qemu-io-s-exit-code.patch new file mode 100644 index 0000000..cc4ae18 --- /dev/null +++ b/SOURCES/kvm-iotests-Let-216-make-use-of-qemu-io-s-exit-code.patch @@ -0,0 +1,115 @@ +From 5914d4c0869766e245b5ed5ea857af72c3b0049e Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 16:43:12 +0200 +Subject: [PATCH 44/54] iotests: Let 216 make use of qemu-io's exit code + +RH-Author: Max Reitz +Message-id: <20180618164312.24423-6-mreitz@redhat.com> +Patchwork-id: 80776 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 5/5] iotests: Let 216 make use of qemu-io's exit code +Bugzilla: 1519617 +RH-Acked-by: John Snow +RH-Acked-by: Kevin Wolf +RH-Acked-by: Miroslav Rezanina + +As a showcase of how you can use qemu-io's exit code to determine +success or failure (same for qemu-img), this test is changed to use +qemu_io_silent() instead of qemu_io(), and to assert the exit code +instead of logging the filtered result. + +One real advantage of this is that in case of an error, you get a +backtrace that helps you locate the issue in the test file quickly. + +Signed-off-by: Max Reitz +Reviewed-by: Eric Blake +Message-id: 20180509194302.21585-6-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit e4ca4e981a0a389d6af5dc5d8b5fbdd1a05276a0) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/216 | 23 ++++++++++++----------- + tests/qemu-iotests/216.out | 17 ++--------------- + 2 files changed, 14 insertions(+), 26 deletions(-) + +diff --git a/tests/qemu-iotests/216 b/tests/qemu-iotests/216 +index ca9b47a..3c0ae54 100755 +--- a/tests/qemu-iotests/216 ++++ b/tests/qemu-iotests/216 +@@ -20,7 +20,7 @@ + # Creator/Owner: Max Reitz + + import iotests +-from iotests import log, qemu_img_pipe, qemu_io, filter_qemu_io ++from iotests import log, qemu_img, qemu_io_silent + + # Need backing file support + iotests.verify_image_format(supported_fmts=['qcow2', 'qcow', 'qed', 'vmdk']) +@@ -50,14 +50,13 @@ with iotests.FilePath('base.img') as base_img_path, \ + log('--- Setting up images ---') + log('') + +- qemu_img_pipe('create', '-f', iotests.imgfmt, base_img_path, '64M') ++ assert qemu_img('create', '-f', iotests.imgfmt, base_img_path, '64M') == 0 ++ assert qemu_io_silent(base_img_path, '-c', 'write -P 1 0M 1M') == 0 ++ assert qemu_img('create', '-f', iotests.imgfmt, '-b', base_img_path, ++ top_img_path) == 0 ++ assert qemu_io_silent(top_img_path, '-c', 'write -P 2 1M 1M') == 0 + +- log(filter_qemu_io(qemu_io(base_img_path, '-c', 'write -P 1 0M 1M'))) +- +- qemu_img_pipe('create', '-f', iotests.imgfmt, '-b', base_img_path, +- top_img_path) +- +- log(filter_qemu_io(qemu_io(top_img_path, '-c', 'write -P 2 1M 1M'))) ++ log('Done') + + log('') + log('--- Doing COR ---') +@@ -110,6 +109,8 @@ with iotests.FilePath('base.img') as base_img_path, \ + log('--- Checking COR result ---') + log('') + +- log(filter_qemu_io(qemu_io(base_img_path, '-c', 'discard 0 64M'))) +- log(filter_qemu_io(qemu_io(top_img_path, '-c', 'read -P 1 0M 1M'))) +- log(filter_qemu_io(qemu_io(top_img_path, '-c', 'read -P 2 1M 1M'))) ++ assert qemu_io_silent(base_img_path, '-c', 'discard 0 64M') == 0 ++ assert qemu_io_silent(top_img_path, '-c', 'read -P 1 0M 1M') == 0 ++ assert qemu_io_silent(top_img_path, '-c', 'read -P 2 1M 1M') == 0 ++ ++ log('Done') +diff --git a/tests/qemu-iotests/216.out b/tests/qemu-iotests/216.out +index d3fc590..45ea857 100644 +--- a/tests/qemu-iotests/216.out ++++ b/tests/qemu-iotests/216.out +@@ -3,12 +3,7 @@ + + --- Setting up images --- + +-wrote 1048576/1048576 bytes at offset 0 +-1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +- +-wrote 1048576/1048576 bytes at offset 1048576 +-1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +- ++Done + + --- Doing COR --- + +@@ -17,12 +12,4 @@ wrote 1048576/1048576 bytes at offset 1048576 + + --- Checking COR result --- + +-discard 67108864/67108864 bytes at offset 0 +-64 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +- +-read 1048576/1048576 bytes at offset 0 +-1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +- +-read 1048576/1048576 bytes at offset 1048576 +-1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +- ++Done +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Move-qmp_to_opts-to-VM.patch b/SOURCES/kvm-iotests-Move-qmp_to_opts-to-VM.patch new file mode 100644 index 0000000..b3b6664 --- /dev/null +++ b/SOURCES/kvm-iotests-Move-qmp_to_opts-to-VM.patch @@ -0,0 +1,132 @@ +From 3ebb5a4471553aa32662d74676bcc5f8d01cacf1 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:35 +0200 +Subject: [PATCH 66/89] iotests: Move qmp_to_opts() to VM + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-53-kwolf@redhat.com> +Patchwork-id: 81085 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 52/73] iotests: Move qmp_to_opts() to VM +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +qmp_to_opts() used to be a method of QMPTestCase, but recently we +started to add more Python test cases that don't make use of +QMPTestCase. In order to make the method usable there, move it to VM. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +(cherry picked from commit 62a9428812c0f4aacbf2f7fdf449fa4f4ab3775c) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/041 | 6 +++--- + tests/qemu-iotests/155 | 2 +- + tests/qemu-iotests/iotests.py | 45 ++++++++++++++++++++++--------------------- + 3 files changed, 27 insertions(+), 26 deletions(-) + +diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041 +index e945879..c20ac7d 100755 +--- a/tests/qemu-iotests/041 ++++ b/tests/qemu-iotests/041 +@@ -1030,9 +1030,9 @@ class TestOrphanedSource(iotests.QMPTestCase): + 'read-only': 'on' } + + self.vm = iotests.VM() +- self.vm.add_blockdev(self.qmp_to_opts(blk0)) +- self.vm.add_blockdev(self.qmp_to_opts(blk1)) +- self.vm.add_blockdev(self.qmp_to_opts(blk2)) ++ self.vm.add_blockdev(self.vm.qmp_to_opts(blk0)) ++ self.vm.add_blockdev(self.vm.qmp_to_opts(blk1)) ++ self.vm.add_blockdev(self.vm.qmp_to_opts(blk2)) + self.vm.launch() + + def tearDown(self): +diff --git a/tests/qemu-iotests/155 b/tests/qemu-iotests/155 +index 42dae04..63a5b5e 100755 +--- a/tests/qemu-iotests/155 ++++ b/tests/qemu-iotests/155 +@@ -63,7 +63,7 @@ class BaseClass(iotests.QMPTestCase): + 'driver': iotests.imgfmt, + 'file': {'driver': 'file', + 'filename': source_img}} +- self.vm.add_blockdev(self.qmp_to_opts(blockdev)) ++ self.vm.add_blockdev(self.vm.qmp_to_opts(blockdev)) + self.vm.add_device('virtio-blk,id=qdev0,drive=source') + self.vm.launch() + +diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py +index 3dab1bf..daf008a 100644 +--- a/tests/qemu-iotests/iotests.py ++++ b/tests/qemu-iotests/iotests.py +@@ -372,6 +372,27 @@ class VM(qtest.QEMUQtestMachine): + return self.qmp('human-monitor-command', + command_line='qemu-io %s "%s"' % (drive, cmd)) + ++ def flatten_qmp_object(self, obj, output=None, basestr=''): ++ if output is None: ++ output = dict() ++ if isinstance(obj, list): ++ for i in range(len(obj)): ++ self.flatten_qmp_object(obj[i], output, basestr + str(i) + '.') ++ elif isinstance(obj, dict): ++ for key in obj: ++ self.flatten_qmp_object(obj[key], output, basestr + key + '.') ++ else: ++ output[basestr[:-1]] = obj # Strip trailing '.' ++ return output ++ ++ def qmp_to_opts(self, obj): ++ obj = self.flatten_qmp_object(obj) ++ output_list = list() ++ for key in obj: ++ output_list += [key + '=' + obj[key]] ++ return ','.join(output_list) ++ ++ + + index_re = re.compile(r'([^\[]+)\[([^\]]+)\]') + +@@ -399,26 +420,6 @@ class QMPTestCase(unittest.TestCase): + self.fail('invalid index "%s" in path "%s" in "%s"' % (idx, path, str(d))) + return d + +- def flatten_qmp_object(self, obj, output=None, basestr=''): +- if output is None: +- output = dict() +- if isinstance(obj, list): +- for i in range(len(obj)): +- self.flatten_qmp_object(obj[i], output, basestr + str(i) + '.') +- elif isinstance(obj, dict): +- for key in obj: +- self.flatten_qmp_object(obj[key], output, basestr + key + '.') +- else: +- output[basestr[:-1]] = obj # Strip trailing '.' +- return output +- +- def qmp_to_opts(self, obj): +- obj = self.flatten_qmp_object(obj) +- output_list = list() +- for key in obj: +- output_list += [key + '=' + obj[key]] +- return ','.join(output_list) +- + def assert_qmp_absent(self, d, path): + try: + result = self.dictpath(d, path) +@@ -453,8 +454,8 @@ class QMPTestCase(unittest.TestCase): + '''Asserts that the given filename is a json: filename and that its + content is equal to the given reference object''' + self.assertEqual(json_filename[:5], 'json:') +- self.assertEqual(self.flatten_qmp_object(json.loads(json_filename[5:])), +- self.flatten_qmp_object(reference)) ++ self.assertEqual(self.vm.flatten_qmp_object(json.loads(json_filename[5:])), ++ self.vm.flatten_qmp_object(reference)) + + def cancel_and_wait(self, drive='drive0', force=False, resume=False): + '''Cancel a block job and wait for it to finish, returning the event''' +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-New-test-223-for-exporting-dirty-bitmap-over.patch b/SOURCES/kvm-iotests-New-test-223-for-exporting-dirty-bitmap-over.patch new file mode 100644 index 0000000..661356f --- /dev/null +++ b/SOURCES/kvm-iotests-New-test-223-for-exporting-dirty-bitmap-over.patch @@ -0,0 +1,259 @@ +From a213535d2d03296c7b2f31845160757dbb959ca6 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Tue, 24 Jul 2018 13:06:13 +0200 +Subject: [PATCH 86/89] iotests: New test 223 for exporting dirty bitmap over + NBD + +RH-Author: John Snow +Message-id: <20180718225511.14878-36-jsnow@redhat.com> +Patchwork-id: 81424 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 35/35] iotests: New test 223 for exporting dirty bitmap over NBD +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Eric Blake + +Although this test is NOT a full test of image fleecing (as it +intentionally uses just a single block device directly exported +over NBD, rather than trying to set up a blockdev-backup job with +multiple BDS involved), it DOES prove that qemu as a server is +able to properly expose a dirty bitmap over NBD. + +When coupled with image fleecing, it is then possible for a +third-party client to do an incremental backup by using +qemu-img map with the x-dirty-bitmap option to learn which parts +of the file are dirty (perhaps confusingly, they are the portions +mapped as "data":false - which is part of the reason this is +still in the x- experimental namespace), along with another +normal client (perhaps 'qemu-nbd -c' to expose the server over +/dev/nbd0 and then just use normal I/O on that block device) to +read the dirty sections. + +Signed-off-by: Eric Blake +Message-Id: <20180702191458.28741-3-eblake@redhat.com> +Tested-by: John Snow +Reviewed-by: John Snow +(cherry picked from commit a1532a225a183c9fa60b9c1e8ac8a00c7771f64d) +Signed-off-by: John Snow +--- + tests/qemu-iotests/223 | 138 +++++++++++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/223.out | 49 ++++++++++++++++ + tests/qemu-iotests/group | 1 + + 3 files changed, 188 insertions(+) + create mode 100644 tests/qemu-iotests/223 + create mode 100644 tests/qemu-iotests/223.out + +diff --git a/tests/qemu-iotests/223 b/tests/qemu-iotests/223 +new file mode 100644 +index 0000000..b63b7a4 +--- /dev/null ++++ b/tests/qemu-iotests/223 +@@ -0,0 +1,138 @@ ++#!/bin/bash ++# ++# Test reading dirty bitmap over NBD ++# ++# Copyright (C) 2018 Red Hat, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++ ++seq="$(basename $0)" ++echo "QA output created by $seq" ++ ++here="$PWD" ++status=1 # failure is the default! ++ ++_cleanup() ++{ ++ _cleanup_test_img ++ _cleanup_qemu ++ rm -f "$TEST_DIR/nbd" ++} ++trap "_cleanup; exit \$status" 0 1 2 3 15 ++ ++# get standard environment, filters and checks ++. ./common.rc ++. ./common.filter ++. ./common.qemu ++ ++_supported_fmt qcow2 ++_supported_proto file # uses NBD as well ++_supported_os Linux ++ ++function do_run_qemu() ++{ ++ echo Testing: "$@" ++ $QEMU -nographic -qmp stdio -serial none "$@" ++ echo ++} ++ ++function run_qemu() ++{ ++ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \ ++ | _filter_qemu | _filter_imgfmt \ ++ | _filter_actual_image_size ++} ++ ++echo ++echo "=== Create partially sparse image, then add dirty bitmap ===" ++echo ++ ++_make_test_img 4M ++$QEMU_IO -c 'w -P 0x11 1M 2M' "$TEST_IMG" | _filter_qemu_io ++run_qemu < >(_filter_nbd) ++ ++silent= ++_send_qemu_cmd $QEMU_HANDLE '{"execute":"qmp_capabilities"}' "return" ++_send_qemu_cmd $QEMU_HANDLE '{"execute":"blockdev-add", ++ "arguments":{"driver":"qcow2", "node-name":"n", ++ "file":{"driver":"file", "filename":"'"$TEST_IMG"'"}}}' "return" ++_send_qemu_cmd $QEMU_HANDLE '{"execute":"x-block-dirty-bitmap-disable", ++ "arguments":{"node":"n", "name":"b"}}' "return" ++_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-start", ++ "arguments":{"addr":{"type":"unix", ++ "data":{"path":"'"$TEST_DIR/nbd"'"}}}}' "return" ++_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add", ++ "arguments":{"device":"n"}}' "return" ++_send_qemu_cmd $QEMU_HANDLE '{"execute":"x-nbd-server-add-bitmap", ++ "arguments":{"name":"n", "bitmap":"b"}}' "return" ++ ++echo ++echo "=== Contrast normal status with dirty-bitmap status ===" ++echo ++ ++QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT ++IMG="driver=nbd,export=n,server.type=unix,server.path=$TEST_DIR/nbd" ++$QEMU_IO -r -c 'r -P 0 0 1m' -c 'r -P 0x11 1m 1m' \ ++ -c 'r -P 0x22 2m 2m' --image-opts "$IMG" | _filter_qemu_io ++$QEMU_IMG map --output=json --image-opts \ ++ "$IMG" | _filter_qemu_img_map ++$QEMU_IMG map --output=json --image-opts \ ++ "$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b" | _filter_qemu_img_map ++ ++echo ++echo "=== End NBD server ===" ++echo ++ ++_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-remove", ++ "arguments":{"name":"n"}}' "return" ++_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-stop"}' "return" ++_send_qemu_cmd $QEMU_HANDLE '{"execute":"quit"}' "return" ++ ++# success, all done ++echo '*** done' ++rm -f $seq.full ++status=0 +diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out +new file mode 100644 +index 0000000..33021c8 +--- /dev/null ++++ b/tests/qemu-iotests/223.out +@@ -0,0 +1,49 @@ ++QA output created by 223 ++ ++=== Create partially sparse image, then add dirty bitmap === ++ ++Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4194304 ++wrote 2097152/2097152 bytes at offset 1048576 ++2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++Testing: ++QMP_VERSION ++{"return": {}} ++{"return": {}} ++{"return": {}} ++{"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} ++ ++ ++=== Write part of the file under active bitmap === ++ ++wrote 2097152/2097152 bytes at offset 2097152 ++2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++ ++=== End dirty bitmap, and start serving image over NBD === ++ ++{"return": {}} ++{"return": {}} ++{"return": {}} ++{"return": {}} ++{"return": {}} ++{"return": {}} ++ ++=== Contrast normal status with dirty-bitmap status === ++ ++read 1048576/1048576 bytes at offset 0 ++1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++read 1048576/1048576 bytes at offset 1048576 ++1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++read 2097152/2097152 bytes at offset 2097152 ++2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false}, ++{ "start": 1048576, "length": 3145728, "depth": 0, "zero": false, "data": true}] ++[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true}, ++{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": false}] ++ ++=== End NBD server === ++ ++{"return": {}} ++{"return": {}} ++{"return": {}} ++*** done +diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group +index be55905..401258f 100644 +--- a/tests/qemu-iotests/group ++++ b/tests/qemu-iotests/group +@@ -219,4 +219,5 @@ + 218 rw auto quick + 219 rw auto + 222 rw auto quick ++223 rw auto quick + 226 auto quick +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Repairing-error-during-snapshot-deletion.patch b/SOURCES/kvm-iotests-Repairing-error-during-snapshot-deletion.patch new file mode 100644 index 0000000..e4a2a59 --- /dev/null +++ b/SOURCES/kvm-iotests-Repairing-error-during-snapshot-deletion.patch @@ -0,0 +1,192 @@ +From 4ffeaaff9109fbdf63bca8c0f944d6ebc46c9ffd Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 17:16:55 +0200 +Subject: [PATCH 46/54] iotests: Repairing error during snapshot deletion + +RH-Author: Max Reitz +Message-id: <20180618171655.25987-3-mreitz@redhat.com> +Patchwork-id: 80784 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 2/2] iotests: Repairing error during snapshot deletion +Bugzilla: 1527085 +RH-Acked-by: John Snow +RH-Acked-by: Kevin Wolf +RH-Acked-by: Miroslav Rezanina + +This adds a test for an I/O error during snapshot deletion, and maybe +more importantly, for how to repair the resulting image. If the +snapshot has been deleted before the error occurs, the only negative +result will be leaked clusters -- and those should be repairable with +qemu-img check -r leaks. + +Signed-off-by: Max Reitz +Reviewed-by: Eric Blake +Message-id: 20180509200059.31125-3-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit b41ad73a3bb972eb43cf52d28669f67ea3fe1762) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/217 | 90 ++++++++++++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/217.out | 42 ++++++++++++++++++++++ + tests/qemu-iotests/group | 1 + + 3 files changed, 133 insertions(+) + create mode 100755 tests/qemu-iotests/217 + create mode 100644 tests/qemu-iotests/217.out + +diff --git a/tests/qemu-iotests/217 b/tests/qemu-iotests/217 +new file mode 100755 +index 0000000..d3ab5d7 +--- /dev/null ++++ b/tests/qemu-iotests/217 +@@ -0,0 +1,90 @@ ++#!/bin/bash ++# ++# I/O errors when working with internal qcow2 snapshots, and repairing ++# the result ++# ++# Copyright (C) 2018 Red Hat, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++seq=$(basename $0) ++echo "QA output created by $seq" ++ ++status=1 # failure is the default! ++ ++_cleanup() ++{ ++ _cleanup_test_img ++ rm -f "$TEST_DIR/blkdebug.conf" ++} ++trap "_cleanup; exit \$status" 0 1 2 3 15 ++ ++# get standard environment, filters and checks ++. ./common.rc ++. ./common.filter ++ ++# This test is specific to qcow2 ++_supported_fmt qcow2 ++_supported_proto file ++_supported_os Linux ++ ++# 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]' ++ ++echo ++echo '=== Simulating an I/O error during snapshot deletion ===' ++echo ++ ++_make_test_img 64M ++$QEMU_IO -c 'write 0 64k' "$TEST_IMG" | _filter_qemu_io ++ ++# Create the snapshot ++$QEMU_IMG snapshot -c foo "$TEST_IMG" ++ ++# Verify the snapshot is there ++echo ++_img_info | grep 'Snapshot list' ++echo '(Snapshot filtered)' ++echo ++ ++# Try to delete the snapshot (with an error happening when freeing the ++# then leaked clusters) ++cat > "$TEST_DIR/blkdebug.conf" < +Date: Mon, 18 Jun 2018 14:59:43 +0200 +Subject: [PATCH 09/89] iotests: Rework 113 + +RH-Author: Max Reitz +Message-id: <20180618145943.4489-8-mreitz@redhat.com> +Patchwork-id: 80757 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 7/7] iotests: Rework 113 +Bugzilla: 1537956 +RH-Acked-by: John Snow +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi + +This test case has been broken since 398e6ad014df261d (roughly half a +year). qemu-img amend requires its output image to be R/W, so it opens +it as such; the node is then turned into an read-only node automatically +which is now accompanied by a warning, however. This warning has not +been part of the reference output. + +For one thing, this warning shows that we cannot keep the test case as +it is. We would need a format that has no create_opts but that does +have write support -- we do not have such a format, though. + +Another thing is that qemu now actually checks whether an image format +supports amendment instead of whether it has create_opts (since the +former always implies the latter). So we can now use any format that +does not support amendment (even if it supports creation) and thus test +the same code path. + +The reason nobody has noticed the breakage until now of course is the +fact that nobody runs the iotests for nbd+bochs. There actually was +never any reason to set the protocol to "nbd" but because that was +technically correct; functionally it made no difference. So that is the +first thing we are going to change: Make the protocol "file" instead so +that people might actually notice breakage here. + +Secondly, now that bochs no longer works for the amend test case, we +have to change the format there anyway. Set let us just bend the truth +a bit, declare this test a raw test. In fact, that does not even +concern the bochs test cases, other than the output now reading 'bochs' +instead of 'IMGFMT'. + +So with this test now being a raw test, we can rework the amend test +case to use raw instead. + +Signed-off-by: Max Reitz +Reviewed-by: John Snow +Message-id: 20180509210023.20283-8-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit dee6ddd8a6b7978d0bc8ef8e1f006282ce30e4fa) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/113 | 19 +++++++++---------- + tests/qemu-iotests/113.out | 7 ++++--- + 2 files changed, 13 insertions(+), 13 deletions(-) + +diff --git a/tests/qemu-iotests/113 b/tests/qemu-iotests/113 +index 19b68b2..4e09810 100755 +--- a/tests/qemu-iotests/113 ++++ b/tests/qemu-iotests/113 +@@ -38,16 +38,17 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 + . ./common.rc + . ./common.filter + +-# We can only test one format here because we need its sample file +-_supported_fmt bochs +-_supported_proto nbd ++# Some of these test cases use bochs, but others do use raw, so this ++# is only half a lie. ++_supported_fmt raw ++_supported_proto file + _supported_os Linux + + echo + echo '=== Unsupported image creation in qemu-img create ===' + echo + +-$QEMU_IMG create -f $IMGFMT nbd://example.com 2>&1 64M | _filter_imgfmt ++$QEMU_IMG create -f bochs nbd://example.com 2>&1 64M + + echo + echo '=== Unsupported image creation in qemu-img convert ===' +@@ -56,17 +57,15 @@ echo + # We could use any input image format here, but this is a bochs test, so just + # use the bochs image + _use_sample_img empty.bochs.bz2 +-$QEMU_IMG convert -f $IMGFMT -O $IMGFMT "$TEST_IMG" nbd://example.com 2>&1 \ +- | _filter_imgfmt ++$QEMU_IMG convert -f bochs -O bochs "$TEST_IMG" nbd://example.com + + echo + echo '=== Unsupported format in qemu-img amend ===' + echo + +-# The protocol does not matter here +-_use_sample_img empty.bochs.bz2 +-$QEMU_IMG amend -f $IMGFMT -o foo=bar "$TEST_IMG" 2>&1 | _filter_imgfmt +- ++TEST_IMG="$TEST_DIR/t.$IMGFMT" ++_make_test_img 1M ++$QEMU_IMG amend -f $IMGFMT -o size=2M "$TEST_IMG" 2>&1 | _filter_imgfmt + + # success, all done + echo +diff --git a/tests/qemu-iotests/113.out b/tests/qemu-iotests/113.out +index 00bdfd6..3557e2b 100644 +--- a/tests/qemu-iotests/113.out ++++ b/tests/qemu-iotests/113.out +@@ -2,14 +2,15 @@ QA output created by 113 + + === Unsupported image creation in qemu-img create === + +-qemu-img: nbd://example.com: Format driver 'IMGFMT' does not support image creation ++qemu-img: nbd://example.com: Format driver 'bochs' does not support image creation + + === Unsupported image creation in qemu-img convert === + +-qemu-img: Format driver 'IMGFMT' does not support image creation ++qemu-img: Format driver 'bochs' does not support image creation + + === Unsupported format in qemu-img amend === + +-qemu-img: Format driver 'IMGFMT' does not support any options to amend ++Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 ++qemu-img: Format driver 'IMGFMT' does not support option amendment + + *** done +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Split-214-off-of-122.patch b/SOURCES/kvm-iotests-Split-214-off-of-122.patch new file mode 100644 index 0000000..d7220b1 --- /dev/null +++ b/SOURCES/kvm-iotests-Split-214-off-of-122.patch @@ -0,0 +1,301 @@ +From 6de5873f52d3fac1aef3091c1e283530e37c4b02 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 16:12:03 +0200 +Subject: [PATCH 27/54] iotests: Split 214 off of 122 + +RH-Author: Max Reitz +Message-id: <20180618161212.14444-2-mreitz@redhat.com> +Patchwork-id: 80761 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 01/10] iotests: Split 214 off of 122 +Bugzilla: 1518738 +RH-Acked-by: John Snow +RH-Acked-by: Kevin Wolf +RH-Acked-by: Miroslav Rezanina + +Commit abd3622cc03cf41ed542126a540385f30a4c0175 added a case to 122 +regarding how the qcow2 driver handles an incorrect compressed data +length value. This does not really fit into 122, as that file is +supposed to contain qemu-img convert test cases, which this case is not. +So this patch splits it off into its own file; maybe we will even get +more qcow2-only compression tests in the future. + +Also, that test case does not work with refcount_bits=1, so mark that +option as unsupported. + +Signed-off-by: Max Reitz +Message-id: 20180406164108.26118-1-mreitz@redhat.com +Reviewed-by: Eric Blake +Signed-off-by: Alberto Garcia +Signed-off-by: Max Reitz +(cherry picked from commit 6cba5377f54d7ea859a29c1877785e7101794683) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/122 | 47 ---------------------- + tests/qemu-iotests/122.out | 33 ---------------- + tests/qemu-iotests/214 | 97 ++++++++++++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/214.out | 35 +++++++++++++++++ + tests/qemu-iotests/group | 1 + + 5 files changed, 133 insertions(+), 80 deletions(-) + create mode 100755 tests/qemu-iotests/214 + create mode 100644 tests/qemu-iotests/214.out + +diff --git a/tests/qemu-iotests/122 b/tests/qemu-iotests/122 +index 6cf4fcb..45b359c 100755 +--- a/tests/qemu-iotests/122 ++++ b/tests/qemu-iotests/122 +@@ -130,53 +130,6 @@ $QEMU_IO -c "read -P 0 1024k 1022k" "$TEST_IMG" 2>&1 | _filter_qemu_io | _fil + + + echo +-echo "=== Corrupted size field in compressed cluster descriptor ===" +-echo +-# Create an empty image and fill half of it with compressed data. +-# The L2 entries of the two compressed clusters are located at +-# 0x800000 and 0x800008, their original values are 0x4008000000a00000 +-# and 0x4008000000a00802 (5 sectors for compressed data each). +-_make_test_img 8M -o cluster_size=2M +-$QEMU_IO -c "write -c -P 0x11 0 2M" -c "write -c -P 0x11 2M 2M" "$TEST_IMG" \ +- 2>&1 | _filter_qemu_io | _filter_testdir +- +-# Reduce size of compressed data to 4 sectors: this corrupts the image. +-poke_file "$TEST_IMG" $((0x800000)) "\x40\x06" +-$QEMU_IO -c "read -P 0x11 0 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir +- +-# 'qemu-img check' however doesn't see anything wrong because it +-# doesn't try to decompress the data and the refcounts are consistent. +-# TODO: update qemu-img so this can be detected. +-_check_test_img +- +-# Increase size of compressed data to the maximum (8192 sectors). +-# This makes QEMU read more data (8192 sectors instead of 5, host +-# addresses [0xa00000, 0xdfffff]), but the decompression algorithm +-# stops once we have enough to restore the uncompressed cluster, so +-# the rest of the data is ignored. +-poke_file "$TEST_IMG" $((0x800000)) "\x7f\xfe" +-# Do it also for the second compressed cluster (L2 entry at 0x800008). +-# In this case the compressed data would span 3 host clusters +-# (host addresses: [0xa00802, 0xe00801]) +-poke_file "$TEST_IMG" $((0x800008)) "\x7f\xfe" +- +-# Here the image is too small so we're asking QEMU to read beyond the +-# end of the image. +-$QEMU_IO -c "read -P 0x11 0 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir +-# But if we grow the image we won't be reading beyond its end anymore. +-$QEMU_IO -c "write -P 0x22 4M 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir +-$QEMU_IO -c "read -P 0x11 0 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir +- +-# The refcount data is however wrong because due to the increased size +-# of the compressed data it now reaches the following host clusters. +-# This can be repaired by qemu-img check by increasing the refcount of +-# those clusters. +-# TODO: update qemu-img to correct the compressed cluster size instead. +-_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 "=== Full allocation with -S 0 ===" + echo + +diff --git a/tests/qemu-iotests/122.out b/tests/qemu-iotests/122.out +index a6b7fe0..47d8656 100644 +--- a/tests/qemu-iotests/122.out ++++ b/tests/qemu-iotests/122.out +@@ -99,39 +99,6 @@ read 1024/1024 bytes at offset 1047552 + read 1046528/1046528 bytes at offset 1048576 + 1022 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +-=== Corrupted size field in compressed cluster descriptor === +- +-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8388608 +-wrote 2097152/2097152 bytes at offset 0 +-2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +-wrote 2097152/2097152 bytes at offset 2097152 +-2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +-read failed: Input/output error +-No errors were found on the image. +-read 4194304/4194304 bytes at offset 0 +-4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +-wrote 4194304/4194304 bytes at offset 4194304 +-4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +-read 4194304/4194304 bytes at offset 0 +-4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +-ERROR cluster 6 refcount=1 reference=3 +-ERROR cluster 7 refcount=1 reference=2 +-Repairing cluster 6 refcount=1 reference=3 +-Repairing cluster 7 refcount=1 reference=2 +-Repairing OFLAG_COPIED data cluster: l2_entry=8000000000c00000 refcount=3 +-Repairing OFLAG_COPIED data cluster: l2_entry=8000000000e00000 refcount=2 +-The following inconsistencies were found and repaired: +- +- 0 leaked clusters +- 4 corruptions +- +-Double checking the fixed image now... +-No errors were found on the image. +-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) +- + === Full allocation with -S 0 === + + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +diff --git a/tests/qemu-iotests/214 b/tests/qemu-iotests/214 +new file mode 100755 +index 0000000..c46ca2a +--- /dev/null ++++ b/tests/qemu-iotests/214 +@@ -0,0 +1,97 @@ ++#!/bin/bash ++# ++# Test qcow2 image compression ++# ++# Copyright (C) 2018 Igalia, S.L. ++# Author: Alberto Garcia ++# ++# 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 . ++# ++ ++seq=$(basename "$0") ++echo "QA output created by $seq" ++ ++here=$PWD ++status=1 # failure is the default! ++ ++_cleanup() ++{ ++ _cleanup_test_img ++} ++trap "_cleanup; exit \$status" 0 1 2 3 15 ++ ++# get standard environment, filters and checks ++. ./common.rc ++. ./common.filter ++ ++_supported_fmt qcow2 ++_supported_proto file ++_supported_os Linux ++ ++# 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]' ++ ++ ++echo ++echo "=== Corrupted size field in compressed cluster descriptor ===" ++echo ++# Create an empty image and fill half of it with compressed data. ++# The L2 entries of the two compressed clusters are located at ++# 0x800000 and 0x800008, their original values are 0x4008000000a00000 ++# and 0x4008000000a00802 (5 sectors for compressed data each). ++_make_test_img 8M -o cluster_size=2M ++$QEMU_IO -c "write -c -P 0x11 0 2M" -c "write -c -P 0x11 2M 2M" "$TEST_IMG" \ ++ 2>&1 | _filter_qemu_io | _filter_testdir ++ ++# Reduce size of compressed data to 4 sectors: this corrupts the image. ++poke_file "$TEST_IMG" $((0x800000)) "\x40\x06" ++$QEMU_IO -c "read -P 0x11 0 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir ++ ++# 'qemu-img check' however doesn't see anything wrong because it ++# doesn't try to decompress the data and the refcounts are consistent. ++# TODO: update qemu-img so this can be detected. ++_check_test_img ++ ++# Increase size of compressed data to the maximum (8192 sectors). ++# This makes QEMU read more data (8192 sectors instead of 5, host ++# addresses [0xa00000, 0xdfffff]), but the decompression algorithm ++# stops once we have enough to restore the uncompressed cluster, so ++# the rest of the data is ignored. ++poke_file "$TEST_IMG" $((0x800000)) "\x7f\xfe" ++# Do it also for the second compressed cluster (L2 entry at 0x800008). ++# In this case the compressed data would span 3 host clusters ++# (host addresses: [0xa00802, 0xe00801]) ++poke_file "$TEST_IMG" $((0x800008)) "\x7f\xfe" ++ ++# Here the image is too small so we're asking QEMU to read beyond the ++# end of the image. ++$QEMU_IO -c "read -P 0x11 0 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir ++# But if we grow the image we won't be reading beyond its end anymore. ++$QEMU_IO -c "write -P 0x22 4M 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir ++$QEMU_IO -c "read -P 0x11 0 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir ++ ++# The refcount data is however wrong because due to the increased size ++# of the compressed data it now reaches the following host clusters. ++# This can be repaired by qemu-img check by increasing the refcount of ++# those clusters. ++# TODO: update qemu-img to correct the compressed cluster size instead. ++_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 ++ ++# success, all done ++echo '*** done' ++rm -f $seq.full ++status=0 +diff --git a/tests/qemu-iotests/214.out b/tests/qemu-iotests/214.out +new file mode 100644 +index 0000000..0fcd8dc +--- /dev/null ++++ b/tests/qemu-iotests/214.out +@@ -0,0 +1,35 @@ ++QA output created by 214 ++ ++=== Corrupted size field in compressed cluster descriptor === ++ ++Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8388608 ++wrote 2097152/2097152 bytes at offset 0 ++2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++wrote 2097152/2097152 bytes at offset 2097152 ++2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++read failed: Input/output error ++No errors were found on the image. ++read 4194304/4194304 bytes at offset 0 ++4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++wrote 4194304/4194304 bytes at offset 4194304 ++4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++read 4194304/4194304 bytes at offset 0 ++4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++ERROR cluster 6 refcount=1 reference=3 ++ERROR cluster 7 refcount=1 reference=2 ++Repairing cluster 6 refcount=1 reference=3 ++Repairing cluster 7 refcount=1 reference=2 ++Repairing OFLAG_COPIED data cluster: l2_entry=8000000000c00000 refcount=3 ++Repairing OFLAG_COPIED data cluster: l2_entry=8000000000e00000 refcount=2 ++The following inconsistencies were found and repaired: ++ ++ 0 leaked clusters ++ 4 corruptions ++ ++Double checking the fixed image now... ++No errors were found on the image. ++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) ++*** done +diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group +index 3a89aed..ba7a2d1 100644 +--- a/tests/qemu-iotests/group ++++ b/tests/qemu-iotests/group +@@ -212,4 +212,5 @@ + 211 rw auto quick + 212 rw auto quick + 213 rw auto quick ++214 rw auto + 218 rw auto quick +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Test-help-option-for-unsupporting-formats.patch b/SOURCES/kvm-iotests-Test-help-option-for-unsupporting-formats.patch new file mode 100644 index 0000000..7b77b0a --- /dev/null +++ b/SOURCES/kvm-iotests-Test-help-option-for-unsupporting-formats.patch @@ -0,0 +1,99 @@ +From 71c378083914a8ee1c4169bc47d1a21df38a16f7 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 14:59:42 +0200 +Subject: [PATCH 08/89] iotests: Test help option for unsupporting formats + +RH-Author: Max Reitz +Message-id: <20180618145943.4489-7-mreitz@redhat.com> +Patchwork-id: 80760 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 6/7] iotests: Test help option for unsupporting formats +Bugzilla: 1537956 +RH-Acked-by: John Snow +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi + +This adds test cases to 082 for qemu-img create/convert/amend "-o help" +on formats that do not support creation or amendment, respectively. + +Signed-off-by: Max Reitz +Reviewed-by: John Snow +Reviewed-by: Eric Blake +Message-id: 20180509210023.20283-7-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit e53995eb19b546b18d1a34cd6eaa07faedbade79) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/082 | 9 +++++++++ + tests/qemu-iotests/082.out | 9 +++++++++ + 2 files changed, 18 insertions(+) + +diff --git a/tests/qemu-iotests/082 b/tests/qemu-iotests/082 +index d5c83d4..a872f77 100755 +--- a/tests/qemu-iotests/082 ++++ b/tests/qemu-iotests/082 +@@ -97,6 +97,9 @@ run_qemu_img create -f $IMGFMT -o backing_file="$TEST_IMG" -o ,, -o help "$TEST_ + run_qemu_img create -f $IMGFMT -o help + run_qemu_img create -o help + ++# Try help option for a format that does not support creation ++run_qemu_img create -f bochs -o help ++ + echo + echo === convert: Options specified more than once === + +@@ -151,6 +154,9 @@ run_qemu_img convert -O $IMGFMT -o backing_file="$TEST_IMG" -o ,, -o help "$TEST + run_qemu_img convert -O $IMGFMT -o help + run_qemu_img convert -o help + ++# Try help option for a format that does not support creation ++run_qemu_img convert -O bochs -o help ++ + echo + echo === amend: Options specified more than once === + +@@ -201,6 +207,9 @@ run_qemu_img amend -f $IMGFMT -o backing_file="$TEST_IMG" -o ,, -o help "$TEST_I + run_qemu_img amend -f $IMGFMT -o help + run_qemu_img convert -o help + ++# Try help option for a format that does not support amendment ++run_qemu_img amend -f bochs -o help ++ + # success, all done + echo "*** done" + rm -f $seq.full +diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out +index 4e52dce..60ef87c 100644 +--- a/tests/qemu-iotests/082.out ++++ b/tests/qemu-iotests/082.out +@@ -249,6 +249,9 @@ Testing: create -o help + Supported options: + size Virtual disk size + ++Testing: create -f bochs -o help ++qemu-img: Format driver 'bochs' does not support image creation ++ + === convert: Options specified more than once === + + Testing: create -f qcow2 TEST_DIR/t.qcow2 128M +@@ -502,6 +505,9 @@ Testing: convert -o help + Supported options: + size Virtual disk size + ++Testing: convert -O bochs -o help ++qemu-img: Format driver 'bochs' does not support image creation ++ + === amend: Options specified more than once === + + Testing: amend -f foo -f qcow2 -o lazy_refcounts=on TEST_DIR/t.qcow2 +@@ -763,4 +769,7 @@ Note that not all of these options may be amendable. + Testing: convert -o help + Supported options: + size Virtual disk size ++ ++Testing: amend -f bochs -o help ++qemu-img: Format driver 'bochs' does not support option amendment + *** done +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-Test-post-backing-convert-target-behavior.patch b/SOURCES/kvm-iotests-Test-post-backing-convert-target-behavior.patch new file mode 100644 index 0000000..cd8a4b6 --- /dev/null +++ b/SOURCES/kvm-iotests-Test-post-backing-convert-target-behavior.patch @@ -0,0 +1,116 @@ +From 4368733f4cfd8aa424c6f14f950b8e33db6829f2 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 18:04:51 +0200 +Subject: [PATCH 13/89] iotests: Test post-backing convert target behavior + +RH-Author: Max Reitz +Message-id: <20180618180451.23808-3-mreitz@redhat.com> +Patchwork-id: 80797 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 2/2] iotests: Test post-backing convert target behavior +Bugzilla: 1527898 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Kevin Wolf +RH-Acked-by: Jeffrey Cody + +This adds a test case to 122 for what happens when you convert to a +target with a backing file that is shorter than the target, and the +image format does not support efficient zero writes (as is the case with +qcow2 v2). + +Signed-off-by: Max Reitz +Message-id: 20180501165750.19242-3-mreitz@redhat.com +Reviewed-by: Eric Blake +Signed-off-by: Max Reitz +(cherry picked from commit 0682854f899d03c78befce9f5aae4a7e37655d25) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/122 | 42 ++++++++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/122.out | 18 ++++++++++++++++++ + 2 files changed, 60 insertions(+) + +diff --git a/tests/qemu-iotests/122 b/tests/qemu-iotests/122 +index 45b359c..d8c8ad7 100755 +--- a/tests/qemu-iotests/122 ++++ b/tests/qemu-iotests/122 +@@ -77,6 +77,48 @@ $QEMU_IO -c "read -P 0 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_t + + + echo ++echo "=== Converting to an overlay larger than its backing file ===" ++echo ++ ++TEST_IMG="$TEST_IMG".base _make_test_img 256M ++# Needs to be at least how much an L2 table covers ++# (64 kB/entry * 64 kB / 8 B/entry = 512 MB) ++# That way, qcow2 will yield at least two status request responses. ++# With just a single response, it would always say "Allocated in the ++# backing file", so the optimization qemu-img convert tries to do is ++# done automatically. Once it has to be queried twice, however (and ++# one of the queries is completely after the end of the backing file), ++# the block layer will automatically add a ZERO flag that qemu-img ++# convert used to follow up with a zero write to the target. ++# We do not want such a zero write, however, because we are past the ++# end of the backing file on the target as well, so we do not need to ++# write anything there. ++_make_test_img -b "$TEST_IMG".base 768M ++ ++# Use compat=0.10 as the output so there is no zero cluster support ++$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base -o compat=0.10 \ ++ "$TEST_IMG" "$TEST_IMG".orig ++# See that nothing has been allocated past 64M ++$QEMU_IMG map "$TEST_IMG".orig | _filter_qemu_img_map ++ ++echo ++ ++# Just before the end of the backing file ++$QEMU_IO -c 'write -P 0x11 255M 1M' "$TEST_IMG".base 2>&1 | _filter_qemu_io ++# Somewhere in the second L2 table ++$QEMU_IO -c 'write -P 0x22 600M 1M' "$TEST_IMG" 2>&1 | _filter_qemu_io ++ ++$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base -o compat=0.10 \ ++ "$TEST_IMG" "$TEST_IMG".orig ++ ++$QEMU_IMG map "$TEST_IMG".orig | _filter_qemu_img_map ++$QEMU_IO -c 'read -P 0x11 255M 1M' \ ++ -c 'read -P 0x22 600M 1M' \ ++ "$TEST_IMG".orig \ ++ | _filter_qemu_io ++ ++ ++echo + echo "=== Concatenate multiple source images ===" + echo + +diff --git a/tests/qemu-iotests/122.out b/tests/qemu-iotests/122.out +index 47d8656..6c7ee1d 100644 +--- a/tests/qemu-iotests/122.out ++++ b/tests/qemu-iotests/122.out +@@ -28,6 +28,24 @@ read 3145728/3145728 bytes at offset 0 + read 3145728/3145728 bytes at offset 0 + 3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + ++=== Converting to an overlay larger than its backing file === ++ ++Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=268435456 ++Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=805306368 backing_file=TEST_DIR/t.IMGFMT.base ++Offset Length File ++ ++wrote 1048576/1048576 bytes at offset 267386880 ++1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++wrote 1048576/1048576 bytes at offset 629145600 ++1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++Offset Length File ++0xff00000 0x100000 TEST_DIR/t.IMGFMT.base ++0x25800000 0x100000 TEST_DIR/t.IMGFMT.orig ++read 1048576/1048576 bytes at offset 267386880 ++1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++read 1048576/1048576 bytes at offset 629145600 ++1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++ + === Concatenate multiple source images === + + Formatting 'TEST_DIR/t.IMGFMT.1', fmt=IMGFMT size=4194304 +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-add-222-to-test-basic-fleecing.patch b/SOURCES/kvm-iotests-add-222-to-test-basic-fleecing.patch new file mode 100644 index 0000000..1e57da3 --- /dev/null +++ b/SOURCES/kvm-iotests-add-222-to-test-basic-fleecing.patch @@ -0,0 +1,275 @@ +From 561418d66933d9262f1678fda614dc0bde2a8f45 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Tue, 24 Jul 2018 12:25:31 +0200 +Subject: [PATCH 62/89] iotests: add 222 to test basic fleecing + +RH-Author: John Snow +Message-id: <20180718225511.14878-12-jsnow@redhat.com> +Patchwork-id: 81407 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 11/35] iotests: add 222 to test basic fleecing +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +Signed-off-by: John Snow +Message-Id: <20180702194630.9360-3-jsnow@redhat.com> +Reviewed-by: Eric Blake +Signed-off-by: Eric Blake +(cherry picked from commit bacebdedbf921a2c641a34486ff543089d338f32) +Signed-off-by: John Snow +--- + tests/qemu-iotests/222 | 155 +++++++++++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/222.out | 67 ++++++++++++++++++++ + tests/qemu-iotests/group | 1 + + 3 files changed, 223 insertions(+) + create mode 100644 tests/qemu-iotests/222 + create mode 100644 tests/qemu-iotests/222.out + +diff --git a/tests/qemu-iotests/222 b/tests/qemu-iotests/222 +new file mode 100644 +index 0000000..ff3bfc1 +--- /dev/null ++++ b/tests/qemu-iotests/222 +@@ -0,0 +1,155 @@ ++#!/usr/bin/env python ++# ++# This test covers the basic fleecing workflow, which provides a ++# point-in-time snapshot of a node that can be queried over NBD. ++# ++# Copyright (C) 2018 Red Hat, Inc. ++# John helped, too. ++# ++# 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 . ++# ++# Creator/Owner: John Snow ++ ++import iotests ++from iotests import log, qemu_img, qemu_io, qemu_io_silent ++ ++iotests.verify_platform(['linux']) ++ ++patterns = [("0x5d", "0", "64k"), ++ ("0xd5", "1M", "64k"), ++ ("0xdc", "32M", "64k"), ++ ("0xcd", "0x3ff0000", "64k")] # 64M - 64K ++ ++overwrite = [("0xab", "0", "64k"), # Full overwrite ++ ("0xad", "0x00f8000", "64k"), # Partial-left (1M-32K) ++ ("0x1d", "0x2008000", "64k"), # Partial-right (32M+32K) ++ ("0xea", "0x3fe0000", "64k")] # Adjacent-left (64M - 128K) ++ ++zeroes = [("0", "0x00f8000", "32k"), # Left-end of partial-left (1M-32K) ++ ("0", "0x2010000", "32k"), # Right-end of partial-right (32M+64K) ++ ("0", "0x3fe0000", "64k")] # overwrite[3] ++ ++remainder = [("0xd5", "0x108000", "32k"), # Right-end of partial-left [1] ++ ("0xdc", "32M", "32k"), # Left-end of partial-right [2] ++ ("0xcd", "0x3ff0000", "64k")] # patterns[3] ++ ++with iotests.FilePath('base.img') as base_img_path, \ ++ iotests.FilePath('fleece.img') as fleece_img_path, \ ++ iotests.FilePath('nbd.sock') as nbd_sock_path, \ ++ iotests.VM() as vm: ++ ++ log('--- Setting up images ---') ++ log('') ++ ++ assert qemu_img('create', '-f', iotests.imgfmt, base_img_path, '64M') == 0 ++ assert qemu_img('create', '-f', "qcow2", fleece_img_path, '64M') == 0 ++ ++ for p in patterns: ++ qemu_io('-f', iotests.imgfmt, ++ '-c', 'write -P%s %s %s' % p, base_img_path) ++ ++ log('Done') ++ ++ log('') ++ log('--- Launching VM ---') ++ log('') ++ ++ vm.add_drive(base_img_path) ++ vm.launch() ++ log('Done') ++ ++ log('') ++ log('--- Setting up Fleecing Graph ---') ++ log('') ++ ++ src_node = "drive0" ++ tgt_node = "fleeceNode" ++ ++ # create tgt_node backed by src_node ++ log(vm.qmp("blockdev-add", **{ ++ "driver": "qcow2", ++ "node-name": tgt_node, ++ "file": { ++ "driver": "file", ++ "filename": fleece_img_path, ++ }, ++ "backing": src_node, ++ })) ++ ++ # Establish COW from source to fleecing node ++ log(vm.qmp("blockdev-backup", ++ device=src_node, ++ target=tgt_node, ++ sync="none")) ++ ++ log('') ++ log('--- Setting up NBD Export ---') ++ log('') ++ ++ nbd_uri = 'nbd+unix:///%s?socket=%s' % (tgt_node, nbd_sock_path) ++ log(vm.qmp("nbd-server-start", ++ **{"addr": { "type": "unix", ++ "data": { "path": nbd_sock_path } } })) ++ ++ log(vm.qmp("nbd-server-add", device=tgt_node)) ++ ++ log('') ++ log('--- Sanity Check ---') ++ log('') ++ ++ for p in (patterns + zeroes): ++ cmd = "read -P%s %s %s" % p ++ log(cmd) ++ assert qemu_io_silent('-r', '-f', 'raw', '-c', cmd, nbd_uri) == 0 ++ ++ log('') ++ log('--- Testing COW ---') ++ log('') ++ ++ for p in overwrite: ++ cmd = "write -P%s %s %s" % p ++ log(cmd) ++ log(vm.hmp_qemu_io(src_node, cmd)) ++ ++ log('') ++ log('--- Verifying Data ---') ++ log('') ++ ++ for p in (patterns + zeroes): ++ cmd = "read -P%s %s %s" % p ++ log(cmd) ++ assert qemu_io_silent('-r', '-f', 'raw', '-c', cmd, nbd_uri) == 0 ++ ++ log('') ++ log('--- Cleanup ---') ++ log('') ++ ++ log(vm.qmp('block-job-cancel', device=src_node)) ++ log(vm.event_wait('BLOCK_JOB_CANCELLED'), ++ filters=[iotests.filter_qmp_event]) ++ log(vm.qmp('nbd-server-stop')) ++ log(vm.qmp('blockdev-del', node_name=tgt_node)) ++ vm.shutdown() ++ ++ log('') ++ log('--- Confirming writes ---') ++ log('') ++ ++ for p in (overwrite + remainder): ++ cmd = "read -P%s %s %s" % p ++ log(cmd) ++ assert qemu_io_silent(base_img_path, '-c', cmd) == 0 ++ ++ log('') ++ log('Done') +diff --git a/tests/qemu-iotests/222.out b/tests/qemu-iotests/222.out +new file mode 100644 +index 0000000..48f336a +--- /dev/null ++++ b/tests/qemu-iotests/222.out +@@ -0,0 +1,67 @@ ++--- Setting up images --- ++ ++Done ++ ++--- Launching VM --- ++ ++Done ++ ++--- Setting up Fleecing Graph --- ++ ++{u'return': {}} ++{u'return': {}} ++ ++--- Setting up NBD Export --- ++ ++{u'return': {}} ++{u'return': {}} ++ ++--- Sanity Check --- ++ ++read -P0x5d 0 64k ++read -P0xd5 1M 64k ++read -P0xdc 32M 64k ++read -P0xcd 0x3ff0000 64k ++read -P0 0x00f8000 32k ++read -P0 0x2010000 32k ++read -P0 0x3fe0000 64k ++ ++--- Testing COW --- ++ ++write -P0xab 0 64k ++{u'return': u''} ++write -P0xad 0x00f8000 64k ++{u'return': u''} ++write -P0x1d 0x2008000 64k ++{u'return': u''} ++write -P0xea 0x3fe0000 64k ++{u'return': u''} ++ ++--- Verifying Data --- ++ ++read -P0x5d 0 64k ++read -P0xd5 1M 64k ++read -P0xdc 32M 64k ++read -P0xcd 0x3ff0000 64k ++read -P0 0x00f8000 32k ++read -P0 0x2010000 32k ++read -P0 0x3fe0000 64k ++ ++--- Cleanup --- ++ ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'device': u'drive0', u'type': u'backup', u'speed': 0, u'len': 67108864, u'offset': 393216}, u'event': u'BLOCK_JOB_CANCELLED'} ++{u'return': {}} ++{u'return': {}} ++ ++--- Confirming writes --- ++ ++read -P0xab 0 64k ++read -P0xad 0x00f8000 64k ++read -P0x1d 0x2008000 64k ++read -P0xea 0x3fe0000 64k ++read -P0xd5 0x108000 32k ++read -P0xdc 32M 32k ++read -P0xcd 0x3ff0000 64k ++ ++Done +diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group +index 11498fd..be55905 100644 +--- a/tests/qemu-iotests/group ++++ b/tests/qemu-iotests/group +@@ -218,4 +218,5 @@ + 217 rw auto quick + 218 rw auto quick + 219 rw auto ++222 rw auto quick + 226 auto quick +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-add-VM.add_object.patch b/SOURCES/kvm-iotests-add-VM.add_object.patch deleted file mode 100644 index d95d7ce..0000000 --- a/SOURCES/kvm-iotests-add-VM.add_object.patch +++ /dev/null @@ -1,47 +0,0 @@ -From cc83ddb2ea7c12b48d78160bd60b703097d849ea Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Fri, 22 Dec 2017 11:08:58 +0100 -Subject: [PATCH 40/42] iotests: add VM.add_object() - -RH-Author: Stefan Hajnoczi -Message-id: <20171222110900.24813-19-stefanha@redhat.com> -Patchwork-id: 78500 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 18/20] iotests: add VM.add_object() -Bugzilla: 1519721 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -The VM.add_object() method can be used to add IOThreads or memory -backend objects. - -Signed-off-by: Stefan Hajnoczi -Reviewed-by: Eric Blake -Message-id: 20171207201320.19284-5-stefanha@redhat.com -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit ccc15f7dafff63cbcc3f6a7c51e380025d67f7f4) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - tests/qemu-iotests/iotests.py | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py -index 07fa162..4a3d3fb 100644 ---- a/tests/qemu-iotests/iotests.py -+++ b/tests/qemu-iotests/iotests.py -@@ -198,6 +198,11 @@ class VM(qtest.QEMUQtestMachine): - self._debug = True - self._num_drives = 0 - -+ def add_object(self, opts): -+ self._args.append('-object') -+ self._args.append(opts) -+ return self -+ - def add_device(self, opts): - self._args.append('-device') - self._args.append(opts) --- -1.8.3.1 - diff --git a/SOURCES/kvm-iotests-add-test-226-for-file-driver-types.patch b/SOURCES/kvm-iotests-add-test-226-for-file-driver-types.patch new file mode 100644 index 0000000..2fb536b --- /dev/null +++ b/SOURCES/kvm-iotests-add-test-226-for-file-driver-types.patch @@ -0,0 +1,150 @@ +From 60808b0c672add535f7381785faa6e5609fb20ce Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 13 Jul 2018 14:50:02 +0200 +Subject: [PATCH 44/89] iotests: add test 226 for file driver types + +RH-Author: Kevin Wolf +Message-id: <20180713145002.20953-3-kwolf@redhat.com> +Patchwork-id: 81351 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 2/2] iotests: add test 226 for file driver types +Bugzilla: 1525829 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +From: John Snow + +Test that we're rejecting what we ought to for file, +host_driver and host_cdrom drivers. Test that we're +seeing the deprecated message for block and chardevs +on the file driver. + +Signed-off-by: John Snow +Signed-off-by: Kevin Wolf +(cherry picked from commit 2d4cb49ddaa219ed3f5a985ecf8b188aeb2b3d6b) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/226 | 66 ++++++++++++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/226.out | 26 ++++++++++++++++++ + tests/qemu-iotests/group | 1 + + 3 files changed, 93 insertions(+) + create mode 100755 tests/qemu-iotests/226 + create mode 100644 tests/qemu-iotests/226.out + +diff --git a/tests/qemu-iotests/226 b/tests/qemu-iotests/226 +new file mode 100755 +index 0000000..460aea2 +--- /dev/null ++++ b/tests/qemu-iotests/226 +@@ -0,0 +1,66 @@ ++#!/bin/bash ++# ++# This test covers expected filetypes for the file, host_cdrom and ++# host_device drivers. ++# ++# Copyright (C) 2018 Red Hat, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++ ++# creator ++owner=jsnow@redhat.com ++ ++seq=`basename $0` ++echo "QA output created by $seq" ++ ++here=`pwd` ++status=1 # failure is the default! ++ ++_cleanup() ++{ ++ rmdir "$TEST_IMG" ++} ++trap "_cleanup; exit \$status" 0 1 2 3 15 ++ ++# get standard environment, filters and checks ++. ./common.rc ++. ./common.filter ++. ./common.pattern ++ ++# Generic format, but tests file-protocol specific error handling ++_supported_fmt generic ++_supported_proto file ++_supported_os Linux ++ ++# Create something decidedly not a file, blockdev or chardev... ++mkdir "$TEST_IMG" ++ ++for PROTO in "file" "host_device" "host_cdrom"; do ++ echo ++ echo "=== Testing with driver:$PROTO ===" ++ echo ++ echo "== Testing RO ==" ++ $QEMU_IO -c "open -r -o driver=$PROTO,filename=$TEST_IMG" 2>&1 | _filter_imgfmt | _filter_testdir ++ $QEMU_IO -c "open -r -o driver=$PROTO,filename=/dev/null" 2>&1 | _filter_imgfmt ++ echo "== Testing RW ==" ++ $QEMU_IO -c "open -o driver=$PROTO,filename=$TEST_IMG" 2>&1 | _filter_imgfmt | _filter_testdir ++ $QEMU_IO -c "open -o driver=$PROTO,filename=/dev/null" 2>&1 | _filter_imgfmt ++done ++ ++# success, all done ++echo ++echo "*** done" ++rm -f $seq.full ++status=0 +diff --git a/tests/qemu-iotests/226.out b/tests/qemu-iotests/226.out +new file mode 100644 +index 0000000..8c0d060 +--- /dev/null ++++ b/tests/qemu-iotests/226.out +@@ -0,0 +1,26 @@ ++QA output created by 226 ++ ++=== Testing with driver:file === ++ ++== Testing RO == ++can't open: A regular file was expected by the 'file' driver, but something else was given ++warning: Opening a character device as a file using the 'file' driver is deprecated ++== Testing RW == ++can't open: Could not open 'TEST_DIR/t.IMGFMT': Is a directory ++warning: Opening a character device as a file using the 'file' driver is deprecated ++ ++=== Testing with driver:host_device === ++ ++== Testing RO == ++can't open: 'host_device' driver expects either a character or block device ++== Testing RW == ++can't open: Could not open 'TEST_DIR/t.IMGFMT': Is a directory ++ ++=== Testing with driver:host_cdrom === ++ ++== Testing RO == ++can't open: 'host_cdrom' driver expects either a character or block device ++== Testing RW == ++can't open: Could not open 'TEST_DIR/t.IMGFMT': Is a directory ++ ++*** done +diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group +index 5c55adc..11498fd 100644 +--- a/tests/qemu-iotests/group ++++ b/tests/qemu-iotests/group +@@ -218,3 +218,4 @@ + 217 rw auto quick + 218 rw auto quick + 219 rw auto ++226 auto quick +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests-improve-pause_job.patch b/SOURCES/kvm-iotests-improve-pause_job.patch new file mode 100644 index 0000000..481172f --- /dev/null +++ b/SOURCES/kvm-iotests-improve-pause_job.patch @@ -0,0 +1,55 @@ +From 438c9fb5fd117816c960ad2995e53a627d2df4c5 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:56 +0200 +Subject: [PATCH 87/89] iotests: improve pause_job + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-74-kwolf@redhat.com> +Patchwork-id: 81118 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 73/73] iotests: improve pause_job +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +From: Vladimir Sementsov-Ogievskiy + +It's possible, that job was finished during waiting. In this case we +will see error message "Timeout waiting for job to pause" which is not +very informative. So, let's check during waiting iteration that the job +exists. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-id: 20180601115923.17159-1-vsementsov@virtuozzo.com +Signed-off-by: Max Reitz +(cherry picked from commit c1bac161bb7ad27243776e90971c51cc38c2e1b6) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/iotests.py | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py +index 0b204dc..2f22fab 100644 +--- a/tests/qemu-iotests/iotests.py ++++ b/tests/qemu-iotests/iotests.py +@@ -590,9 +590,14 @@ class QMPTestCase(unittest.TestCase): + with Timeout(1, "Timeout waiting for job to pause"): + while True: + result = self.vm.qmp('query-block-jobs') ++ found = False + for job in result['return']: +- if job['device'] == job_id and job['paused'] == True and job['busy'] == False: +- return job ++ if job['device'] == job_id: ++ found = True ++ if job['paused'] == True and job['busy'] == False: ++ return job ++ break ++ assert found + + def pause_job(self, job_id='job0', wait=True): + result = self.vm.qmp('block-job-pause', device=job_id) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests.py-Add-qemu_io_silent.patch b/SOURCES/kvm-iotests.py-Add-qemu_io_silent.patch new file mode 100644 index 0000000..90384f0 --- /dev/null +++ b/SOURCES/kvm-iotests.py-Add-qemu_io_silent.patch @@ -0,0 +1,52 @@ +From fc5822a57d255dd35ccb789dc03ac11d699007a1 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 16:43:11 +0200 +Subject: [PATCH 43/54] iotests.py: Add qemu_io_silent + +RH-Author: Max Reitz +Message-id: <20180618164312.24423-5-mreitz@redhat.com> +Patchwork-id: 80777 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 4/5] iotests.py: Add qemu_io_silent +Bugzilla: 1519617 +RH-Acked-by: John Snow +RH-Acked-by: Kevin Wolf +RH-Acked-by: Miroslav Rezanina + +With qemu-io now returning a useful exit code, some tests may find it +sufficient to just query that instead of logging (and filtering) the +whole output. + +Signed-off-by: Max Reitz +Reviewed-by: Eric Blake +Message-id: 20180509194302.21585-5-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit 745f2bf4a5b973d1a69b21db97f9e4219da60624) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/iotests.py | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py +index b25d48a..9747ca9 100644 +--- a/tests/qemu-iotests/iotests.py ++++ b/tests/qemu-iotests/iotests.py +@@ -119,6 +119,15 @@ def qemu_io(*args): + sys.stderr.write('qemu-io received signal %i: %s\n' % (-exitcode, ' '.join(args))) + return subp.communicate()[0] + ++def qemu_io_silent(*args): ++ '''Run qemu-io and return the exit code, suppressing stdout''' ++ args = qemu_io_args + list(args) ++ exitcode = subprocess.call(args, stdout=open('/dev/null', 'w')) ++ if exitcode < 0: ++ sys.stderr.write('qemu-io received signal %i: %s\n' % ++ (-exitcode, ' '.join(args))) ++ return exitcode ++ + + class QemuIoInteractive: + def __init__(self, *args): +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iotests.py-add-FilePath-context-manager.patch b/SOURCES/kvm-iotests.py-add-FilePath-context-manager.patch deleted file mode 100644 index 0c49e1a..0000000 --- a/SOURCES/kvm-iotests.py-add-FilePath-context-manager.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 2715cad830a73bb550a4645054ff2e008f7e08fa Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Fri, 22 Dec 2017 11:08:42 +0100 -Subject: [PATCH 24/42] iotests.py: add FilePath context manager - -RH-Author: Stefan Hajnoczi -Message-id: <20171222110900.24813-3-stefanha@redhat.com> -Patchwork-id: 78484 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 02/20] iotests.py: add FilePath context manager -Bugzilla: 1519721 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -The scratch/ (TEST_DIR) directory is not automatically cleaned up after -test execution. It is the responsibility of tests to remove any files -they create. - -A nice way of doing this is to declare files at the beginning of the -test and automatically remove them with a context manager: - - with iotests.FilePath('test.img') as img_path: - qemu_img(...) - qemu_io(...) - # img_path is guaranteed to be deleted here - -Signed-off-by: Stefan Hajnoczi -Message-id: 20170824072202.26818-3-stefanha@redhat.com -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit f4844ac0adabc458ba4610a71155448783d37c73) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - tests/qemu-iotests/iotests.py | 26 ++++++++++++++++++++++++++ - 1 file changed, 26 insertions(+) - -diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py -index 7233983..07fa162 100644 ---- a/tests/qemu-iotests/iotests.py -+++ b/tests/qemu-iotests/iotests.py -@@ -160,6 +160,32 @@ class Timeout: - def timeout(self, signum, frame): - raise Exception(self.errmsg) - -+ -+class FilePath(object): -+ '''An auto-generated filename that cleans itself up. -+ -+ Use this context manager to generate filenames and ensure that the file -+ gets deleted:: -+ -+ with TestFilePath('test.img') as img_path: -+ qemu_img('create', img_path, '1G') -+ # migration_sock_path is automatically deleted -+ ''' -+ def __init__(self, name): -+ filename = '{0}-{1}'.format(os.getpid(), name) -+ self.path = os.path.join(test_dir, filename) -+ -+ def __enter__(self): -+ return self.path -+ -+ def __exit__(self, exc_type, exc_val, exc_tb): -+ try: -+ os.remove(self.path) -+ except OSError: -+ pass -+ return False -+ -+ - class VM(qtest.QEMUQtestMachine): - '''A QEMU VM''' - --- -1.8.3.1 - diff --git a/SOURCES/kvm-iothread-Make-iothread_stop-idempotent.patch b/SOURCES/kvm-iothread-Make-iothread_stop-idempotent.patch deleted file mode 100644 index 972447c..0000000 --- a/SOURCES/kvm-iothread-Make-iothread_stop-idempotent.patch +++ /dev/null @@ -1,56 +0,0 @@ -From aad2de527db618942ce1f5cad0d9c2e29ec42f2e Mon Sep 17 00:00:00 2001 -From: Eduardo Habkost -Date: Thu, 19 Oct 2017 01:34:50 +0200 -Subject: [PATCH 61/69] iothread: Make iothread_stop() idempotent - -RH-Author: Eduardo Habkost -Message-id: <20171019013453.21449-2-ehabkost@redhat.com> -Patchwork-id: 77367 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 1/4] iothread: Make iothread_stop() idempotent -Bugzilla: 1460848 -RH-Acked-by: Michael S. Tsirkin -RH-Acked-by: Igor Mammedov -RH-Acked-by: Paolo Bonzini - -Currently, iothread_stop_all() makes all iothread objects unsafe -to be destroyed, because qemu_thread_join() ends up being called -twice. - -To fix this, make iothread_stop() idempotent by checking -thread->stopped. - -Fixes the following crash: - - qemu-system-x86_64 -object iothread,id=iothread0 -monitor stdio -display none - QEMU 2.10.50 monitor - type 'help' for more information - (qemu) quit - qemu: qemu_thread_join: No such process - Aborted (core dumped) - -Reported-by: Christian Borntraeger -Signed-off-by: Eduardo Habkost -Message-Id: <20170926130028.12471-1-ehabkost@redhat.com> -Signed-off-by: Paolo Bonzini -(cherry picked from commit 65072c157e466db2785748a929e775703b20eefe) -Signed-off-by: Eduardo Habkost -Signed-off-by: Miroslav Rezanina ---- - iothread.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/iothread.c b/iothread.c -index beeb870..d67bdd4 100644 ---- a/iothread.c -+++ b/iothread.c -@@ -68,7 +68,7 @@ static int iothread_stop(Object *object, void *opaque) - IOThread *iothread; - - iothread = (IOThread *)object_dynamic_cast(object, TYPE_IOTHREAD); -- if (!iothread || !iothread->ctx) { -+ if (!iothread || !iothread->ctx || iothread->stopping) { - return 0; - } - iothread->stopping = true; --- -1.8.3.1 - diff --git a/SOURCES/kvm-iothread-add-iothread_by_id-API.patch b/SOURCES/kvm-iothread-add-iothread_by_id-API.patch deleted file mode 100644 index 261ec95..0000000 --- a/SOURCES/kvm-iothread-add-iothread_by_id-API.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 84bd8f0e4da949579b20ea0879c8b44404ef2604 Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Fri, 22 Dec 2017 11:08:54 +0100 -Subject: [PATCH 36/42] iothread: add iothread_by_id() API - -RH-Author: Stefan Hajnoczi -Message-id: <20171222110900.24813-15-stefanha@redhat.com> -Patchwork-id: 78498 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 14/20] iothread: add iothread_by_id() API -Bugzilla: 1519721 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -Encapsulate IOThread QOM object lookup so that callers don't need to -know how and where IOThread objects live. - -Signed-off-by: Stefan Hajnoczi -Reviewed-by: Kevin Wolf -Reviewed-by: Eric Blake -Message-id: 20171206144550.22295-8-stefanha@redhat.com -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit fbcc6923b00c2b468a7470fec7863f0403a65736) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - include/sysemu/iothread.h | 1 + - iothread.c | 7 +++++++ - 2 files changed, 8 insertions(+) - -diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h -index 110329b..55de171 100644 ---- a/include/sysemu/iothread.h -+++ b/include/sysemu/iothread.h -@@ -42,6 +42,7 @@ typedef struct { - OBJECT_CHECK(IOThread, obj, TYPE_IOTHREAD) - - char *iothread_get_id(IOThread *iothread); -+IOThread *iothread_by_id(const char *id); - AioContext *iothread_get_aio_context(IOThread *iothread); - void iothread_stop_all(void); - GMainContext *iothread_get_g_main_context(IOThread *iothread); -diff --git a/iothread.c b/iothread.c -index 27a4288..e7b93e0 100644 ---- a/iothread.c -+++ b/iothread.c -@@ -380,3 +380,10 @@ void iothread_destroy(IOThread *iothread) - { - object_unparent(OBJECT(iothread)); - } -+ -+/* Lookup IOThread by its id. Only finds user-created objects, not internal -+ * iothread_create() objects. */ -+IOThread *iothread_by_id(const char *id) -+{ -+ return IOTHREAD(object_resolve_path_type(id, TYPE_IOTHREAD, NULL)); -+} --- -1.8.3.1 - diff --git a/SOURCES/kvm-iothread-delay-the-context-release-to-finalize.patch b/SOURCES/kvm-iothread-delay-the-context-release-to-finalize.patch deleted file mode 100644 index 3daf0f7..0000000 --- a/SOURCES/kvm-iothread-delay-the-context-release-to-finalize.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 38a2a92899b4f351cb7f4c002428a064819a565a Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Fri, 22 Dec 2017 11:08:47 +0100 -Subject: [PATCH 29/42] iothread: delay the context release to finalize - -RH-Author: Stefan Hajnoczi -Message-id: <20171222110900.24813-8-stefanha@redhat.com> -Patchwork-id: 78489 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 07/20] iothread: delay the context release to finalize -Bugzilla: 1519721 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -From: Peter Xu - -When gcontext is used with iothread, the context will be destroyed -during iothread_stop(). That's not good since sometimes we would like -to keep the resources until iothread is destroyed, but we may want to -stop the thread before that point. - -Delay the destruction of gcontext to iothread finalize. Then we can do: - - iothread_stop(thread); - some_cleanup_on_resources(); - iothread_destroy(thread); - -We may need this patch if we want to run chardev IOs in iothreads and -hopefully clean them up correctly. For more specific information, -please see 2b316774f6 ("qemu-char: do not operate on sources from -finalize callbacks"). - -Reviewed-by: Fam Zheng -Reviewed-by: Stefan Hajnoczi -Signed-off-by: Peter Xu -Message-id: 20170928025958.1420-5-peterx@redhat.com -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit 5b3ac23fee97fc1a79ad2bb1cf3a1ce518d27905) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - iothread.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/iothread.c b/iothread.c -index b3c092b..27a4288 100644 ---- a/iothread.c -+++ b/iothread.c -@@ -71,8 +71,6 @@ static void *iothread_run(void *opaque) - g_main_loop_unref(loop); - - g_main_context_pop_thread_default(iothread->worker_context); -- g_main_context_unref(iothread->worker_context); -- iothread->worker_context = NULL; - } - } - -@@ -117,6 +115,10 @@ static void iothread_instance_finalize(Object *obj) - IOThread *iothread = IOTHREAD(obj); - - iothread_stop(iothread); -+ if (iothread->worker_context) { -+ g_main_context_unref(iothread->worker_context); -+ iothread->worker_context = NULL; -+ } - qemu_cond_destroy(&iothread->init_done_cond); - qemu_mutex_destroy(&iothread->init_done_lock); - if (!iothread->ctx) { --- -1.8.3.1 - diff --git a/SOURCES/kvm-iothread-export-iothread_stop.patch b/SOURCES/kvm-iothread-export-iothread_stop.patch deleted file mode 100644 index 76e665a..0000000 --- a/SOURCES/kvm-iothread-export-iothread_stop.patch +++ /dev/null @@ -1,112 +0,0 @@ -From 903416521c130289b769af87a70e19c2bbbff3aa Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Fri, 22 Dec 2017 11:08:46 +0100 -Subject: [PATCH 28/42] iothread: export iothread_stop() - -RH-Author: Stefan Hajnoczi -Message-id: <20171222110900.24813-7-stefanha@redhat.com> -Patchwork-id: 78488 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 06/20] iothread: export iothread_stop() -Bugzilla: 1519721 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -From: Peter Xu - -So that internal iothread users can explicitly stop one iothread without -destroying it. - -Since at it, fix iothread_stop() to allow it to be called multiple -times. Before this patch we may call iothread_stop() more than once on -single iothread, while that may not be correct since qemu_thread_join() -is not allowed to run twice. From manual of pthread_join(): - - Joining with a thread that has previously been joined results in - undefined behavior. - -Reviewed-by: Fam Zheng -Reviewed-by: Stefan Hajnoczi -Signed-off-by: Peter Xu -Message-id: 20170928025958.1420-4-peterx@redhat.com -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit 82d90705fe203cc6e150c10bd61f0dbe6979e8f4) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - include/sysemu/iothread.h | 1 + - iothread.c | 24 ++++++++++++++++-------- - 2 files changed, 17 insertions(+), 8 deletions(-) - -diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h -index b07663f..110329b 100644 ---- a/include/sysemu/iothread.h -+++ b/include/sysemu/iothread.h -@@ -52,6 +52,7 @@ GMainContext *iothread_get_g_main_context(IOThread *iothread); - * "query-iothreads". - */ - IOThread *iothread_create(const char *id, Error **errp); -+void iothread_stop(IOThread *iothread); - void iothread_destroy(IOThread *iothread); - - #endif /* IOTHREAD_H */ -diff --git a/iothread.c b/iothread.c -index 0672a91..b3c092b 100644 ---- a/iothread.c -+++ b/iothread.c -@@ -80,13 +80,10 @@ static void *iothread_run(void *opaque) - return NULL; - } - --static int iothread_stop(Object *object, void *opaque) -+void iothread_stop(IOThread *iothread) - { -- IOThread *iothread; -- -- iothread = (IOThread *)object_dynamic_cast(object, TYPE_IOTHREAD); -- if (!iothread || !iothread->ctx || iothread->stopping) { -- return 0; -+ if (!iothread->ctx || iothread->stopping) { -+ return; - } - iothread->stopping = true; - aio_notify(iothread->ctx); -@@ -94,6 +91,17 @@ static int iothread_stop(Object *object, void *opaque) - g_main_loop_quit(iothread->main_loop); - } - qemu_thread_join(&iothread->thread); -+} -+ -+static int iothread_stop_iter(Object *object, void *opaque) -+{ -+ IOThread *iothread; -+ -+ iothread = (IOThread *)object_dynamic_cast(object, TYPE_IOTHREAD); -+ if (!iothread) { -+ return 0; -+ } -+ iothread_stop(iothread); - return 0; - } - -@@ -108,7 +116,7 @@ static void iothread_instance_finalize(Object *obj) - { - IOThread *iothread = IOTHREAD(obj); - -- iothread_stop(obj, NULL); -+ iothread_stop(iothread); - qemu_cond_destroy(&iothread->init_done_cond); - qemu_mutex_destroy(&iothread->init_done_lock); - if (!iothread->ctx) { -@@ -328,7 +336,7 @@ void iothread_stop_all(void) - aio_context_release(ctx); - } - -- object_child_foreach(container, iothread_stop, NULL); -+ object_child_foreach(container, iothread_stop_iter, NULL); - } - - static gpointer iothread_g_main_context_init(gpointer opaque) --- -1.8.3.1 - diff --git a/SOURCES/kvm-iothread-fix-iothread_stop-race-condition.patch b/SOURCES/kvm-iothread-fix-iothread_stop-race-condition.patch deleted file mode 100644 index f3ace09..0000000 --- a/SOURCES/kvm-iothread-fix-iothread_stop-race-condition.patch +++ /dev/null @@ -1,158 +0,0 @@ -From 9750c7d9d35ac49262848a0996667f8e6c782dc8 Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Fri, 22 Dec 2017 11:08:59 +0100 -Subject: [PATCH 41/42] iothread: fix iothread_stop() race condition - -RH-Author: Stefan Hajnoczi -Message-id: <20171222110900.24813-20-stefanha@redhat.com> -Patchwork-id: 78501 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 19/20] iothread: fix iothread_stop() race condition -Bugzilla: 1519721 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -There is a small chance that iothread_stop() hangs as follows: - - Thread 3 (Thread 0x7f63eba5f700 (LWP 16105)): - #0 0x00007f64012c09b6 in ppoll () at /lib64/libc.so.6 - #1 0x000055959992eac9 in ppoll (__ss=0x0, __timeout=0x0, __nfds=, __fds=) at /usr/include/bits/poll2.h:77 - #2 0x000055959992eac9 in qemu_poll_ns (fds=, nfds=, timeout=) at util/qemu-timer.c:322 - #3 0x0000559599930711 in aio_poll (ctx=0x55959bdb83c0, blocking=blocking@entry=true) at util/aio-posix.c:629 - #4 0x00005595996806fe in iothread_run (opaque=0x55959bd78400) at iothread.c:59 - #5 0x00007f640159f609 in start_thread () at /lib64/libpthread.so.0 - #6 0x00007f64012cce6f in clone () at /lib64/libc.so.6 - - Thread 1 (Thread 0x7f640b45b280 (LWP 16103)): - #0 0x00007f64015a0b6d in pthread_join () at /lib64/libpthread.so.0 - #1 0x00005595999332ef in qemu_thread_join (thread=) at util/qemu-thread-posix.c:547 - #2 0x00005595996808ae in iothread_stop (iothread=) at iothread.c:91 - #3 0x000055959968094d in iothread_stop_iter (object=, opaque=) at iothread.c:102 - #4 0x0000559599857d97 in do_object_child_foreach (obj=obj@entry=0x55959bdb8100, fn=fn@entry=0x559599680930 , opaque=opaque@entry=0x0, recurse=recurse@entry=false) at qom/object.c:852 - #5 0x0000559599859477 in object_child_foreach (obj=obj@entry=0x55959bdb8100, fn=fn@entry=0x559599680930 , opaque=opaque@entry=0x0) at qom/object.c:867 - #6 0x0000559599680a6e in iothread_stop_all () at iothread.c:341 - #7 0x000055959955b1d5 in main (argc=, argv=, envp=) at vl.c:4913 - -The relevant code from iothread_run() is: - - while (!atomic_read(&iothread->stopping)) { - aio_poll(iothread->ctx, true); - -and iothread_stop(): - - iothread->stopping = true; - aio_notify(iothread->ctx); - ... - qemu_thread_join(&iothread->thread); - -The following scenario can occur: - -1. IOThread: - while (!atomic_read(&iothread->stopping)) -> stopping=false - -2. Main loop: - iothread->stopping = true; - aio_notify(iothread->ctx); - -3. IOThread: - aio_poll(iothread->ctx, true); -> hang - -The bug is explained by the AioContext->notify_me doc comments: - - "If this field is 0, everything (file descriptors, bottom halves, - timers) will be re-evaluated before the next blocking poll(), thus the - event_notifier_set call can be skipped." - -The problem is that "everything" does not include checking -iothread->stopping. This means iothread_run() will block in aio_poll() -if aio_notify() was called just before aio_poll(). - -This patch fixes the hang by replacing aio_notify() with -aio_bh_schedule_oneshot(). This makes aio_poll() or g_main_loop_run() -to return. - -Implementing this properly required a new bool running flag. The new -flag prevents races that are tricky if we try to use iothread->stopping. -Now iothread->stopping is purely for iothread_stop() and -iothread->running is purely for the iothread_run() thread. - -Signed-off-by: Stefan Hajnoczi -Reviewed-by: Eric Blake -Message-id: 20171207201320.19284-6-stefanha@redhat.com -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit 2362a28ea11c145e1a13ae79342d76dc118a72a6) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - include/sysemu/iothread.h | 3 ++- - iothread.c | 20 +++++++++++++++----- - 2 files changed, 17 insertions(+), 6 deletions(-) - -diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h -index 55de171..799614f 100644 ---- a/include/sysemu/iothread.h -+++ b/include/sysemu/iothread.h -@@ -29,7 +29,8 @@ typedef struct { - GOnce once; - QemuMutex init_done_lock; - QemuCond init_done_cond; /* is thread initialization done? */ -- bool stopping; -+ bool stopping; /* has iothread_stop() been called? */ -+ bool running; /* should iothread_run() continue? */ - int thread_id; - - /* AioContext poll parameters */ -diff --git a/iothread.c b/iothread.c -index e7b93e0..d8b6c1f 100644 ---- a/iothread.c -+++ b/iothread.c -@@ -55,7 +55,7 @@ static void *iothread_run(void *opaque) - qemu_cond_signal(&iothread->init_done_cond); - qemu_mutex_unlock(&iothread->init_done_lock); - -- while (!atomic_read(&iothread->stopping)) { -+ while (iothread->running) { - aio_poll(iothread->ctx, true); - - if (atomic_read(&iothread->worker_context)) { -@@ -78,16 +78,25 @@ static void *iothread_run(void *opaque) - return NULL; - } - -+/* Runs in iothread_run() thread */ -+static void iothread_stop_bh(void *opaque) -+{ -+ IOThread *iothread = opaque; -+ -+ iothread->running = false; /* stop iothread_run() */ -+ -+ if (iothread->main_loop) { -+ g_main_loop_quit(iothread->main_loop); -+ } -+} -+ - void iothread_stop(IOThread *iothread) - { - if (!iothread->ctx || iothread->stopping) { - return; - } - iothread->stopping = true; -- aio_notify(iothread->ctx); -- if (atomic_read(&iothread->main_loop)) { -- g_main_loop_quit(iothread->main_loop); -- } -+ aio_bh_schedule_oneshot(iothread->ctx, iothread_stop_bh, iothread); - qemu_thread_join(&iothread->thread); - } - -@@ -134,6 +143,7 @@ static void iothread_complete(UserCreatable *obj, Error **errp) - char *name, *thread_name; - - iothread->stopping = false; -+ iothread->running = true; - iothread->thread_id = -1; - iothread->ctx = aio_context_new(&local_error); - if (!iothread->ctx) { --- -1.8.3.1 - diff --git a/SOURCES/kvm-iothread-provide-helpers-for-internal-use.patch b/SOURCES/kvm-iothread-provide-helpers-for-internal-use.patch deleted file mode 100644 index e7f0335..0000000 --- a/SOURCES/kvm-iothread-provide-helpers-for-internal-use.patch +++ /dev/null @@ -1,79 +0,0 @@ -From a709d66bc6e7b3559fbd8502c6f94b76b6a899d1 Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Fri, 22 Dec 2017 11:08:45 +0100 -Subject: [PATCH 27/42] iothread: provide helpers for internal use - -RH-Author: Stefan Hajnoczi -Message-id: <20171222110900.24813-6-stefanha@redhat.com> -Patchwork-id: 78487 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 05/20] iothread: provide helpers for internal use -Bugzilla: 1519721 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -From: Peter Xu - -IOThread is a general framework that contains IO loop environment and a -real thread behind. It's also good to be used internally inside qemu. -Provide some helpers for it to create iothreads to be used internally. - -Put all the internal used iothreads into the internal object container. - -Reviewed-by: Fam Zheng -Reviewed-by: Stefan Hajnoczi -Signed-off-by: Peter Xu -Message-id: 20170928025958.1420-3-peterx@redhat.com -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit 0173e21b617d3de1fcfa917e329bb9194ab332a4) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - include/sysemu/iothread.h | 8 ++++++++ - iothread.c | 16 ++++++++++++++++ - 2 files changed, 24 insertions(+) - -diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h -index d2985b3..b07663f 100644 ---- a/include/sysemu/iothread.h -+++ b/include/sysemu/iothread.h -@@ -46,4 +46,12 @@ AioContext *iothread_get_aio_context(IOThread *iothread); - void iothread_stop_all(void); - GMainContext *iothread_get_g_main_context(IOThread *iothread); - -+/* -+ * Helpers used to allocate iothreads for internal use. These -+ * iothreads will not be seen by monitor clients when query using -+ * "query-iothreads". -+ */ -+IOThread *iothread_create(const char *id, Error **errp); -+void iothread_destroy(IOThread *iothread); -+ - #endif /* IOTHREAD_H */ -diff --git a/iothread.c b/iothread.c -index 59d0850..0672a91 100644 ---- a/iothread.c -+++ b/iothread.c -@@ -354,3 +354,19 @@ GMainContext *iothread_get_g_main_context(IOThread *iothread) - - return iothread->worker_context; - } -+ -+IOThread *iothread_create(const char *id, Error **errp) -+{ -+ Object *obj; -+ -+ obj = object_new_with_props(TYPE_IOTHREAD, -+ object_get_internal_root(), -+ id, errp, NULL); -+ -+ return IOTHREAD(obj); -+} -+ -+void iothread_destroy(IOThread *iothread) -+{ -+ object_unparent(OBJECT(iothread)); -+} --- -1.8.3.1 - diff --git a/SOURCES/kvm-iscsi-Create-and-use-iscsi_co_wait_for_task.patch b/SOURCES/kvm-iscsi-Create-and-use-iscsi_co_wait_for_task.patch new file mode 100644 index 0000000..713dce5 --- /dev/null +++ b/SOURCES/kvm-iscsi-Create-and-use-iscsi_co_wait_for_task.patch @@ -0,0 +1,139 @@ +From b528c59ca234b23c7bdcb9d3bcff20cdb111fd46 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 29 Jun 2018 06:11:47 +0200 +Subject: [PATCH 43/57] iscsi: Create and use iscsi_co_wait_for_task + +RH-Author: Fam Zheng +Message-id: <20180629061153.12687-8-famz@redhat.com> +Patchwork-id: 81160 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v2 07/13] iscsi: Create and use iscsi_co_wait_for_task +Bugzilla: 1482537 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Kevin Wolf + +This loop is repeated a growing number times. Make a helper. + +Signed-off-by: Fam Zheng +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Eric Blake +Message-id: 20180601092648.24614-8-famz@redhat.com +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 66e75c03b2247bda6dcaa883b700291bc0f7f0ef) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/iscsi.c | 54 +++++++++++++++++------------------------------------- + 1 file changed, 17 insertions(+), 37 deletions(-) + +diff --git a/block/iscsi.c b/block/iscsi.c +index a1a0044..338f3dd 100644 +--- a/block/iscsi.c ++++ b/block/iscsi.c +@@ -557,6 +557,17 @@ static inline bool iscsi_allocmap_is_valid(IscsiLun *iscsilun, + offset / iscsilun->cluster_size) == size); + } + ++static void coroutine_fn iscsi_co_wait_for_task(IscsiTask *iTask, ++ IscsiLun *iscsilun) ++{ ++ while (!iTask->complete) { ++ iscsi_set_events(iscsilun); ++ qemu_mutex_unlock(&iscsilun->mutex); ++ qemu_coroutine_yield(); ++ qemu_mutex_lock(&iscsilun->mutex); ++ } ++} ++ + static int coroutine_fn + iscsi_co_writev_flags(BlockDriverState *bs, int64_t sector_num, int nb_sectors, + QEMUIOVector *iov, int flags) +@@ -618,12 +629,7 @@ retry: + scsi_task_set_iov_out(iTask.task, (struct scsi_iovec *) iov->iov, + iov->niov); + #endif +- while (!iTask.complete) { +- iscsi_set_events(iscsilun); +- qemu_mutex_unlock(&iscsilun->mutex); +- qemu_coroutine_yield(); +- qemu_mutex_lock(&iscsilun->mutex); +- } ++ iscsi_co_wait_for_task(&iTask, iscsilun); + + if (iTask.task != NULL) { + scsi_free_scsi_task(iTask.task); +@@ -694,13 +700,7 @@ retry: + ret = -ENOMEM; + goto out_unlock; + } +- +- while (!iTask.complete) { +- iscsi_set_events(iscsilun); +- qemu_mutex_unlock(&iscsilun->mutex); +- qemu_coroutine_yield(); +- qemu_mutex_lock(&iscsilun->mutex); +- } ++ iscsi_co_wait_for_task(&iTask, iscsilun); + + if (iTask.do_retry) { + if (iTask.task != NULL) { +@@ -864,13 +864,8 @@ retry: + #if LIBISCSI_API_VERSION < (20160603) + scsi_task_set_iov_in(iTask.task, (struct scsi_iovec *) iov->iov, iov->niov); + #endif +- while (!iTask.complete) { +- iscsi_set_events(iscsilun); +- qemu_mutex_unlock(&iscsilun->mutex); +- qemu_coroutine_yield(); +- qemu_mutex_lock(&iscsilun->mutex); +- } + ++ iscsi_co_wait_for_task(&iTask, iscsilun); + if (iTask.task != NULL) { + scsi_free_scsi_task(iTask.task); + iTask.task = NULL; +@@ -907,12 +902,7 @@ retry: + return -ENOMEM; + } + +- while (!iTask.complete) { +- iscsi_set_events(iscsilun); +- qemu_mutex_unlock(&iscsilun->mutex); +- qemu_coroutine_yield(); +- qemu_mutex_lock(&iscsilun->mutex); +- } ++ iscsi_co_wait_for_task(&iTask, iscsilun); + + if (iTask.task != NULL) { + scsi_free_scsi_task(iTask.task); +@@ -1144,12 +1134,7 @@ retry: + goto out_unlock; + } + +- while (!iTask.complete) { +- iscsi_set_events(iscsilun); +- qemu_mutex_unlock(&iscsilun->mutex); +- qemu_coroutine_yield(); +- qemu_mutex_lock(&iscsilun->mutex); +- } ++ iscsi_co_wait_for_task(&iTask, iscsilun); + + if (iTask.task != NULL) { + scsi_free_scsi_task(iTask.task); +@@ -1245,12 +1230,7 @@ retry: + return -ENOMEM; + } + +- while (!iTask.complete) { +- iscsi_set_events(iscsilun); +- qemu_mutex_unlock(&iscsilun->mutex); +- qemu_coroutine_yield(); +- qemu_mutex_lock(&iscsilun->mutex); +- } ++ iscsi_co_wait_for_task(&iTask, iscsilun); + + if (iTask.status == SCSI_STATUS_CHECK_CONDITION && + iTask.task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST && +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iscsi-Don-t-blindly-use-designator-length-in-respons.patch b/SOURCES/kvm-iscsi-Don-t-blindly-use-designator-length-in-respons.patch new file mode 100644 index 0000000..6533b8d --- /dev/null +++ b/SOURCES/kvm-iscsi-Don-t-blindly-use-designator-length-in-respons.patch @@ -0,0 +1,42 @@ +From cb9d3b91772324bb697a0f3b89ecc181f59629e2 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 29 Jun 2018 06:11:52 +0200 +Subject: [PATCH 48/57] iscsi: Don't blindly use designator length in response + for memcpy + +RH-Author: Fam Zheng +Message-id: <20180629061153.12687-13-famz@redhat.com> +Patchwork-id: 81162 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v2 12/13] iscsi: Don't blindly use designator length in response for memcpy +Bugzilla: 1482537 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Kevin Wolf + +Per SCSI definition the designator_length we receive from INQUIRY is 8, +12 or at most 16, but we should be careful because the remote iscsi +target may misbehave, otherwise we could have a buffer overflow. + +Reported-by: Max Reitz +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/iscsi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/block/iscsi.c b/block/iscsi.c +index fbcd5bb..751884d 100644 +--- a/block/iscsi.c ++++ b/block/iscsi.c +@@ -2226,7 +2226,7 @@ static void iscsi_populate_target_desc(unsigned char *desc, IscsiLun *lun) + desc[5] = (dd->designator_type & 0xF) + | ((dd->association & 3) << 4); + desc[7] = dd->designator_length; +- memcpy(desc + 8, dd->designator, dd->designator_length); ++ memcpy(desc + 8, dd->designator, MIN(dd->designator_length, 20)); + + desc[28] = 0; + desc[29] = (lun->block_size >> 16) & 0xFF; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iscsi-Drop-deprecated-drive-parameter-filename.patch b/SOURCES/kvm-iscsi-Drop-deprecated-drive-parameter-filename.patch new file mode 100644 index 0000000..99880c7 --- /dev/null +++ b/SOURCES/kvm-iscsi-Drop-deprecated-drive-parameter-filename.patch @@ -0,0 +1,82 @@ +From 975a41d8556024bed3fafc5118f084adf4cb391e Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Mon, 18 Jun 2018 08:43:14 +0200 +Subject: [PATCH 07/54] iscsi: Drop deprecated -drive parameter "filename" + +RH-Author: Markus Armbruster +Message-id: <20180618084330.30009-8-armbru@redhat.com> +Patchwork-id: 80740 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 07/23] iscsi: Drop deprecated -drive parameter "filename" +Bugzilla: 1557995 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Parameter "filename" is deprecated since commit 5c3ad1a6a8f, v2.10.0. +Time to get rid of it. + +Signed-off-by: Markus Armbruster +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit deadbb8ebb5c253da9b8ed02ab51a0fadf60edc7) +Signed-off-by: Miroslav Rezanina +--- + block/iscsi.c | 23 ++--------------------- + 1 file changed, 2 insertions(+), 21 deletions(-) + +diff --git a/block/iscsi.c b/block/iscsi.c +index d19ae0e..658462b 100644 +--- a/block/iscsi.c ++++ b/block/iscsi.c +@@ -1732,10 +1732,6 @@ static QemuOptsList runtime_opts = { + .name = "timeout", + .type = QEMU_OPT_NUMBER, + }, +- { +- .name = "filename", +- .type = QEMU_OPT_STRING, +- }, + { /* end of list */ } + }, + }; +@@ -1751,27 +1747,12 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, + char *initiator_name = NULL; + QemuOpts *opts; + Error *local_err = NULL; +- const char *transport_name, *portal, *target, *filename; ++ const char *transport_name, *portal, *target; + #if LIBISCSI_API_VERSION >= (20160603) + enum iscsi_transport_type transport; + #endif + int i, ret = 0, timeout = 0, lun; + +- /* If we are given a filename, parse the filename, with precedence given to +- * filename encoded options */ +- filename = qdict_get_try_str(options, "filename"); +- if (filename) { +- warn_report("'filename' option specified. " +- "This is an unsupported option, and may be deprecated " +- "in the future"); +- iscsi_parse_filename(filename, options, &local_err); +- if (local_err) { +- ret = -EINVAL; +- error_propagate(errp, local_err); +- goto exit; +- } +- } +- + opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); + qemu_opts_absorb_qdict(opts, options, &local_err); + if (local_err) { +@@ -1989,7 +1970,7 @@ out: + } + memset(iscsilun, 0, sizeof(IscsiLun)); + } +-exit: ++ + return ret; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iscsi-Implement-copy-offloading.patch b/SOURCES/kvm-iscsi-Implement-copy-offloading.patch new file mode 100644 index 0000000..a63e770 --- /dev/null +++ b/SOURCES/kvm-iscsi-Implement-copy-offloading.patch @@ -0,0 +1,291 @@ +From e059872c2b30d6065411e7b11d6841efa69d57c4 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 29 Jun 2018 06:11:48 +0200 +Subject: [PATCH 44/57] iscsi: Implement copy offloading + +RH-Author: Fam Zheng +Message-id: <20180629061153.12687-9-famz@redhat.com> +Patchwork-id: 81159 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v2 08/13] iscsi: Implement copy offloading +Bugzilla: 1482537 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Kevin Wolf + +Issue EXTENDED COPY (LID1) command to implement the copy_range API. + +The parameter data construction code is modified from libiscsi's +iscsi-dd.c. + +Signed-off-by: Fam Zheng +Reviewed-by: Stefan Hajnoczi +Message-id: 20180601092648.24614-9-famz@redhat.com +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 604dfaaa3270081da689991afe83d94d3e8231df) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/iscsi.c | 219 +++++++++++++++++++++++++++++++++++++++++++++++ + include/scsi/constants.h | 4 + + 2 files changed, 223 insertions(+) + +diff --git a/block/iscsi.c b/block/iscsi.c +index 338f3dd..fbcd5bb 100644 +--- a/block/iscsi.c ++++ b/block/iscsi.c +@@ -2187,6 +2187,221 @@ static void coroutine_fn iscsi_co_invalidate_cache(BlockDriverState *bs, + iscsi_allocmap_invalidate(iscsilun); + } + ++static int coroutine_fn iscsi_co_copy_range_from(BlockDriverState *bs, ++ BdrvChild *src, ++ uint64_t src_offset, ++ BdrvChild *dst, ++ uint64_t dst_offset, ++ uint64_t bytes, ++ BdrvRequestFlags flags) ++{ ++ return bdrv_co_copy_range_to(src, src_offset, dst, dst_offset, bytes, flags); ++} ++ ++static struct scsi_task *iscsi_xcopy_task(int param_len) ++{ ++ struct scsi_task *task; ++ ++ task = g_new0(struct scsi_task, 1); ++ ++ task->cdb[0] = EXTENDED_COPY; ++ task->cdb[10] = (param_len >> 24) & 0xFF; ++ task->cdb[11] = (param_len >> 16) & 0xFF; ++ task->cdb[12] = (param_len >> 8) & 0xFF; ++ task->cdb[13] = param_len & 0xFF; ++ task->cdb_size = 16; ++ task->xfer_dir = SCSI_XFER_WRITE; ++ task->expxferlen = param_len; ++ ++ return task; ++} ++ ++static void iscsi_populate_target_desc(unsigned char *desc, IscsiLun *lun) ++{ ++ struct scsi_inquiry_device_designator *dd = lun->dd; ++ ++ memset(desc, 0, 32); ++ desc[0] = 0xE4; /* IDENT_DESCR_TGT_DESCR */ ++ desc[4] = dd->code_set; ++ desc[5] = (dd->designator_type & 0xF) ++ | ((dd->association & 3) << 4); ++ desc[7] = dd->designator_length; ++ memcpy(desc + 8, dd->designator, dd->designator_length); ++ ++ desc[28] = 0; ++ desc[29] = (lun->block_size >> 16) & 0xFF; ++ desc[30] = (lun->block_size >> 8) & 0xFF; ++ desc[31] = lun->block_size & 0xFF; ++} ++ ++static void iscsi_xcopy_desc_hdr(uint8_t *hdr, int dc, int cat, int src_index, ++ int dst_index) ++{ ++ hdr[0] = 0x02; /* BLK_TO_BLK_SEG_DESCR */ ++ hdr[1] = ((dc << 1) | cat) & 0xFF; ++ hdr[2] = (XCOPY_BLK2BLK_SEG_DESC_SIZE >> 8) & 0xFF; ++ /* don't account for the first 4 bytes in descriptor header*/ ++ hdr[3] = (XCOPY_BLK2BLK_SEG_DESC_SIZE - 4 /* SEG_DESC_SRC_INDEX_OFFSET */) & 0xFF; ++ hdr[4] = (src_index >> 8) & 0xFF; ++ hdr[5] = src_index & 0xFF; ++ hdr[6] = (dst_index >> 8) & 0xFF; ++ hdr[7] = dst_index & 0xFF; ++} ++ ++static void iscsi_xcopy_populate_desc(uint8_t *desc, int dc, int cat, ++ int src_index, int dst_index, int num_blks, ++ uint64_t src_lba, uint64_t dst_lba) ++{ ++ iscsi_xcopy_desc_hdr(desc, dc, cat, src_index, dst_index); ++ ++ /* The caller should verify the request size */ ++ assert(num_blks < 65536); ++ desc[10] = (num_blks >> 8) & 0xFF; ++ desc[11] = num_blks & 0xFF; ++ desc[12] = (src_lba >> 56) & 0xFF; ++ desc[13] = (src_lba >> 48) & 0xFF; ++ desc[14] = (src_lba >> 40) & 0xFF; ++ desc[15] = (src_lba >> 32) & 0xFF; ++ desc[16] = (src_lba >> 24) & 0xFF; ++ desc[17] = (src_lba >> 16) & 0xFF; ++ desc[18] = (src_lba >> 8) & 0xFF; ++ desc[19] = src_lba & 0xFF; ++ desc[20] = (dst_lba >> 56) & 0xFF; ++ desc[21] = (dst_lba >> 48) & 0xFF; ++ desc[22] = (dst_lba >> 40) & 0xFF; ++ desc[23] = (dst_lba >> 32) & 0xFF; ++ desc[24] = (dst_lba >> 24) & 0xFF; ++ desc[25] = (dst_lba >> 16) & 0xFF; ++ desc[26] = (dst_lba >> 8) & 0xFF; ++ desc[27] = dst_lba & 0xFF; ++} ++ ++static void iscsi_xcopy_populate_header(unsigned char *buf, int list_id, int str, ++ int list_id_usage, int prio, ++ int tgt_desc_len, ++ int seg_desc_len, int inline_data_len) ++{ ++ buf[0] = list_id; ++ buf[1] = ((str & 1) << 5) | ((list_id_usage & 3) << 3) | (prio & 7); ++ buf[2] = (tgt_desc_len >> 8) & 0xFF; ++ buf[3] = tgt_desc_len & 0xFF; ++ buf[8] = (seg_desc_len >> 24) & 0xFF; ++ buf[9] = (seg_desc_len >> 16) & 0xFF; ++ buf[10] = (seg_desc_len >> 8) & 0xFF; ++ buf[11] = seg_desc_len & 0xFF; ++ buf[12] = (inline_data_len >> 24) & 0xFF; ++ buf[13] = (inline_data_len >> 16) & 0xFF; ++ buf[14] = (inline_data_len >> 8) & 0xFF; ++ buf[15] = inline_data_len & 0xFF; ++} ++ ++static void iscsi_xcopy_data(struct iscsi_data *data, ++ IscsiLun *src, int64_t src_lba, ++ IscsiLun *dst, int64_t dst_lba, ++ uint16_t num_blocks) ++{ ++ uint8_t *buf; ++ const int src_offset = XCOPY_DESC_OFFSET; ++ const int dst_offset = XCOPY_DESC_OFFSET + IDENT_DESCR_TGT_DESCR_SIZE; ++ const int seg_offset = dst_offset + IDENT_DESCR_TGT_DESCR_SIZE; ++ ++ data->size = XCOPY_DESC_OFFSET + ++ IDENT_DESCR_TGT_DESCR_SIZE * 2 + ++ XCOPY_BLK2BLK_SEG_DESC_SIZE; ++ data->data = g_malloc0(data->size); ++ buf = data->data; ++ ++ /* Initialise the parameter list header */ ++ iscsi_xcopy_populate_header(buf, 1, 0, 2 /* LIST_ID_USAGE_DISCARD */, ++ 0, 2 * IDENT_DESCR_TGT_DESCR_SIZE, ++ XCOPY_BLK2BLK_SEG_DESC_SIZE, ++ 0); ++ ++ /* Initialise CSCD list with one src + one dst descriptor */ ++ iscsi_populate_target_desc(&buf[src_offset], src); ++ iscsi_populate_target_desc(&buf[dst_offset], dst); ++ ++ /* Initialise one segment descriptor */ ++ iscsi_xcopy_populate_desc(&buf[seg_offset], 0, 0, 0, 1, num_blocks, ++ src_lba, dst_lba); ++} ++ ++static int coroutine_fn iscsi_co_copy_range_to(BlockDriverState *bs, ++ BdrvChild *src, ++ uint64_t src_offset, ++ BdrvChild *dst, ++ uint64_t dst_offset, ++ uint64_t bytes, ++ BdrvRequestFlags flags) ++{ ++ IscsiLun *dst_lun = dst->bs->opaque; ++ IscsiLun *src_lun; ++ struct IscsiTask iscsi_task; ++ struct iscsi_data data; ++ int r = 0; ++ int block_size; ++ ++ if (src->bs->drv->bdrv_co_copy_range_to != iscsi_co_copy_range_to) { ++ return -ENOTSUP; ++ } ++ src_lun = src->bs->opaque; ++ ++ if (!src_lun->dd || !dst_lun->dd) { ++ return -ENOTSUP; ++ } ++ if (!is_byte_request_lun_aligned(dst_offset, bytes, dst_lun)) { ++ return -ENOTSUP; ++ } ++ if (!is_byte_request_lun_aligned(src_offset, bytes, src_lun)) { ++ return -ENOTSUP; ++ } ++ if (dst_lun->block_size != src_lun->block_size || ++ !dst_lun->block_size) { ++ return -ENOTSUP; ++ } ++ ++ block_size = dst_lun->block_size; ++ if (bytes / block_size > 65535) { ++ return -ENOTSUP; ++ } ++ ++ iscsi_xcopy_data(&data, ++ src_lun, src_offset / block_size, ++ dst_lun, dst_offset / block_size, ++ bytes / block_size); ++ ++ iscsi_co_init_iscsitask(dst_lun, &iscsi_task); ++ ++ qemu_mutex_lock(&dst_lun->mutex); ++ iscsi_task.task = iscsi_xcopy_task(data.size); ++retry: ++ if (iscsi_scsi_command_async(dst_lun->iscsi, dst_lun->lun, ++ iscsi_task.task, iscsi_co_generic_cb, ++ &data, ++ &iscsi_task) != 0) { ++ r = -EIO; ++ goto out_unlock; ++ } ++ ++ iscsi_co_wait_for_task(&iscsi_task, dst_lun); ++ ++ if (iscsi_task.do_retry) { ++ iscsi_task.complete = 0; ++ goto retry; ++ } ++ ++ if (iscsi_task.status != SCSI_STATUS_GOOD) { ++ r = iscsi_task.err_code; ++ goto out_unlock; ++ } ++ ++out_unlock: ++ g_free(iscsi_task.task); ++ qemu_mutex_unlock(&dst_lun->mutex); ++ g_free(iscsi_task.err_str); ++ return r; ++} ++ + static QemuOptsList iscsi_create_opts = { + .name = "iscsi-create-opts", + .head = QTAILQ_HEAD_INITIALIZER(iscsi_create_opts.head), +@@ -2221,6 +2436,8 @@ static BlockDriver bdrv_iscsi = { + + .bdrv_co_block_status = iscsi_co_block_status, + .bdrv_co_pdiscard = iscsi_co_pdiscard, ++ .bdrv_co_copy_range_from = iscsi_co_copy_range_from, ++ .bdrv_co_copy_range_to = iscsi_co_copy_range_to, + .bdrv_co_pwrite_zeroes = iscsi_co_pwrite_zeroes, + .bdrv_co_readv = iscsi_co_readv, + .bdrv_co_writev_flags = iscsi_co_writev_flags, +@@ -2256,6 +2473,8 @@ static BlockDriver bdrv_iser = { + + .bdrv_co_block_status = iscsi_co_block_status, + .bdrv_co_pdiscard = iscsi_co_pdiscard, ++ .bdrv_co_copy_range_from = iscsi_co_copy_range_from, ++ .bdrv_co_copy_range_to = iscsi_co_copy_range_to, + .bdrv_co_pwrite_zeroes = iscsi_co_pwrite_zeroes, + .bdrv_co_readv = iscsi_co_readv, + .bdrv_co_writev_flags = iscsi_co_writev_flags, +diff --git a/include/scsi/constants.h b/include/scsi/constants.h +index a141dd7..083a8e8 100644 +--- a/include/scsi/constants.h ++++ b/include/scsi/constants.h +@@ -311,4 +311,8 @@ + #define MMC_PROFILE_HDDVD_RW_DL 0x005A + #define MMC_PROFILE_INVALID 0xFFFF + ++#define XCOPY_DESC_OFFSET 16 ++#define IDENT_DESCR_TGT_DESCR_SIZE 32 ++#define XCOPY_BLK2BLK_SEG_DESC_SIZE 28 ++ + #endif +-- +1.8.3.1 + diff --git a/SOURCES/kvm-iscsi-Query-and-save-device-designator-when-opening.patch b/SOURCES/kvm-iscsi-Query-and-save-device-designator-when-opening.patch new file mode 100644 index 0000000..8951b07 --- /dev/null +++ b/SOURCES/kvm-iscsi-Query-and-save-device-designator-when-opening.patch @@ -0,0 +1,112 @@ +From 20dcbb9776926fea51e6178298ed76f2c64a1d03 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 29 Jun 2018 06:11:46 +0200 +Subject: [PATCH 42/57] iscsi: Query and save device designator when opening + +RH-Author: Fam Zheng +Message-id: <20180629061153.12687-7-famz@redhat.com> +Patchwork-id: 81157 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v2 06/13] iscsi: Query and save device designator when opening +Bugzilla: 1482537 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Kevin Wolf + +The device designator data returned in INQUIRY command will be useful to +fill in source/target fields during copy offloading. Do this when +connecting to the target and save the data for later use. + +Signed-off-by: Fam Zheng +Reviewed-by: Stefan Hajnoczi +Message-id: 20180601092648.24614-7-famz@redhat.com +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit cc9743c236cce8a35449e3ef67140287b68bb705) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/iscsi.c | 41 +++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 41 insertions(+) + +diff --git a/block/iscsi.c b/block/iscsi.c +index 1705187..a1a0044 100644 +--- a/block/iscsi.c ++++ b/block/iscsi.c +@@ -69,6 +69,7 @@ typedef struct IscsiLun { + QemuMutex mutex; + struct scsi_inquiry_logical_block_provisioning lbp; + struct scsi_inquiry_block_limits bl; ++ struct scsi_inquiry_device_designator *dd; + unsigned char *zeroblock; + /* The allocmap tracks which clusters (pages) on the iSCSI target are + * allocated and which are not. In case a target returns zeros for +@@ -1737,6 +1738,30 @@ static QemuOptsList runtime_opts = { + }, + }; + ++static void iscsi_save_designator(IscsiLun *lun, ++ struct scsi_inquiry_device_identification *inq_di) ++{ ++ struct scsi_inquiry_device_designator *desig, *copy = NULL; ++ ++ for (desig = inq_di->designators; desig; desig = desig->next) { ++ if (desig->association || ++ desig->designator_type > SCSI_DESIGNATOR_TYPE_NAA) { ++ continue; ++ } ++ /* NAA works better than T10 vendor ID based designator. */ ++ if (!copy || copy->designator_type < desig->designator_type) { ++ copy = desig; ++ } ++ } ++ if (copy) { ++ lun->dd = g_new(struct scsi_inquiry_device_designator, 1); ++ *lun->dd = *copy; ++ lun->dd->next = NULL; ++ lun->dd->designator = g_malloc(copy->designator_length); ++ memcpy(lun->dd->designator, copy->designator, copy->designator_length); ++ } ++} ++ + static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, + Error **errp) + { +@@ -1904,6 +1929,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, + struct scsi_task *inq_task; + struct scsi_inquiry_logical_block_provisioning *inq_lbp; + struct scsi_inquiry_block_limits *inq_bl; ++ struct scsi_inquiry_device_identification *inq_di; + switch (inq_vpd->pages[i]) { + case SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING: + inq_task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1, +@@ -1929,6 +1955,17 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, + sizeof(struct scsi_inquiry_block_limits)); + scsi_free_scsi_task(inq_task); + break; ++ case SCSI_INQUIRY_PAGECODE_DEVICE_IDENTIFICATION: ++ inq_task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1, ++ SCSI_INQUIRY_PAGECODE_DEVICE_IDENTIFICATION, ++ (void **) &inq_di, errp); ++ if (inq_task == NULL) { ++ ret = -EINVAL; ++ goto out; ++ } ++ iscsi_save_designator(iscsilun, inq_di); ++ scsi_free_scsi_task(inq_task); ++ break; + default: + break; + } +@@ -1985,6 +2022,10 @@ static void iscsi_close(BlockDriverState *bs) + iscsi_logout_sync(iscsi); + } + iscsi_destroy_context(iscsi); ++ if (iscsilun->dd) { ++ g_free(iscsilun->dd->designator); ++ g_free(iscsilun->dd); ++ } + g_free(iscsilun->zeroblock); + iscsi_allocmap_free(iscsilun); + qemu_mutex_destroy(&iscsilun->mutex); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Add-JOB_STATUS_CHANGE-QMP-event.patch b/SOURCES/kvm-job-Add-JOB_STATUS_CHANGE-QMP-event.patch new file mode 100644 index 0000000..5d0d177 --- /dev/null +++ b/SOURCES/kvm-job-Add-JOB_STATUS_CHANGE-QMP-event.patch @@ -0,0 +1,1333 @@ +From 72b18613852189fb6b2c1a8e88f5bd83749dfe2e Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:31 +0200 +Subject: [PATCH 62/89] job: Add JOB_STATUS_CHANGE QMP event + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-49-kwolf@redhat.com> +Patchwork-id: 81121 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 48/73] job: Add JOB_STATUS_CHANGE QMP event +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This adds a QMP event that is emitted whenever a job transitions from +one status to another. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +(cherry picked from commit 1dac83f1a10c4c66858075970e199f4e4a8d8b71) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + job.c | 10 +++ + qapi/job.json | 14 ++++ + tests/qemu-iotests/030 | 17 +++- + tests/qemu-iotests/040 | 2 + + tests/qemu-iotests/041 | 17 +++- + tests/qemu-iotests/094.out | 7 ++ + tests/qemu-iotests/095 | 2 +- + tests/qemu-iotests/095.out | 6 ++ + tests/qemu-iotests/109 | 2 +- + tests/qemu-iotests/109.out | 178 ++++++++++++++++++++++++++++++++++++------ + tests/qemu-iotests/124 | 8 ++ + tests/qemu-iotests/127.out | 7 ++ + tests/qemu-iotests/141 | 13 ++- + tests/qemu-iotests/141.out | 29 +++++++ + tests/qemu-iotests/144 | 2 +- + tests/qemu-iotests/144.out | 7 ++ + tests/qemu-iotests/156 | 2 +- + tests/qemu-iotests/156.out | 7 ++ + tests/qemu-iotests/185 | 12 +-- + tests/qemu-iotests/185.out | 10 +++ + tests/qemu-iotests/191 | 4 +- + tests/qemu-iotests/191.out | 132 +++++++++++++++++++++++++++++++ + tests/qemu-iotests/iotests.py | 5 ++ + 23 files changed, 449 insertions(+), 44 deletions(-) + +diff --git a/job.c b/job.c +index 2046d2f..599a104 100644 +--- a/job.c ++++ b/job.c +@@ -30,6 +30,7 @@ + #include "qemu/id.h" + #include "qemu/main-loop.h" + #include "trace-root.h" ++#include "qapi/qapi-events-job.h" + + static QLIST_HEAD(, Job) jobs = QLIST_HEAD_INITIALIZER(jobs); + +@@ -157,6 +158,11 @@ static int job_txn_apply(JobTxn *txn, int fn(Job *), bool lock) + return rc; + } + ++static bool job_is_internal(Job *job) ++{ ++ return (job->id == NULL); ++} ++ + static void job_state_transition(Job *job, JobStatus s1) + { + JobStatus s0 = job->status; +@@ -166,6 +172,10 @@ static void job_state_transition(Job *job, JobStatus s1) + JobStatus_str(s0), JobStatus_str(s1)); + assert(JobSTT[s0][s1]); + job->status = s1; ++ ++ if (!job_is_internal(job) && s1 != s0) { ++ qapi_event_send_job_status_change(job->id, job->status, &error_abort); ++ } + } + + int job_apply_verb(Job *job, JobVerb verb, Error **errp) +diff --git a/qapi/job.json b/qapi/job.json +index a472c0c..9fbdd0c 100644 +--- a/qapi/job.json ++++ b/qapi/job.json +@@ -92,3 +92,17 @@ + { 'enum': 'JobVerb', + 'data': ['cancel', 'pause', 'resume', 'set-speed', 'complete', 'dismiss', + 'finalize' ] } ++ ++## ++# @JOB_STATUS_CHANGE: ++# ++# Emitted when a job transitions to a different status. ++# ++# @id: The job identifier ++# @status: The new job status ++# ++# Since: 2.13 ++## ++{ 'event': 'JOB_STATUS_CHANGE', ++ 'data': { 'id': 'str', ++ 'status': 'JobStatus' } } +diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030 +index 640a6df..1dbc2dd 100755 +--- a/tests/qemu-iotests/030 ++++ b/tests/qemu-iotests/030 +@@ -304,8 +304,7 @@ class TestParallelOps(iotests.QMPTestCase): + result = self.vm.qmp('block-stream', device='node5', base=self.imgs[3], job_id='stream-node6') + self.assert_qmp(result, 'error/class', 'GenericError') + +- event = self.vm.get_qmp_event(wait=True) +- self.assertEqual(event['event'], 'BLOCK_JOB_READY') ++ event = self.vm.event_wait(name='BLOCK_JOB_READY') + self.assert_qmp(event, 'data/device', 'commit-drive0') + self.assert_qmp(event, 'data/type', 'commit') + self.assert_qmp_absent(event, 'data/error') +@@ -565,6 +564,8 @@ class TestEIO(TestErrors): + self.assert_qmp(event, 'data/offset', self.STREAM_BUFFER_SIZE) + self.assert_qmp(event, 'data/len', self.image_len) + completed = True ++ elif event['event'] == 'JOB_STATUS_CHANGE': ++ self.assert_qmp(event, 'data/id', 'drive0') + + self.assert_no_active_block_jobs() + self.vm.shutdown() +@@ -596,6 +597,8 @@ class TestEIO(TestErrors): + self.assert_qmp(event, 'data/offset', self.image_len) + self.assert_qmp(event, 'data/len', self.image_len) + completed = True ++ elif event['event'] == 'JOB_STATUS_CHANGE': ++ self.assert_qmp(event, 'data/id', 'drive0') + + self.assert_no_active_block_jobs() + self.vm.shutdown() +@@ -637,6 +640,8 @@ class TestEIO(TestErrors): + self.assert_qmp(event, 'data/offset', self.image_len) + self.assert_qmp(event, 'data/len', self.image_len) + completed = True ++ elif event['event'] == 'JOB_STATUS_CHANGE': ++ self.assert_qmp(event, 'data/id', 'drive0') + + self.assert_no_active_block_jobs() + self.vm.shutdown() +@@ -663,6 +668,8 @@ class TestEIO(TestErrors): + self.assert_qmp(event, 'data/offset', self.STREAM_BUFFER_SIZE) + self.assert_qmp(event, 'data/len', self.image_len) + completed = True ++ elif event['event'] == 'JOB_STATUS_CHANGE': ++ self.assert_qmp(event, 'data/id', 'drive0') + + self.assert_no_active_block_jobs() + self.vm.shutdown() +@@ -722,6 +729,8 @@ class TestENOSPC(TestErrors): + self.assert_qmp(event, 'data/offset', self.image_len) + self.assert_qmp(event, 'data/len', self.image_len) + completed = True ++ elif event['event'] == 'JOB_STATUS_CHANGE': ++ self.assert_qmp(event, 'data/id', 'drive0') + + self.assert_no_active_block_jobs() + self.vm.shutdown() +@@ -751,7 +760,9 @@ class TestStreamStop(iotests.QMPTestCase): + + time.sleep(0.1) + events = self.vm.get_qmp_events(wait=False) +- self.assertEqual(events, [], 'unexpected QMP event: %s' % events) ++ for e in events: ++ self.assert_qmp(e, 'event', 'JOB_STATUS_CHANGE') ++ self.assert_qmp(e, 'data/id', 'drive0') + + self.cancel_and_wait(resume=True) + +diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040 +index 90b5b4f..1beb5e6 100755 +--- a/tests/qemu-iotests/040 ++++ b/tests/qemu-iotests/040 +@@ -162,6 +162,8 @@ class TestSingleDrive(ImageCommitTestCase): + elif event['event'] == 'BLOCK_JOB_CANCELLED': + self.assert_qmp(event, 'data/device', 'drive0') + cancelled = True ++ elif event['event'] == 'JOB_STATUS_CHANGE': ++ self.assert_qmp(event, 'data/id', 'drive0') + else: + self.fail("Unexpected event %s" % (event['event'])) + +diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041 +index a860a31..e945879 100755 +--- a/tests/qemu-iotests/041 ++++ b/tests/qemu-iotests/041 +@@ -445,6 +445,8 @@ new_state = "1" + self.assert_qmp(event, 'data/device', 'drive0') + self.assert_qmp(event, 'data/error', 'Input/output error') + completed = True ++ elif event['event'] == 'JOB_STATUS_CHANGE': ++ self.assert_qmp(event, 'data/id', 'drive0') + + self.assert_no_active_block_jobs() + self.vm.shutdown() +@@ -457,6 +459,10 @@ new_state = "1" + self.assert_qmp(result, 'return', {}) + + event = self.vm.get_qmp_event(wait=True) ++ while event['event'] == 'JOB_STATUS_CHANGE': ++ self.assert_qmp(event, 'data/id', 'drive0') ++ event = self.vm.get_qmp_event(wait=True) ++ + self.assertEquals(event['event'], 'BLOCK_JOB_ERROR') + self.assert_qmp(event, 'data/device', 'drive0') + self.assert_qmp(event, 'data/operation', 'read') +@@ -478,6 +484,10 @@ new_state = "1" + self.assert_qmp(result, 'return', {}) + + event = self.vm.get_qmp_event(wait=True) ++ while event['event'] == 'JOB_STATUS_CHANGE': ++ self.assert_qmp(event, 'data/id', 'drive0') ++ event = self.vm.get_qmp_event(wait=True) ++ + self.assertEquals(event['event'], 'BLOCK_JOB_ERROR') + self.assert_qmp(event, 'data/device', 'drive0') + self.assert_qmp(event, 'data/operation', 'read') +@@ -608,7 +618,7 @@ new_state = "1" + on_target_error='ignore') + self.assert_qmp(result, 'return', {}) + +- event = self.vm.get_qmp_event(wait=True) ++ event = self.vm.event_wait(name='BLOCK_JOB_ERROR') + self.assertEquals(event['event'], 'BLOCK_JOB_ERROR') + self.assert_qmp(event, 'data/device', 'drive0') + self.assert_qmp(event, 'data/operation', 'write') +@@ -784,7 +794,12 @@ class TestGranularity(iotests.QMPTestCase): + sync='full', target=target_img, + mode='absolute-paths', granularity=8192) + self.assert_qmp(result, 'return', {}) ++ + event = self.vm.get_qmp_event(wait=60.0) ++ while event['event'] == 'JOB_STATUS_CHANGE': ++ self.assert_qmp(event, 'data/id', 'drive0') ++ event = self.vm.get_qmp_event(wait=60.0) ++ + # Failures will manifest as COMPLETED/ERROR. + self.assert_qmp(event, 'event', 'BLOCK_JOB_READY') + self.complete_and_wait(drive='drive0', wait_ready=False) +diff --git a/tests/qemu-iotests/094.out b/tests/qemu-iotests/094.out +index f52baff..665b630 100644 +--- a/tests/qemu-iotests/094.out ++++ b/tests/qemu-iotests/094.out +@@ -2,10 +2,17 @@ QA output created by 094 + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 + Formatting 'TEST_DIR/source.IMGFMT', fmt=IMGFMT size=67108864 + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}} + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + *** done +diff --git a/tests/qemu-iotests/095 b/tests/qemu-iotests/095 +index 030adb2..72ecc22 100755 +--- a/tests/qemu-iotests/095 ++++ b/tests/qemu-iotests/095 +@@ -72,7 +72,7 @@ _send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" "return" + + _send_qemu_cmd $h "{ 'execute': 'block-commit', + 'arguments': { 'device': 'test', +- 'top': '"${TEST_IMG}.snp1"' } }" "BLOCK_JOB_COMPLETED" ++ 'top': '"${TEST_IMG}.snp1"' } }" '"status": "null"' + + _cleanup_qemu + +diff --git a/tests/qemu-iotests/095.out b/tests/qemu-iotests/095.out +index 73875ca..8c093df 100644 +--- a/tests/qemu-iotests/095.out ++++ b/tests/qemu-iotests/095.out +@@ -11,8 +11,14 @@ virtual size: 5.0M (5242880 bytes) + === Running QEMU Live Commit Test === + + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "test"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "test"}} + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "test"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "test"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "test", "len": 104857600, "offset": 104857600, "speed": 0, "type": "commit"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "test"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "test"}} + + === Base image info after commit and resize === + image: TEST_DIR/t.IMGFMT.base +diff --git a/tests/qemu-iotests/109 b/tests/qemu-iotests/109 +index d70b574..acbd079 100755 +--- a/tests/qemu-iotests/109 ++++ b/tests/qemu-iotests/109 +@@ -64,7 +64,7 @@ function run_qemu() + + _send_qemu_cmd $QEMU_HANDLE '' "$qmp_event" + if test "$qmp_event" = BLOCK_JOB_ERROR; then +- _send_qemu_cmd $QEMU_HANDLE '' "BLOCK_JOB_COMPLETED" ++ _send_qemu_cmd $QEMU_HANDLE '' '"status": "null"' + fi + _send_qemu_cmd $QEMU_HANDLE '{"execute":"query-block-jobs"}' "return" + _send_qemu_cmd $QEMU_HANDLE '{"execute":"quit"}' "return" +diff --git a/tests/qemu-iotests/109.out b/tests/qemu-iotests/109.out +index 8a9b936..ad0ee6f 100644 +--- a/tests/qemu-iotests/109.out ++++ b/tests/qemu-iotests/109.out +@@ -6,23 +6,35 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 + Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 + {"return": {}} + WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. +-Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +-Specify the 'raw' format explicitly to remove the restrictions. ++ Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. ++ Specify the 'raw' format explicitly to remove the restrictions. ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} + {"return": []} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + read 65536/65536 bytes at offset 0 + 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}} + {"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 1024, "offset": 1024, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} + Warning: Image size mismatch! + Images are identical. + +@@ -32,23 +44,35 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 + Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 + {"return": {}} + WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. +-Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +-Specify the 'raw' format explicitly to remove the restrictions. ++ Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. ++ Specify the 'raw' format explicitly to remove the restrictions. ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": 512, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} + {"return": []} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + read 65536/65536 bytes at offset 0 + 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 197120, "offset": 197120, "speed": 0, "type": "mirror"}} + {"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 197120, "offset": 197120, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 197120, "offset": 197120, "speed": 0, "type": "mirror"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} + Warning: Image size mismatch! + Images are identical. + +@@ -58,23 +82,35 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 + Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 + {"return": {}} + WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. +-Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +-Specify the 'raw' format explicitly to remove the restrictions. ++ Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. ++ Specify the 'raw' format explicitly to remove the restrictions. ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": 262144, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} + {"return": []} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + read 65536/65536 bytes at offset 0 + 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}} + {"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 327680, "offset": 327680, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} + Warning: Image size mismatch! + Images are identical. + +@@ -84,23 +120,35 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 + Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 + {"return": {}} + WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. +-Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +-Specify the 'raw' format explicitly to remove the restrictions. ++ Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. ++ Specify the 'raw' format explicitly to remove the restrictions. ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} + {"return": []} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + read 65536/65536 bytes at offset 0 + 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}} + {"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 1024, "offset": 1024, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} + Warning: Image size mismatch! + Images are identical. + +@@ -110,23 +158,35 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 + Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 + {"return": {}} + WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. +-Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +-Specify the 'raw' format explicitly to remove the restrictions. ++ Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. ++ Specify the 'raw' format explicitly to remove the restrictions. ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} + {"return": []} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + read 65536/65536 bytes at offset 0 + 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 65536, "offset": 65536, "speed": 0, "type": "mirror"}} + {"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 65536, "offset": 65536, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": 65536, "speed": 0, "type": "mirror"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} + Warning: Image size mismatch! + Images are identical. + +@@ -136,23 +196,35 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 + Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 + {"return": {}} + WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. +-Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +-Specify the 'raw' format explicitly to remove the restrictions. ++ Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. ++ Specify the 'raw' format explicitly to remove the restrictions. ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} + {"return": []} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + read 65536/65536 bytes at offset 0 + 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}} + {"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 2560, "offset": 2560, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} + Warning: Image size mismatch! + Images are identical. + +@@ -161,23 +233,35 @@ Images are identical. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 + {"return": {}} + WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. +-Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +-Specify the 'raw' format explicitly to remove the restrictions. ++ Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. ++ Specify the 'raw' format explicitly to remove the restrictions. ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} + {"return": []} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + read 65536/65536 bytes at offset 0 + 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}} + {"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 2560, "offset": 2560, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} + Warning: Image size mismatch! + Images are identical. + +@@ -186,23 +270,35 @@ Images are identical. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 + {"return": {}} + WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. +-Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +-Specify the 'raw' format explicitly to remove the restrictions. ++ Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. ++ Specify the 'raw' format explicitly to remove the restrictions. ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} + {"return": []} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + read 65536/65536 bytes at offset 0 + 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 31457280, "offset": 31457280, "speed": 0, "type": "mirror"}} + {"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 31457280, "offset": 31457280, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 31457280, "offset": 31457280, "speed": 0, "type": "mirror"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} + Warning: Image size mismatch! + Images are identical. + +@@ -211,23 +307,35 @@ Images are identical. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 + {"return": {}} + WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. +-Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +-Specify the 'raw' format explicitly to remove the restrictions. ++ Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. ++ Specify the 'raw' format explicitly to remove the restrictions. ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} + {"return": []} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + read 65536/65536 bytes at offset 0 + 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}} + {"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 327680, "offset": 327680, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} + Warning: Image size mismatch! + Images are identical. + +@@ -236,23 +344,35 @@ Images are identical. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 + {"return": {}} + WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. +-Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +-Specify the 'raw' format explicitly to remove the restrictions. ++ Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. ++ Specify the 'raw' format explicitly to remove the restrictions. ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} + {"return": []} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + read 65536/65536 bytes at offset 0 + 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 2048, "offset": 2048, "speed": 0, "type": "mirror"}} + {"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 2048, "offset": 2048, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2048, "offset": 2048, "speed": 0, "type": "mirror"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} + Warning: Image size mismatch! + Images are identical. + +@@ -261,23 +381,37 @@ Images are identical. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 + {"return": {}} + WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. +-Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. +-Specify the 'raw' format explicitly to remove the restrictions. ++ Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. ++ Specify the 'raw' format explicitly to remove the restrictions. ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}} + {"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 512, "offset": 512, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} + Warning: Image size mismatch! + Images are identical. + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}} + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}} + {"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 512, "offset": 512, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}} + Warning: Image size mismatch! + Images are identical. + *** done +diff --git a/tests/qemu-iotests/124 b/tests/qemu-iotests/124 +index 8e76e62..3ea4ac5 100755 +--- a/tests/qemu-iotests/124 ++++ b/tests/qemu-iotests/124 +@@ -151,10 +151,17 @@ class TestIncrementalBackupBase(iotests.QMPTestCase): + return self.wait_qmp_backup(kwargs['device'], error) + + ++ def ignore_job_status_change_events(self): ++ while True: ++ e = self.vm.event_wait(name="JOB_STATUS_CHANGE") ++ if e['data']['status'] == 'null': ++ break ++ + def wait_qmp_backup(self, device, error='Input/output error'): + event = self.vm.event_wait(name="BLOCK_JOB_COMPLETED", + match={'data': {'device': device}}) + self.assertNotEqual(event, None) ++ self.ignore_job_status_change_events() + + try: + failure = self.dictpath(event, 'data/error') +@@ -172,6 +179,7 @@ class TestIncrementalBackupBase(iotests.QMPTestCase): + event = self.vm.event_wait(name='BLOCK_JOB_CANCELLED', + match={'data': {'device': device}}) + self.assertNotEqual(event, None) ++ self.ignore_job_status_change_events() + + + def create_anchor_backup(self, drive=None): +diff --git a/tests/qemu-iotests/127.out b/tests/qemu-iotests/127.out +index 543d075..83b522d 100644 +--- a/tests/qemu-iotests/127.out ++++ b/tests/qemu-iotests/127.out +@@ -5,10 +5,17 @@ Formatting 'TEST_DIR/t.IMGFMT.overlay1', fmt=IMGFMT size=65536 backing_file=TEST + wrote 42/42 bytes at offset 0 + 42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "mirror"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "mirror"}} + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "mirror"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "mirror", "len": 65536, "offset": 65536, "speed": 0, "type": "mirror"}} + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "mirror"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "mirror"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "mirror", "len": 65536, "offset": 65536, "speed": 0, "type": "mirror"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "mirror"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "mirror"}} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} + *** done +diff --git a/tests/qemu-iotests/141 b/tests/qemu-iotests/141 +index 2f9d7b9..4246d38 100755 +--- a/tests/qemu-iotests/141 ++++ b/tests/qemu-iotests/141 +@@ -107,7 +107,7 @@ test_blockjob \ + 'format': '$IMGFMT', + 'sync': 'none'}}" \ + 'return' \ +- 'BLOCK_JOB_CANCELLED' ++ '"status": "null"' + + echo + echo '=== Testing drive-mirror ===' +@@ -124,7 +124,7 @@ test_blockjob \ + 'format': '$IMGFMT', + 'sync': 'none'}}" \ + 'BLOCK_JOB_READY' \ +- 'BLOCK_JOB_COMPLETED' ++ '"status": "null"' + + echo + echo '=== Testing active block-commit ===' +@@ -138,7 +138,7 @@ test_blockjob \ + "{'execute': 'block-commit', + 'arguments': {'job-id': 'job0', 'device': 'drv0'}}" \ + 'BLOCK_JOB_READY' \ +- 'BLOCK_JOB_COMPLETED' ++ '"status": "null"' + + echo + echo '=== Testing non-active block-commit ===' +@@ -157,7 +157,7 @@ test_blockjob \ + 'top': '$TEST_DIR/m.$IMGFMT', + 'speed': 1}}" \ + 'return' \ +- 'BLOCK_JOB_CANCELLED' ++ '"status": "null"' + + echo + echo '=== Testing block-stream ===' +@@ -170,8 +170,7 @@ echo + $QEMU_IO -c 'write 0 1M' "$TEST_DIR/b.$IMGFMT" | _filter_qemu_io + + # With some data to stream (and @speed set to 1), block-stream will not complete +-# until we send the block-job-cancel command. Therefore, no event other than +-# BLOCK_JOB_CANCELLED will be emitted. ++# until we send the block-job-cancel command. + + test_blockjob \ + "{'execute': 'block-stream', +@@ -179,7 +178,7 @@ test_blockjob \ + 'device': 'drv0', + 'speed': 1}}" \ + 'return' \ +- 'BLOCK_JOB_CANCELLED' ++ '"status": "null"' + + _cleanup_qemu + +diff --git a/tests/qemu-iotests/141.out b/tests/qemu-iotests/141.out +index 82e763b..f252c86 100644 +--- a/tests/qemu-iotests/141.out ++++ b/tests/qemu-iotests/141.out +@@ -8,31 +8,50 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/m. + + {"return": {}} + Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}} + {"return": {}} + {"error": {"class": "GenericError", "desc": "Node drv0 is in use"}} + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "job0"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "job0", "len": 1048576, "offset": 0, "speed": 0, "type": "backup"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job0"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}} + {"return": {}} + + === Testing drive-mirror === + + {"return": {}} + Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job0"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}} + {"return": {}} + {"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: node is used as backing hd of 'NODE_NAME'"}} + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job0"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job0"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job0"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}} + {"return": {}} + + === Testing active block-commit === + + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job0"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}} + {"return": {}} + {"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: node is used as backing hd of 'NODE_NAME'"}} + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job0"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job0"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job0"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}} + {"return": {}} + + === Testing non-active block-commit === +@@ -40,10 +59,15 @@ Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t. + wrote 1048576/1048576 bytes at offset 0 + 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}} + {"return": {}} + {"error": {"class": "GenericError", "desc": "Node drv0 is in use"}} + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "job0"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "job0", "len": 1048576, "offset": 524288, "speed": 1, "type": "commit"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job0"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}} + {"return": {}} + + === Testing block-stream === +@@ -51,9 +75,14 @@ wrote 1048576/1048576 bytes at offset 0 + wrote 1048576/1048576 bytes at offset 0 + 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}} + {"return": {}} + {"error": {"class": "GenericError", "desc": "Node drv0 is in use"}} + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "job0"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "job0", "len": 1048576, "offset": 524288, "speed": 1, "type": "stream"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job0"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}} + {"return": {}} + *** done +diff --git a/tests/qemu-iotests/144 b/tests/qemu-iotests/144 +index 00de3c33..4b91571 100755 +--- a/tests/qemu-iotests/144 ++++ b/tests/qemu-iotests/144 +@@ -93,7 +93,7 @@ _send_qemu_cmd $h "{ 'execute': 'block-job-complete', + 'arguments': { + 'device': 'virtio0' + } +- }" "COMPLETED" ++ }" '"status": "null"' + + echo + echo === Performing Live Snapshot 2 === +diff --git a/tests/qemu-iotests/144.out b/tests/qemu-iotests/144.out +index 014b281..5529920 100644 +--- a/tests/qemu-iotests/144.out ++++ b/tests/qemu-iotests/144.out +@@ -12,10 +12,17 @@ Formatting 'TEST_DIR/tmp.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/ + + === Performing block-commit on active layer === + ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "virtio0"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "virtio0"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "virtio0"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "virtio0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}} + {"return": {}} + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "virtio0"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "virtio0"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "virtio0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "virtio0"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "virtio0"}} + + === Performing Live Snapshot 2 === + +diff --git a/tests/qemu-iotests/156 b/tests/qemu-iotests/156 +index e75dc4d..0a9a098 100755 +--- a/tests/qemu-iotests/156 ++++ b/tests/qemu-iotests/156 +@@ -119,7 +119,7 @@ _send_qemu_cmd $QEMU_HANDLE \ + + _send_qemu_cmd $QEMU_HANDLE \ + '' \ +- 'BLOCK_JOB_COMPLETED' ++ '"status": "null"' + + # Remove the source images + rm -f "$TEST_IMG{,.backing,.overlay}" +diff --git a/tests/qemu-iotests/156.out b/tests/qemu-iotests/156.out +index f96a564..34c057b 100644 +--- a/tests/qemu-iotests/156.out ++++ b/tests/qemu-iotests/156.out +@@ -12,13 +12,20 @@ wrote 131072/131072 bytes at offset 131072 + 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + {"return": ""} + Formatting 'TEST_DIR/t.IMGFMT.target.overlay', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.target ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "source"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "source"}} + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "source"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "source", "len": 131072, "offset": 131072, "speed": 0, "type": "mirror"}} + wrote 65536/65536 bytes at offset 196608 + 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + {"return": ""} + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "source"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "source"}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "source", "len": 196608, "offset": 196608, "speed": 0, "type": "mirror"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "source"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "source"}} + + read 65536/65536 bytes at offset 0 + 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +diff --git a/tests/qemu-iotests/185 b/tests/qemu-iotests/185 +index 9a2d317..567ba67 100755 +--- a/tests/qemu-iotests/185 ++++ b/tests/qemu-iotests/185 +@@ -118,8 +118,10 @@ _send_qemu_cmd $h \ + # If we don't sleep here 'quit' command races with disk I/O + sleep 0.5 + ++# Ignore the JOB_STATUS_CHANGE events while shutting down the VM. Depending on ++# the timing, jobs may or may not transition through a paused state. + _send_qemu_cmd $h "{ 'execute': 'quit' }" "return" +-wait=1 _cleanup_qemu ++wait=1 _cleanup_qemu | grep -v 'JOB_STATUS_CHANGE' + + echo + echo === Start active commit job and exit qemu === +@@ -141,7 +143,7 @@ _send_qemu_cmd $h \ + sleep 0.5 + + _send_qemu_cmd $h "{ 'execute': 'quit' }" "return" +-wait=1 _cleanup_qemu ++wait=1 _cleanup_qemu | grep -v 'JOB_STATUS_CHANGE' + + echo + echo === Start mirror job and exit qemu === +@@ -166,7 +168,7 @@ _send_qemu_cmd $h \ + sleep 0.5 + + _send_qemu_cmd $h "{ 'execute': 'quit' }" "return" +-wait=1 _cleanup_qemu ++wait=1 _cleanup_qemu | grep -v 'JOB_STATUS_CHANGE' + + echo + echo === Start backup job and exit qemu === +@@ -190,7 +192,7 @@ _send_qemu_cmd $h \ + sleep 0.5 + + _send_qemu_cmd $h "{ 'execute': 'quit' }" "return" +-wait=1 _cleanup_qemu ++wait=1 _cleanup_qemu | grep -v 'JOB_STATUS_CHANGE' + + echo + echo === Start streaming job and exit qemu === +@@ -211,7 +213,7 @@ _send_qemu_cmd $h \ + sleep 0.5 + + _send_qemu_cmd $h "{ 'execute': 'quit' }" "return" +-wait=1 _cleanup_qemu ++wait=1 _cleanup_qemu | grep -v 'JOB_STATUS_CHANGE' + + _check_test_img + +diff --git a/tests/qemu-iotests/185.out b/tests/qemu-iotests/185.out +index 57eaf8d..4e0ca0d 100644 +--- a/tests/qemu-iotests/185.out ++++ b/tests/qemu-iotests/185.out +@@ -17,6 +17,8 @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.q + + === Start commit job and exit qemu === + ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}} + {"return": {}} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} +@@ -25,6 +27,8 @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.q + === Start active commit job and exit qemu === + + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}} + {"return": {}} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} +@@ -34,6 +38,8 @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.q + + {"return": {}} + Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}} + {"return": {}} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} +@@ -43,6 +49,8 @@ Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 l + + {"return": {}} + Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}} + {"return": {}} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} +@@ -51,6 +59,8 @@ Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 l + === Start streaming job and exit qemu === + + {"return": {}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "disk"}} ++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}} + {"return": {}} + {"return": {}} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} +diff --git a/tests/qemu-iotests/191 b/tests/qemu-iotests/191 +index dfad655..b3629ff 100755 +--- a/tests/qemu-iotests/191 ++++ b/tests/qemu-iotests/191 +@@ -83,7 +83,7 @@ _send_qemu_cmd $h \ + 'device': 'top', + 'base':'$TEST_IMG.base', + 'top': '$TEST_IMG.mid' } }" \ +- "BLOCK_JOB_COMPLETED" ++ '"status": "null"' + _send_qemu_cmd $h "" "^}" + + echo +@@ -131,7 +131,7 @@ _send_qemu_cmd $h \ + 'device': 'top', + 'base':'$TEST_IMG.base', + 'top': '$TEST_IMG.mid' } }" \ +- "BLOCK_JOB_COMPLETED" ++ '"status": "null"' + _send_qemu_cmd $h "" "^}" + + echo +diff --git a/tests/qemu-iotests/191.out b/tests/qemu-iotests/191.out +index 190c5f0..31a0c7d 100644 +--- a/tests/qemu-iotests/191.out ++++ b/tests/qemu-iotests/191.out +@@ -16,6 +16,28 @@ wrote 65536/65536 bytes at offset 1048576 + === Perform commit job === + + { ++ "timestamp": { ++ "seconds": TIMESTAMP, ++ "microseconds": TIMESTAMP ++ }, ++ "event": "JOB_STATUS_CHANGE", ++ "data": { ++ "status": "created", ++ "id": "commit0" ++ } ++} ++{ ++ "timestamp": { ++ "seconds": TIMESTAMP, ++ "microseconds": TIMESTAMP ++ }, ++ "event": "JOB_STATUS_CHANGE", ++ "data": { ++ "status": "running", ++ "id": "commit0" ++ } ++} ++{ + "return": { + } + } +@@ -24,6 +46,28 @@ wrote 65536/65536 bytes at offset 1048576 + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP + }, ++ "event": "JOB_STATUS_CHANGE", ++ "data": { ++ "status": "waiting", ++ "id": "commit0" ++ } ++} ++{ ++ "timestamp": { ++ "seconds": TIMESTAMP, ++ "microseconds": TIMESTAMP ++ }, ++ "event": "JOB_STATUS_CHANGE", ++ "data": { ++ "status": "pending", ++ "id": "commit0" ++ } ++} ++{ ++ "timestamp": { ++ "seconds": TIMESTAMP, ++ "microseconds": TIMESTAMP ++ }, + "event": "BLOCK_JOB_COMPLETED", + "data": { + "device": "commit0", +@@ -33,6 +77,28 @@ wrote 65536/65536 bytes at offset 1048576 + "type": "commit" + } + } ++{ ++ "timestamp": { ++ "seconds": TIMESTAMP, ++ "microseconds": TIMESTAMP ++ }, ++ "event": "JOB_STATUS_CHANGE", ++ "data": { ++ "status": "concluded", ++ "id": "commit0" ++ } ++} ++{ ++ "timestamp": { ++ "seconds": TIMESTAMP, ++ "microseconds": TIMESTAMP ++ }, ++ "event": "JOB_STATUS_CHANGE", ++ "data": { ++ "status": "null", ++ "id": "commit0" ++ } ++} + + === Check that both top and top2 point to base now === + +@@ -356,6 +422,28 @@ wrote 65536/65536 bytes at offset 1048576 + === Perform commit job === + + { ++ "timestamp": { ++ "seconds": TIMESTAMP, ++ "microseconds": TIMESTAMP ++ }, ++ "event": "JOB_STATUS_CHANGE", ++ "data": { ++ "status": "created", ++ "id": "commit0" ++ } ++} ++{ ++ "timestamp": { ++ "seconds": TIMESTAMP, ++ "microseconds": TIMESTAMP ++ }, ++ "event": "JOB_STATUS_CHANGE", ++ "data": { ++ "status": "running", ++ "id": "commit0" ++ } ++} ++{ + "return": { + } + } +@@ -364,6 +452,28 @@ wrote 65536/65536 bytes at offset 1048576 + "seconds": TIMESTAMP, + "microseconds": TIMESTAMP + }, ++ "event": "JOB_STATUS_CHANGE", ++ "data": { ++ "status": "waiting", ++ "id": "commit0" ++ } ++} ++{ ++ "timestamp": { ++ "seconds": TIMESTAMP, ++ "microseconds": TIMESTAMP ++ }, ++ "event": "JOB_STATUS_CHANGE", ++ "data": { ++ "status": "pending", ++ "id": "commit0" ++ } ++} ++{ ++ "timestamp": { ++ "seconds": TIMESTAMP, ++ "microseconds": TIMESTAMP ++ }, + "event": "BLOCK_JOB_COMPLETED", + "data": { + "device": "commit0", +@@ -373,6 +483,28 @@ wrote 65536/65536 bytes at offset 1048576 + "type": "commit" + } + } ++{ ++ "timestamp": { ++ "seconds": TIMESTAMP, ++ "microseconds": TIMESTAMP ++ }, ++ "event": "JOB_STATUS_CHANGE", ++ "data": { ++ "status": "concluded", ++ "id": "commit0" ++ } ++} ++{ ++ "timestamp": { ++ "seconds": TIMESTAMP, ++ "microseconds": TIMESTAMP ++ }, ++ "event": "JOB_STATUS_CHANGE", ++ "data": { ++ "status": "null", ++ "id": "commit0" ++ } ++} + + === Check that both top and top2 point to base now === + +diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py +index 9747ca9..3dab1bf 100644 +--- a/tests/qemu-iotests/iotests.py ++++ b/tests/qemu-iotests/iotests.py +@@ -473,6 +473,9 @@ class QMPTestCase(unittest.TestCase): + self.assert_qmp(event, 'data/device', drive) + result = event + cancelled = True ++ elif event['event'] == 'JOB_STATUS_CHANGE': ++ self.assert_qmp(event, 'data/id', drive) ++ + + self.assert_no_active_block_jobs() + return result +@@ -488,6 +491,8 @@ class QMPTestCase(unittest.TestCase): + self.assert_qmp(event, 'data/offset', event['data']['len']) + self.assert_no_active_block_jobs() + return event ++ elif event['event'] == 'JOB_STATUS_CHANGE': ++ self.assert_qmp(event, 'data/id', drive) + + def wait_ready(self, drive='drive0'): + '''Wait until a block job BLOCK_JOB_READY event''' +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Add-Job.aio_context.patch b/SOURCES/kvm-job-Add-Job.aio_context.patch new file mode 100644 index 0000000..6f2d9be --- /dev/null +++ b/SOURCES/kvm-job-Add-Job.aio_context.patch @@ -0,0 +1,112 @@ +From 25511b69b93fae007b86ccf1410585e6288c2b78 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:07 +0200 +Subject: [PATCH 38/89] job: Add Job.aio_context + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-25-kwolf@redhat.com> +Patchwork-id: 81075 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 24/73] job: Add Job.aio_context +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +When block jobs need an AioContext, they just take it from their main +block node. Generic jobs don't have a main block node, so we need to +assign them an AioContext explicitly. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +Reviewed-by: John Snow +(cherry picked from commit 08be6fe26f6c76d900fc987f58d322b94bc4e248) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + blockjob.c | 5 ++++- + include/qemu/job.h | 7 ++++++- + job.c | 4 +++- + 3 files changed, 13 insertions(+), 3 deletions(-) + +diff --git a/blockjob.c b/blockjob.c +index f4f9956..0a0b1c4 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -216,6 +216,7 @@ static void block_job_attached_aio_context(AioContext *new_context, + { + BlockJob *job = opaque; + ++ job->job.aio_context = new_context; + if (job->driver->attached_aio_context) { + job->driver->attached_aio_context(job, new_context); + } +@@ -247,6 +248,7 @@ static void block_job_detach_aio_context(void *opaque) + block_job_drain(job); + } + ++ job->job.aio_context = NULL; + job_unref(&job->job); + } + +@@ -899,7 +901,8 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + return NULL; + } + +- job = job_create(job_id, &driver->job_driver, errp); ++ job = job_create(job_id, &driver->job_driver, blk_get_aio_context(blk), ++ errp); + if (job == NULL) { + blk_unref(blk); + return NULL; +diff --git a/include/qemu/job.h b/include/qemu/job.h +index 5dfbec5..01e083f 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -47,6 +47,9 @@ typedef struct Job { + /** Current state; See @JobStatus for details. */ + JobStatus status; + ++ /** AioContext to run the job coroutine in */ ++ AioContext *aio_context; ++ + /** + * Set to true if the job should cancel itself. The flag must + * always be tested just before toggling the busy flag from false +@@ -79,9 +82,11 @@ struct JobDriver { + * + * @job_id: The id of the newly-created job, or %NULL for internal jobs + * @driver: The class object for the newly-created job. ++ * @ctx: The AioContext to run the job coroutine in. + * @errp: Error object. + */ +-void *job_create(const char *job_id, const JobDriver *driver, Error **errp); ++void *job_create(const char *job_id, const JobDriver *driver, AioContext *ctx, ++ Error **errp); + + /** + * Add a reference to Job refcnt, it will be decreased with job_unref, and then +diff --git a/job.c b/job.c +index 1abca6a..01074d0 100644 +--- a/job.c ++++ b/job.c +@@ -121,7 +121,8 @@ Job *job_get(const char *id) + return NULL; + } + +-void *job_create(const char *job_id, const JobDriver *driver, Error **errp) ++void *job_create(const char *job_id, const JobDriver *driver, AioContext *ctx, ++ Error **errp) + { + Job *job; + +@@ -140,6 +141,7 @@ void *job_create(const char *job_id, const JobDriver *driver, Error **errp) + job->driver = driver; + job->id = g_strdup(job_id); + job->refcnt = 1; ++ job->aio_context = ctx; + + job_state_transition(job, JOB_STATUS_CREATED); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Add-JobDriver.job_type.patch b/SOURCES/kvm-job-Add-JobDriver.job_type.patch new file mode 100644 index 0000000..9c376f9 --- /dev/null +++ b/SOURCES/kvm-job-Add-JobDriver.job_type.patch @@ -0,0 +1,240 @@ +From afe531712d6465c1a850a8538c1756dbad10135a Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:01 +0200 +Subject: [PATCH 32/89] job: Add JobDriver.job_type + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-19-kwolf@redhat.com> +Patchwork-id: 81063 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 18/73] job: Add JobDriver.job_type +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This moves the job_type field from BlockJobDriver to JobDriver. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +Reviewed-by: John Snow +(cherry picked from commit 252291eaeafcd234a602d71cdf9415dbfc7bc867) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/backup.c | 2 +- + block/commit.c | 2 +- + block/mirror.c | 4 ++-- + block/stream.c | 2 +- + blockjob.c | 16 +++++++--------- + include/block/blockjob_int.h | 3 --- + include/qemu/job.h | 11 +++++++++++ + job.c | 10 ++++++++++ + 8 files changed, 33 insertions(+), 17 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index c49ea92..baf8d43 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -525,8 +525,8 @@ static void coroutine_fn backup_run(void *opaque) + static const BlockJobDriver backup_job_driver = { + .job_driver = { + .instance_size = sizeof(BackupBlockJob), ++ .job_type = JOB_TYPE_BACKUP, + }, +- .job_type = JOB_TYPE_BACKUP, + .start = backup_run, + .commit = backup_commit, + .abort = backup_abort, +diff --git a/block/commit.c b/block/commit.c +index afa2b2b..32d29c8 100644 +--- a/block/commit.c ++++ b/block/commit.c +@@ -217,8 +217,8 @@ out: + static const BlockJobDriver commit_job_driver = { + .job_driver = { + .instance_size = sizeof(CommitBlockJob), ++ .job_type = JOB_TYPE_COMMIT, + }, +- .job_type = JOB_TYPE_COMMIT, + .start = commit_run, + }; + +diff --git a/block/mirror.c b/block/mirror.c +index ed72656..35fcc1f 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -988,8 +988,8 @@ static void mirror_drain(BlockJob *job) + static const BlockJobDriver mirror_job_driver = { + .job_driver = { + .instance_size = sizeof(MirrorBlockJob), ++ .job_type = JOB_TYPE_MIRROR, + }, +- .job_type = JOB_TYPE_MIRROR, + .start = mirror_run, + .complete = mirror_complete, + .pause = mirror_pause, +@@ -1000,8 +1000,8 @@ static const BlockJobDriver mirror_job_driver = { + static const BlockJobDriver commit_active_job_driver = { + .job_driver = { + .instance_size = sizeof(MirrorBlockJob), ++ .job_type = JOB_TYPE_COMMIT, + }, +- .job_type = JOB_TYPE_COMMIT, + .start = mirror_run, + .complete = mirror_complete, + .pause = mirror_pause, +diff --git a/block/stream.c b/block/stream.c +index 048bceb..cb723f1 100644 +--- a/block/stream.c ++++ b/block/stream.c +@@ -211,8 +211,8 @@ out: + static const BlockJobDriver stream_job_driver = { + .job_driver = { + .instance_size = sizeof(StreamBlockJob), ++ .job_type = JOB_TYPE_STREAM, + }, +- .job_type = JOB_TYPE_STREAM, + .start = stream_run, + }; + +diff --git a/blockjob.c b/blockjob.c +index 2a38447..ea71ec0 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -309,9 +309,7 @@ static void block_job_detach_aio_context(void *opaque) + static char *child_job_get_parent_desc(BdrvChild *c) + { + BlockJob *job = c->opaque; +- return g_strdup_printf("%s job '%s'", +- JobType_str(job->driver->job_type), +- job->job.id); ++ return g_strdup_printf("%s job '%s'", job_type_str(&job->job), job->job.id); + } + + static void child_job_drained_begin(BdrvChild *c) +@@ -847,7 +845,7 @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp) + return NULL; + } + info = g_new0(BlockJobInfo, 1); +- info->type = g_strdup(JobType_str(job->driver->job_type)); ++ info->type = g_strdup(job_type_str(&job->job)); + info->device = g_strdup(job->job.id); + info->len = job->len; + info->busy = atomic_read(&job->busy); +@@ -878,7 +876,7 @@ static void block_job_event_cancelled(BlockJob *job) + return; + } + +- qapi_event_send_block_job_cancelled(job->driver->job_type, ++ qapi_event_send_block_job_cancelled(job_type(&job->job), + job->job.id, + job->len, + job->offset, +@@ -892,7 +890,7 @@ static void block_job_event_completed(BlockJob *job, const char *msg) + return; + } + +- qapi_event_send_block_job_completed(job->driver->job_type, ++ qapi_event_send_block_job_completed(job_type(&job->job), + job->job.id, + job->len, + job->offset, +@@ -906,7 +904,7 @@ static int block_job_event_pending(BlockJob *job) + { + block_job_state_transition(job, BLOCK_JOB_STATUS_PENDING); + if (!job->auto_finalize && !block_job_is_internal(job)) { +- qapi_event_send_block_job_pending(job->driver->job_type, ++ qapi_event_send_block_job_pending(job_type(&job->job), + job->job.id, + &error_abort); + } +@@ -980,7 +978,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + block_job_sleep_timer_cb, job); + + error_setg(&job->blocker, "block device is in use by block job: %s", +- JobType_str(driver->job_type)); ++ job_type_str(&job->job)); + block_job_add_bdrv(job, "main node", bs, 0, BLK_PERM_ALL, &error_abort); + bs->job = job; + +@@ -1184,7 +1182,7 @@ void block_job_event_ready(BlockJob *job) + return; + } + +- qapi_event_send_block_job_ready(job->driver->job_type, ++ qapi_event_send_block_job_ready(job_type(&job->job), + job->job.id, + job->len, + job->offset, +diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h +index 8e7e0a2..1e62d6d 100644 +--- a/include/block/blockjob_int.h ++++ b/include/block/blockjob_int.h +@@ -38,9 +38,6 @@ struct BlockJobDriver { + /** Generic JobDriver callbacks and settings */ + JobDriver job_driver; + +- /** String describing the operation, part of query-block-jobs QMP API */ +- JobType job_type; +- + /** Mandatory: Entrypoint for the Coroutine. */ + CoroutineEntry *start; + +diff --git a/include/qemu/job.h b/include/qemu/job.h +index b4b49f1..279ce68 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -26,6 +26,8 @@ + #ifndef JOB_H + #define JOB_H + ++#include "qapi/qapi-types-block-core.h" ++ + typedef struct JobDriver JobDriver; + + /** +@@ -45,6 +47,9 @@ typedef struct Job { + struct JobDriver { + /** Derived Job struct size */ + size_t instance_size; ++ ++ /** Enum describing the operation */ ++ JobType job_type; + }; + + +@@ -57,4 +62,10 @@ struct JobDriver { + */ + void *job_create(const char *job_id, const JobDriver *driver, Error **errp); + ++/** Returns the JobType of a given Job. */ ++JobType job_type(const Job *job); ++ ++/** Returns the enum string for the JobType of a given Job. */ ++const char *job_type_str(const Job *job); ++ + #endif +diff --git a/job.c b/job.c +index 87fd484..83724a4 100644 +--- a/job.c ++++ b/job.c +@@ -29,6 +29,16 @@ + #include "qemu/job.h" + #include "qemu/id.h" + ++JobType job_type(const Job *job) ++{ ++ return job->driver->job_type; ++} ++ ++const char *job_type_str(const Job *job) ++{ ++ return JobType_str(job_type(job)); ++} ++ + void *job_create(const char *job_id, const JobDriver *driver, Error **errp) + { + Job *job; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Add-error-message-for-failing-jobs.patch b/SOURCES/kvm-job-Add-error-message-for-failing-jobs.patch new file mode 100644 index 0000000..ebca08b --- /dev/null +++ b/SOURCES/kvm-job-Add-error-message-for-failing-jobs.patch @@ -0,0 +1,257 @@ +From 864c5b5a3146aac264065f9ef5cf397451747440 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:39 +0200 +Subject: [PATCH 70/89] job: Add error message for failing jobs + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-57-kwolf@redhat.com> +Patchwork-id: 81110 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 56/73] job: Add error message for failing jobs +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +So far we relied on job->ret and strerror() to produce an error message +for failed jobs. Not surprisingly, this tends to result in completely +useless messages. + +This adds a Job.error field that can contain an error string for a +failing job, and a parameter to job_completed() that sets the field. As +a default, if NULL is passed, we continue to use strerror(job->ret). + +All existing callers are changed to pass NULL. They can be improved in +separate patches. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +Reviewed-by: Jeff Cody +(cherry picked from commit 1266c9b9f5fa05877b979eece5963a2bd99c3bfd) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/backup.c | 2 +- + block/commit.c | 2 +- + block/mirror.c | 2 +- + block/stream.c | 2 +- + include/qemu/job.h | 7 ++++++- + job-qmp.c | 9 ++------- + job.c | 16 ++++++++++++++-- + tests/test-bdrv-drain.c | 2 +- + tests/test-blockjob-txn.c | 2 +- + tests/test-blockjob.c | 2 +- + 10 files changed, 29 insertions(+), 17 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index 4e228e9..5661435 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -321,7 +321,7 @@ static void backup_complete(Job *job, void *opaque) + { + BackupCompleteData *data = opaque; + +- job_completed(job, data->ret); ++ job_completed(job, data->ret, NULL); + g_free(data); + } + +diff --git a/block/commit.c b/block/commit.c +index 6206661..e1814d9 100644 +--- a/block/commit.c ++++ b/block/commit.c +@@ -117,7 +117,7 @@ static void commit_complete(Job *job, void *opaque) + * bdrv_set_backing_hd() to fail. */ + block_job_remove_all_bdrv(bjob); + +- job_completed(job, ret); ++ job_completed(job, ret, NULL); + g_free(data); + + /* If bdrv_drop_intermediate() didn't already do that, remove the commit +diff --git a/block/mirror.c b/block/mirror.c +index dcb66ec..435268b 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -581,7 +581,7 @@ static void mirror_exit(Job *job, void *opaque) + blk_set_perm(bjob->blk, 0, BLK_PERM_ALL, &error_abort); + blk_insert_bs(bjob->blk, mirror_top_bs, &error_abort); + +- job_completed(job, data->ret); ++ job_completed(job, data->ret, NULL); + + g_free(data); + bdrv_drained_end(src); +diff --git a/block/stream.c b/block/stream.c +index a5d6e0c..9264b68 100644 +--- a/block/stream.c ++++ b/block/stream.c +@@ -93,7 +93,7 @@ out: + } + + g_free(s->backing_file_str); +- job_completed(job, data->ret); ++ job_completed(job, data->ret, NULL); + g_free(data); + } + +diff --git a/include/qemu/job.h b/include/qemu/job.h +index 8c8badf..1d82053 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -124,6 +124,9 @@ typedef struct Job { + /** Estimated progress_current value at the completion of the job */ + int64_t progress_total; + ++ /** Error string for a failed job (NULL if, and only if, job->ret == 0) */ ++ char *error; ++ + /** ret code passed to job_completed. */ + int ret; + +@@ -466,13 +469,15 @@ void job_transition_to_ready(Job *job); + /** + * @job: The job being completed. + * @ret: The status code. ++ * @error: The error message for a failing job (only with @ret < 0). If @ret is ++ * negative, but NULL is given for @error, strerror() is used. + * + * Marks @job as completed. If @ret is non-zero, the job transaction it is part + * of is aborted. If @ret is zero, the job moves into the WAITING state. If it + * is the last job to complete in its transaction, all jobs in the transaction + * move from WAITING to PENDING. + */ +-void job_completed(Job *job, int ret); ++void job_completed(Job *job, int ret, Error *error); + + /** Asynchronously complete the specified @job. */ + void job_complete(Job *job, Error **errp); +diff --git a/job-qmp.c b/job-qmp.c +index 7f38f63..410775d 100644 +--- a/job-qmp.c ++++ b/job-qmp.c +@@ -136,14 +136,9 @@ void qmp_job_dismiss(const char *id, Error **errp) + static JobInfo *job_query_single(Job *job, Error **errp) + { + JobInfo *info; +- const char *errmsg = NULL; + + assert(!job_is_internal(job)); + +- if (job->ret < 0) { +- errmsg = strerror(-job->ret); +- } +- + info = g_new(JobInfo, 1); + *info = (JobInfo) { + .id = g_strdup(job->id), +@@ -151,8 +146,8 @@ static JobInfo *job_query_single(Job *job, Error **errp) + .status = job->status, + .current_progress = job->progress_current, + .total_progress = job->progress_total, +- .has_error = !!errmsg, +- .error = g_strdup(errmsg), ++ .has_error = !!job->error, ++ .error = g_strdup(job->error), + }; + + return info; +diff --git a/job.c b/job.c +index f026661..84e1402 100644 +--- a/job.c ++++ b/job.c +@@ -369,6 +369,7 @@ void job_unref(Job *job) + + QLIST_REMOVE(job, job_list); + ++ g_free(job->error); + g_free(job->id); + g_free(job); + } +@@ -660,6 +661,9 @@ static void job_update_rc(Job *job) + job->ret = -ECANCELED; + } + if (job->ret) { ++ if (!job->error) { ++ job->error = g_strdup(strerror(-job->ret)); ++ } + job_state_transition(job, JOB_STATUS_ABORTING); + } + } +@@ -782,6 +786,7 @@ static int job_prepare(Job *job) + { + if (job->ret == 0 && job->driver->prepare) { + job->ret = job->driver->prepare(job); ++ job_update_rc(job); + } + return job->ret; + } +@@ -855,10 +860,17 @@ static void job_completed_txn_success(Job *job) + } + } + +-void job_completed(Job *job, int ret) ++void job_completed(Job *job, int ret, Error *error) + { + assert(job && job->txn && !job_is_completed(job)); ++ + job->ret = ret; ++ if (error) { ++ assert(job->ret < 0); ++ job->error = g_strdup(error_get_pretty(error)); ++ error_free(error); ++ } ++ + job_update_rc(job); + trace_job_completed(job, ret, job->ret); + if (job->ret) { +@@ -876,7 +888,7 @@ void job_cancel(Job *job, bool force) + } + job_cancel_async(job, force); + if (!job_started(job)) { +- job_completed(job, -ECANCELED); ++ job_completed(job, -ECANCELED, NULL); + } else if (job->deferred_to_main_loop) { + job_completed_txn_abort(job); + } else { +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index 2cba63b..a11c4cf 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -498,7 +498,7 @@ typedef struct TestBlockJob { + + static void test_job_completed(Job *job, void *opaque) + { +- job_completed(job, 0); ++ job_completed(job, 0, NULL); + } + + static void coroutine_fn test_job_start(void *opaque) +diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c +index fce8366..58d9b87 100644 +--- a/tests/test-blockjob-txn.c ++++ b/tests/test-blockjob-txn.c +@@ -34,7 +34,7 @@ static void test_block_job_complete(Job *job, void *opaque) + rc = -ECANCELED; + } + +- job_completed(job, rc); ++ job_completed(job, rc, NULL); + bdrv_unref(bs); + } + +diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c +index e408d52..cb42f06 100644 +--- a/tests/test-blockjob.c ++++ b/tests/test-blockjob.c +@@ -167,7 +167,7 @@ static void cancel_job_completed(Job *job, void *opaque) + { + CancelJob *s = opaque; + s->completed = true; +- job_completed(job, 0); ++ job_completed(job, 0, NULL); + } + + static void cancel_job_complete(Job *job, Error **errp) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Add-job_delete.patch b/SOURCES/kvm-job-Add-job_delete.patch new file mode 100644 index 0000000..bbc4a98 --- /dev/null +++ b/SOURCES/kvm-job-Add-job_delete.patch @@ -0,0 +1,75 @@ +From 6828f21b1fda85e52bbbe92b4a37f1fde5de5ff0 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:02 +0200 +Subject: [PATCH 33/89] job: Add job_delete() + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-20-kwolf@redhat.com> +Patchwork-id: 81065 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 19/73] job: Add job_delete() +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This moves freeing the Job object and its fields from block_job_unref() +to job_delete(). + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +Reviewed-by: John Snow +(cherry picked from commit fd61a701f1de8e4c1d89b3716ba9ca749cf5c724) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + blockjob.c | 3 +-- + include/qemu/job.h | 3 +++ + job.c | 6 ++++++ + 3 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/blockjob.c b/blockjob.c +index ea71ec0..430a67b 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -261,9 +261,8 @@ void block_job_unref(BlockJob *job) + block_job_detach_aio_context, job); + blk_unref(job->blk); + error_free(job->blocker); +- g_free(job->job.id); + assert(!timer_pending(&job->sleep_timer)); +- g_free(job); ++ job_delete(&job->job); + } + } + +diff --git a/include/qemu/job.h b/include/qemu/job.h +index 279ce68..43dc2e4 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -62,6 +62,9 @@ struct JobDriver { + */ + void *job_create(const char *job_id, const JobDriver *driver, Error **errp); + ++/** Frees the @job object. */ ++void job_delete(Job *job); ++ + /** Returns the JobType of a given Job. */ + JobType job_type(const Job *job); + +diff --git a/job.c b/job.c +index 83724a4..cfdd008 100644 +--- a/job.c ++++ b/job.c +@@ -56,3 +56,9 @@ void *job_create(const char *job_id, const JobDriver *driver, Error **errp) + + return job; + } ++ ++void job_delete(Job *job) ++{ ++ g_free(job->id); ++ g_free(job); ++} +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Add-job_dismiss.patch b/SOURCES/kvm-job-Add-job_dismiss.patch new file mode 100644 index 0000000..65d8035 --- /dev/null +++ b/SOURCES/kvm-job-Add-job_dismiss.patch @@ -0,0 +1,174 @@ +From ba27464d8206fba129745e7b7eb38d59ef05fd5c Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:26 +0200 +Subject: [PATCH 57/89] job: Add job_dismiss() + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-44-kwolf@redhat.com> +Patchwork-id: 81125 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 43/73] job: Add job_dismiss() +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This moves block_job_dismiss() to the Job layer. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +(cherry picked from commit 5f9a6a08e8f65e01746d2485fc65a3a78e74865f) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + blockdev.c | 10 ++++++---- + blockjob.c | 13 ------------- + include/block/blockjob.h | 9 --------- + include/qemu/job.h | 7 ++++++- + job.c | 15 ++++++++++++++- + tests/test-blockjob.c | 4 ++-- + 6 files changed, 28 insertions(+), 30 deletions(-) + +diff --git a/blockdev.c b/blockdev.c +index d6cd8ed..d8b6520 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -3962,14 +3962,16 @@ void qmp_block_job_finalize(const char *id, Error **errp) + void qmp_block_job_dismiss(const char *id, Error **errp) + { + AioContext *aio_context; +- BlockJob *job = find_block_job(id, &aio_context, errp); ++ BlockJob *bjob = find_block_job(id, &aio_context, errp); ++ Job *job; + +- if (!job) { ++ if (!bjob) { + return; + } + +- trace_qmp_block_job_dismiss(job); +- block_job_dismiss(&job, errp); ++ trace_qmp_block_job_dismiss(bjob); ++ job = &bjob->job; ++ job_dismiss(&job, errp); + aio_context_release(aio_context); + } + +diff --git a/blockjob.c b/blockjob.c +index f146fe0..3ca009b 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -242,19 +242,6 @@ int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n) + return ratelimit_calculate_delay(&job->limit, n); + } + +-void block_job_dismiss(BlockJob **jobptr, Error **errp) +-{ +- BlockJob *job = *jobptr; +- /* similarly to _complete, this is QMP-interface only. */ +- assert(job->job.id); +- if (job_apply_verb(&job->job, JOB_VERB_DISMISS, errp)) { +- return; +- } +- +- job_do_dismiss(&job->job); +- *jobptr = NULL; +-} +- + void block_job_progress_update(BlockJob *job, uint64_t done) + { + job->offset += done; +diff --git a/include/block/blockjob.h b/include/block/blockjob.h +index e9ed7b8..5a81afc 100644 +--- a/include/block/blockjob.h ++++ b/include/block/blockjob.h +@@ -141,15 +141,6 @@ void block_job_remove_all_bdrv(BlockJob *job); + void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp); + + /** +- * block_job_dismiss: +- * @job: The job to be dismissed. +- * @errp: Error object. +- * +- * Remove a concluded job from the query list. +- */ +-void block_job_dismiss(BlockJob **job, Error **errp); +- +-/** + * block_job_progress_update: + * @job: The job that has made progress + * @done: How much progress the job made +diff --git a/include/qemu/job.h b/include/qemu/job.h +index 94900ec..1e8050c 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -487,6 +487,12 @@ int job_complete_sync(Job *job, Error **errp); + */ + void job_finalize(Job *job, Error **errp); + ++/** ++ * Remove the concluded @job from the query list and resets the passed pointer ++ * to %NULL. Returns an error if the job is not actually concluded. ++ */ ++void job_dismiss(Job **job, Error **errp); ++ + typedef void JobDeferToMainLoopFn(Job *job, void *opaque); + + /** +@@ -515,6 +521,5 @@ int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp) + + /* TODO To be removed from the public interface */ + void job_state_transition(Job *job, JobStatus s1); +-void job_do_dismiss(Job *job); + + #endif +diff --git a/job.c b/job.c +index eede680..7cd3602 100644 +--- a/job.c ++++ b/job.c +@@ -568,7 +568,7 @@ void job_user_resume(Job *job, Error **errp) + job_resume(job); + } + +-void job_do_dismiss(Job *job) ++static void job_do_dismiss(Job *job) + { + assert(job); + job->busy = false; +@@ -581,6 +581,19 @@ void job_do_dismiss(Job *job) + job_unref(job); + } + ++void job_dismiss(Job **jobptr, Error **errp) ++{ ++ Job *job = *jobptr; ++ /* similarly to _complete, this is QMP-interface only. */ ++ assert(job->id); ++ if (job_apply_verb(job, JOB_VERB_DISMISS, errp)) { ++ return; ++ } ++ ++ job_do_dismiss(job); ++ *jobptr = NULL; ++} ++ + void job_early_fail(Job *job) + { + assert(job->status == JOB_STATUS_CREATED); +diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c +index 46a7873..7131cab 100644 +--- a/tests/test-blockjob.c ++++ b/tests/test-blockjob.c +@@ -233,8 +233,8 @@ static void cancel_common(CancelJob *s) + + job_cancel_sync(&job->job); + if (sts != JOB_STATUS_CREATED && sts != JOB_STATUS_CONCLUDED) { +- BlockJob *dummy = job; +- block_job_dismiss(&dummy, &error_abort); ++ Job *dummy = &job->job; ++ job_dismiss(&dummy, &error_abort); + } + assert(job->job.status == JOB_STATUS_NULL); + job_unref(&job->job); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Add-job_drain.patch b/SOURCES/kvm-job-Add-job_drain.patch new file mode 100644 index 0000000..386908f --- /dev/null +++ b/SOURCES/kvm-job-Add-job_drain.patch @@ -0,0 +1,281 @@ +From eb408c486b9f287df241f65b8abcb05b3c8772da Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:18 +0200 +Subject: [PATCH 49/89] job: Add job_drain() + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-36-kwolf@redhat.com> +Patchwork-id: 81119 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 35/73] job: Add job_drain() +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +block_job_drain() contains a blk_drain() call which cannot be moved to +Job, so add a new JobDriver callback JobDriver.drain which has a common +implementation for all BlockJobs. In addition to this we keep the +existing BlockJobDriver.drain callback that is called by the common +drain implementation for all block jobs. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +(cherry picked from commit b69f777dd9ba992fdd35828a90eefcd88c0ec332) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/backup.c | 1 + + block/commit.c | 1 + + block/mirror.c | 2 ++ + block/stream.c | 1 + + blockjob.c | 20 ++++++++++---------- + include/block/blockjob_int.h | 12 ++++++++++++ + include/qemu/job.h | 13 +++++++++++++ + job.c | 11 +++++++++++ + tests/test-bdrv-drain.c | 1 + + tests/test-blockjob-txn.c | 1 + + tests/test-blockjob.c | 2 ++ + 11 files changed, 55 insertions(+), 10 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index bd31282..ca7d990 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -529,6 +529,7 @@ static const BlockJobDriver backup_job_driver = { + .job_type = JOB_TYPE_BACKUP, + .free = block_job_free, + .user_resume = block_job_user_resume, ++ .drain = block_job_drain, + .start = backup_run, + .commit = backup_commit, + .abort = backup_abort, +diff --git a/block/commit.c b/block/commit.c +index e53b2d7..02a8af9 100644 +--- a/block/commit.c ++++ b/block/commit.c +@@ -221,6 +221,7 @@ static const BlockJobDriver commit_job_driver = { + .job_type = JOB_TYPE_COMMIT, + .free = block_job_free, + .user_resume = block_job_user_resume, ++ .drain = block_job_drain, + .start = commit_run, + }, + }; +diff --git a/block/mirror.c b/block/mirror.c +index c3951d1..a579bd8 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -992,6 +992,7 @@ static const BlockJobDriver mirror_job_driver = { + .job_type = JOB_TYPE_MIRROR, + .free = block_job_free, + .user_resume = block_job_user_resume, ++ .drain = block_job_drain, + .start = mirror_run, + .pause = mirror_pause, + }, +@@ -1006,6 +1007,7 @@ static const BlockJobDriver commit_active_job_driver = { + .job_type = JOB_TYPE_COMMIT, + .free = block_job_free, + .user_resume = block_job_user_resume, ++ .drain = block_job_drain, + .start = mirror_run, + .pause = mirror_pause, + }, +diff --git a/block/stream.c b/block/stream.c +index eee0253..b996278 100644 +--- a/block/stream.c ++++ b/block/stream.c +@@ -215,6 +215,7 @@ static const BlockJobDriver stream_job_driver = { + .free = block_job_free, + .start = stream_run, + .user_resume = block_job_user_resume, ++ .drain = block_job_drain, + }, + }; + +diff --git a/blockjob.c b/blockjob.c +index 4cac367..63e1669 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -169,14 +169,13 @@ static void block_job_attached_aio_context(AioContext *new_context, + job_resume(&job->job); + } + +-static void block_job_drain(BlockJob *job) ++void block_job_drain(Job *job) + { +- /* If job is !job->job.busy this kicks it into the next pause point. */ +- block_job_enter(job); ++ BlockJob *bjob = container_of(job, BlockJob, job); + +- blk_drain(job->blk); +- if (job->driver->drain) { +- job->driver->drain(job); ++ blk_drain(bjob->blk); ++ if (bjob->driver->drain) { ++ bjob->driver->drain(bjob); + } + } + +@@ -190,7 +189,7 @@ static void block_job_detach_aio_context(void *opaque) + job_pause(&job->job); + + while (!job->job.paused && !job_is_completed(&job->job)) { +- block_job_drain(job); ++ job_drain(&job->job); + } + + job->job.aio_context = NULL; +@@ -327,11 +326,11 @@ static int block_job_finish_sync(BlockJob *job, + job_unref(&job->job); + return -EBUSY; + } +- /* block_job_drain calls block_job_enter, and it should be enough to +- * induce progress until the job completes or moves to the main thread. ++ /* job_drain calls job_enter, and it should be enough to induce progress ++ * until the job completes or moves to the main thread. + */ + while (!job->job.deferred_to_main_loop && !job_is_completed(&job->job)) { +- block_job_drain(job); ++ job_drain(&job->job); + } + while (!job_is_completed(&job->job)) { + aio_poll(qemu_get_aio_context(), true); +@@ -713,6 +712,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + assert(is_block_job(&job->job)); + assert(job->job.driver->free == &block_job_free); + assert(job->job.driver->user_resume == &block_job_user_resume); ++ assert(job->job.driver->drain == &block_job_drain); + + job->driver = driver; + job->blk = blk; +diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h +index bf2b762..38fe22d 100644 +--- a/include/block/blockjob_int.h ++++ b/include/block/blockjob_int.h +@@ -65,6 +65,10 @@ struct BlockJobDriver { + * If the callback is not NULL, it will be invoked when the job has to be + * synchronously cancelled or completed; it should drain BlockDriverStates + * as required to ensure progress. ++ * ++ * Block jobs must use the default implementation for job_driver.drain, ++ * which will in turn call this callback after doing generic block job ++ * stuff. + */ + void (*drain)(BlockJob *job); + }; +@@ -112,6 +116,14 @@ void block_job_free(Job *job); + void block_job_user_resume(Job *job); + + /** ++ * block_job_drain: ++ * Callback to be used for JobDriver.drain in all block jobs. Drains the main ++ * block node associated with the block jobs and calls BlockJobDriver.drain for ++ * job-specific actions. ++ */ ++void block_job_drain(Job *job); ++ ++/** + * block_job_yield: + * @job: The job that calls the function. + * +diff --git a/include/qemu/job.h b/include/qemu/job.h +index 2648c74..aebc195 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -167,6 +167,13 @@ struct JobDriver { + */ + void (*user_resume)(Job *job); + ++ /* ++ * If the callback is not NULL, it will be invoked when the job has to be ++ * synchronously cancelled or completed; it should drain any activities ++ * as required to ensure progress. ++ */ ++ void (*drain)(Job *job); ++ + /** + * If the callback is not NULL, it will be invoked when all the jobs + * belonging to the same transaction complete; or upon this job's +@@ -325,6 +332,12 @@ bool job_user_paused(Job *job); + */ + void job_user_resume(Job *job, Error **errp); + ++/* ++ * Drain any activities as required to ensure progress. This can be called in a ++ * loop to synchronously complete a job. ++ */ ++void job_drain(Job *job); ++ + /** + * Get the next element from the list of block jobs after @job, or the + * first one if @job is %NULL. +diff --git a/job.c b/job.c +index 64b64da..3772a35 100644 +--- a/job.c ++++ b/job.c +@@ -367,6 +367,17 @@ void coroutine_fn job_sleep_ns(Job *job, int64_t ns) + job_pause_point(job); + } + ++void job_drain(Job *job) ++{ ++ /* If job is !busy this kicks it into the next pause point. */ ++ job_enter(job); ++ ++ if (job->driver->drain) { ++ job->driver->drain(job); ++ } ++} ++ ++ + /** + * All jobs must allow a pause point before entering their job proper. This + * ensures that jobs can be paused prior to being started, then resumed later. +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index c993512..58ea566 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -525,6 +525,7 @@ BlockJobDriver test_job_driver = { + .instance_size = sizeof(TestBlockJob), + .free = block_job_free, + .user_resume = block_job_user_resume, ++ .drain = block_job_drain, + .start = test_job_start, + }, + .complete = test_job_complete, +diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c +index 60e9fa2..1572f8d 100644 +--- a/tests/test-blockjob-txn.c ++++ b/tests/test-blockjob-txn.c +@@ -79,6 +79,7 @@ static const BlockJobDriver test_block_job_driver = { + .instance_size = sizeof(TestBlockJob), + .free = block_job_free, + .user_resume = block_job_user_resume, ++ .drain = block_job_drain, + .start = test_block_job_run, + }, + }; +diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c +index 1fe6803..592a136 100644 +--- a/tests/test-blockjob.c ++++ b/tests/test-blockjob.c +@@ -21,6 +21,7 @@ static const BlockJobDriver test_block_job_driver = { + .instance_size = sizeof(BlockJob), + .free = block_job_free, + .user_resume = block_job_user_resume, ++ .drain = block_job_drain, + }, + }; + +@@ -201,6 +202,7 @@ static const BlockJobDriver test_cancel_driver = { + .instance_size = sizeof(CancelJob), + .free = block_job_free, + .user_resume = block_job_user_resume, ++ .drain = block_job_drain, + .start = cancel_job_start, + }, + .complete = cancel_job_complete, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Add-job_event_.patch b/SOURCES/kvm-job-Add-job_event_.patch new file mode 100644 index 0000000..2d84e82 --- /dev/null +++ b/SOURCES/kvm-job-Add-job_event_.patch @@ -0,0 +1,232 @@ +From 68b982f2790c7a8caad15f9c088402bbd9d0c611 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:15 +0200 +Subject: [PATCH 46/89] job: Add job_event_*() + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-33-kwolf@redhat.com> +Patchwork-id: 81092 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 32/73] job: Add job_event_*() +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +Go through the Job layer in order to send QMP events. For the moment, +these functions only call a notifier in the BlockJob layer that sends +the existing commands. + +This uses notifiers rather than JobDriver callbacks because internal +users of jobs won't receive QMP events, but might still be interested +in getting notified for the events. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +(cherry picked from commit 139a9f020d49e9f863e0d46fd3d0b440dfb3b9d7) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + blockjob.c | 41 +++++++++++++++++++++++++++-------------- + include/block/blockjob.h | 9 +++++++++ + include/qemu/job.h | 18 ++++++++++++++++++ + job.c | 19 +++++++++++++++++++ + 4 files changed, 73 insertions(+), 14 deletions(-) + +diff --git a/blockjob.c b/blockjob.c +index b4334fb..05d7921 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -36,10 +36,6 @@ + #include "qemu/coroutine.h" + #include "qemu/timer.h" + +-static void block_job_event_cancelled(BlockJob *job); +-static void block_job_event_completed(BlockJob *job, const char *msg); +-static void block_job_event_pending(BlockJob *job); +- + /* Transactional group of block jobs */ + struct BlockJobTxn { + +@@ -352,13 +348,9 @@ static int block_job_finalize_single(BlockJob *job) + /* Emit events only if we actually started */ + if (job_started(&job->job)) { + if (job_is_cancelled(&job->job)) { +- block_job_event_cancelled(job); ++ job_event_cancelled(&job->job); + } else { +- const char *msg = NULL; +- if (job->ret < 0) { +- msg = strerror(-job->ret); +- } +- block_job_event_completed(job, msg); ++ job_event_completed(&job->job); + } + } + +@@ -504,7 +496,7 @@ static int block_job_transition_to_pending(BlockJob *job) + { + job_state_transition(&job->job, JOB_STATUS_PENDING); + if (!job->job.auto_finalize) { +- block_job_event_pending(job); ++ job_event_pending(&job->job); + } + return 0; + } +@@ -712,8 +704,10 @@ static void block_job_iostatus_set_err(BlockJob *job, int error) + } + } + +-static void block_job_event_cancelled(BlockJob *job) ++static void block_job_event_cancelled(Notifier *n, void *opaque) + { ++ BlockJob *job = opaque; ++ + if (block_job_is_internal(job)) { + return; + } +@@ -726,12 +720,19 @@ static void block_job_event_cancelled(BlockJob *job) + &error_abort); + } + +-static void block_job_event_completed(BlockJob *job, const char *msg) ++static void block_job_event_completed(Notifier *n, void *opaque) + { ++ BlockJob *job = opaque; ++ const char *msg = NULL; ++ + if (block_job_is_internal(job)) { + return; + } + ++ if (job->ret < 0) { ++ msg = strerror(-job->ret); ++ } ++ + qapi_event_send_block_job_completed(job_type(&job->job), + job->job.id, + job->len, +@@ -742,8 +743,10 @@ static void block_job_event_completed(BlockJob *job, const char *msg) + &error_abort); + } + +-static void block_job_event_pending(BlockJob *job) ++static void block_job_event_pending(Notifier *n, void *opaque) + { ++ BlockJob *job = opaque; ++ + if (block_job_is_internal(job)) { + return; + } +@@ -799,6 +802,16 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + job->cb = cb; + job->opaque = opaque; + ++ job->finalize_cancelled_notifier.notify = block_job_event_cancelled; ++ job->finalize_completed_notifier.notify = block_job_event_completed; ++ job->pending_notifier.notify = block_job_event_pending; ++ ++ notifier_list_add(&job->job.on_finalize_cancelled, ++ &job->finalize_cancelled_notifier); ++ notifier_list_add(&job->job.on_finalize_completed, ++ &job->finalize_completed_notifier); ++ notifier_list_add(&job->job.on_pending, &job->pending_notifier); ++ + error_setg(&job->blocker, "block device is in use by block job: %s", + job_type_str(&job->job)); + block_job_add_bdrv(job, "main node", bs, 0, BLK_PERM_ALL, &error_abort); +diff --git a/include/block/blockjob.h b/include/block/blockjob.h +index f9aaaaa..aef0629 100644 +--- a/include/block/blockjob.h ++++ b/include/block/blockjob.h +@@ -82,6 +82,15 @@ typedef struct BlockJob { + /** Block other operations when block job is running */ + Error *blocker; + ++ /** Called when a cancelled job is finalised. */ ++ Notifier finalize_cancelled_notifier; ++ ++ /** Called when a successfully completed job is finalised. */ ++ Notifier finalize_completed_notifier; ++ ++ /** Called when the job transitions to PENDING */ ++ Notifier pending_notifier; ++ + /** BlockDriverStates that are involved in this block job */ + GSList *nodes; + +diff --git a/include/qemu/job.h b/include/qemu/job.h +index 9783e40..14d9377 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -105,6 +105,15 @@ typedef struct Job { + /** True if this job should automatically dismiss itself */ + bool auto_dismiss; + ++ /** Notifiers called when a cancelled job is finalised */ ++ NotifierList on_finalize_cancelled; ++ ++ /** Notifiers called when a successfully completed job is finalised */ ++ NotifierList on_finalize_completed; ++ ++ /** Notifiers called when the job transitions to PENDING */ ++ NotifierList on_pending; ++ + /** Element of the list of jobs */ + QLIST_ENTRY(Job) job_list; + } Job; +@@ -182,6 +191,15 @@ void job_ref(Job *job); + */ + void job_unref(Job *job); + ++/** To be called when a cancelled job is finalised. */ ++void job_event_cancelled(Job *job); ++ ++/** To be called when a successfully completed job is finalised. */ ++void job_event_completed(Job *job); ++ ++/** To be called when the job transitions to PENDING */ ++void job_event_pending(Job *job); ++ + /** + * Conditionally enter the job coroutine if the job is ready to run, not + * already busy and fn() returns true. fn() is called while under the job_lock +diff --git a/job.c b/job.c +index dd46170..817c3b4 100644 +--- a/job.c ++++ b/job.c +@@ -215,6 +215,10 @@ void *job_create(const char *job_id, const JobDriver *driver, AioContext *ctx, + job->auto_finalize = !(flags & JOB_MANUAL_FINALIZE); + job->auto_dismiss = !(flags & JOB_MANUAL_DISMISS); + ++ notifier_list_init(&job->on_finalize_cancelled); ++ notifier_list_init(&job->on_finalize_completed); ++ notifier_list_init(&job->on_pending); ++ + job_state_transition(job, JOB_STATUS_CREATED); + aio_timer_init(qemu_get_aio_context(), &job->sleep_timer, + QEMU_CLOCK_REALTIME, SCALE_NS, +@@ -247,6 +251,21 @@ void job_unref(Job *job) + } + } + ++void job_event_cancelled(Job *job) ++{ ++ notifier_list_notify(&job->on_finalize_cancelled, job); ++} ++ ++void job_event_completed(Job *job) ++{ ++ notifier_list_notify(&job->on_finalize_completed, job); ++} ++ ++void job_event_pending(Job *job) ++{ ++ notifier_list_notify(&job->on_pending, job); ++} ++ + void job_enter_cond(Job *job, bool(*fn)(Job *job)) + { + if (!job_started(job)) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Add-job_is_ready.patch b/SOURCES/kvm-job-Add-job_is_ready.patch new file mode 100644 index 0000000..3316fdb --- /dev/null +++ b/SOURCES/kvm-job-Add-job_is_ready.patch @@ -0,0 +1,155 @@ +From bba237b4cbbd22a61ef4cc961a1b0937b806480b Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:27 +0200 +Subject: [PATCH 58/89] job: Add job_is_ready() + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-45-kwolf@redhat.com> +Patchwork-id: 81128 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 44/73] job: Add job_is_ready() +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +Instead of having a 'bool ready' in BlockJob, add a function that +derives its value from the job status. + +At the same time, this fixes the behaviour to match what the QAPI +documentation promises for query-block-job: 'true if the job may be +completed'. When the ready flag was introduced in commit ef6dbf1e46e, +the flag never had to be reset to match the description because after +being ready, the jobs would immediately complete and disappear. + +Job transactions and manual job finalisation were introduced only later. +With these changes, jobs may stay around even after having completed +(and they are not ready to be completed a second time), however their +patches forgot to reset the ready flag. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +(cherry picked from commit df956ae2014340bf7de0190edb1d09be55d9eadf) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + blockjob.c | 3 +-- + include/block/blockjob.h | 5 ----- + include/qemu/job.h | 3 +++ + job.c | 22 ++++++++++++++++++++++ + qemu-img.c | 2 +- + tests/test-blockjob.c | 2 +- + 6 files changed, 28 insertions(+), 9 deletions(-) + +diff --git a/blockjob.c b/blockjob.c +index 3ca009b..38f18e9 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -269,7 +269,7 @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp) + info->offset = job->offset; + info->speed = job->speed; + info->io_status = job->iostatus; +- info->ready = job->ready; ++ info->ready = job_is_ready(&job->job), + info->status = job->job.status; + info->auto_finalize = job->job.auto_finalize; + info->auto_dismiss = job->job.auto_dismiss; +@@ -436,7 +436,6 @@ void block_job_user_resume(Job *job) + void block_job_event_ready(BlockJob *job) + { + job_state_transition(&job->job, JOB_STATUS_READY); +- job->ready = true; + + if (block_job_is_internal(job)) { + return; +diff --git a/include/block/blockjob.h b/include/block/blockjob.h +index 5a81afc..8e1e1ee 100644 +--- a/include/block/blockjob.h ++++ b/include/block/blockjob.h +@@ -49,11 +49,6 @@ typedef struct BlockJob { + /** The block device on which the job is operating. */ + BlockBackend *blk; + +- /** +- * Set to true when the job is ready to be completed. +- */ +- bool ready; +- + /** Status that is published by the query-block-jobs QMP API */ + BlockDeviceIoStatus iostatus; + +diff --git a/include/qemu/job.h b/include/qemu/job.h +index 1e8050c..487f9d9 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -367,6 +367,9 @@ bool job_is_cancelled(Job *job); + /** Returns whether the job is in a completed state. */ + bool job_is_completed(Job *job); + ++/** Returns whether the job is ready to be completed. */ ++bool job_is_ready(Job *job); ++ + /** + * Request @job to pause at the next pause point. Must be paired with + * job_resume(). If the job is supposed to be resumed by user action, call +diff --git a/job.c b/job.c +index 7cd3602..aa4c746 100644 +--- a/job.c ++++ b/job.c +@@ -199,6 +199,28 @@ bool job_is_cancelled(Job *job) + return job->cancelled; + } + ++bool job_is_ready(Job *job) ++{ ++ switch (job->status) { ++ case JOB_STATUS_UNDEFINED: ++ case JOB_STATUS_CREATED: ++ case JOB_STATUS_RUNNING: ++ case JOB_STATUS_PAUSED: ++ case JOB_STATUS_WAITING: ++ case JOB_STATUS_PENDING: ++ case JOB_STATUS_ABORTING: ++ case JOB_STATUS_CONCLUDED: ++ case JOB_STATUS_NULL: ++ return false; ++ case JOB_STATUS_READY: ++ case JOB_STATUS_STANDBY: ++ return true; ++ default: ++ g_assert_not_reached(); ++ } ++ return false; ++} ++ + bool job_is_completed(Job *job) + { + switch (job->status) { +diff --git a/qemu-img.c b/qemu-img.c +index 734ea94..3c449a2 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -878,7 +878,7 @@ static void run_block_job(BlockJob *job, Error **errp) + aio_poll(aio_context, true); + qemu_progress_print(job->len ? + ((float)job->offset / job->len * 100.f) : 0.0f, 0); +- } while (!job->ready && !job_is_completed(&job->job)); ++ } while (!job_is_ready(&job->job) && !job_is_completed(&job->job)); + + if (!job_is_completed(&job->job)) { + ret = job_complete_sync(&job->job, errp); +diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c +index 7131cab..8180d03 100644 +--- a/tests/test-blockjob.c ++++ b/tests/test-blockjob.c +@@ -185,7 +185,7 @@ static void coroutine_fn cancel_job_start(void *opaque) + goto defer; + } + +- if (!s->common.ready && s->should_converge) { ++ if (!job_is_ready(&s->common.job) && s->should_converge) { + block_job_event_ready(&s->common); + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Add-job_sleep_ns.patch b/SOURCES/kvm-job-Add-job_sleep_ns.patch new file mode 100644 index 0000000..acea36a --- /dev/null +++ b/SOURCES/kvm-job-Add-job_sleep_ns.patch @@ -0,0 +1,363 @@ +From 4d81873c780a63cbad24b6ca611760a464c77999 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:10 +0200 +Subject: [PATCH 41/89] job: Add job_sleep_ns() + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-28-kwolf@redhat.com> +Patchwork-id: 81117 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 27/73] job: Add job_sleep_ns() +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +There is nothing block layer specific about block_job_sleep_ns(), so +move the function to Job. + +Signed-off-by: Kevin Wolf +Reviewed-by: John Snow +Reviewed-by: Max Reitz +(cherry picked from commit 5d43e86e11f488fda7956b13160e0c0105a84845) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/backup.c | 2 +- + block/commit.c | 2 +- + block/mirror.c | 4 ++-- + block/stream.c | 2 +- + blockjob.c | 27 --------------------------- + include/block/blockjob_int.h | 11 ----------- + include/qemu/job.h | 19 ++++++++++++++++++- + job.c | 32 ++++++++++++++++++++++++++++++++ + tests/test-bdrv-drain.c | 8 ++++---- + tests/test-blockjob-txn.c | 2 +- + tests/test-blockjob.c | 2 +- + 11 files changed, 61 insertions(+), 50 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index 7d9aad9..f3a4f7c 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -338,7 +338,7 @@ static bool coroutine_fn yield_and_check(BackupBlockJob *job) + * return. Without a yield, the VM would not reboot. */ + delay_ns = block_job_ratelimit_get_delay(&job->common, job->bytes_read); + job->bytes_read = 0; +- block_job_sleep_ns(&job->common, delay_ns); ++ job_sleep_ns(&job->common.job, delay_ns); + + if (job_is_cancelled(&job->common.job)) { + return true; +diff --git a/block/commit.c b/block/commit.c +index 2fbc310..1c6cb6c 100644 +--- a/block/commit.c ++++ b/block/commit.c +@@ -172,7 +172,7 @@ static void coroutine_fn commit_run(void *opaque) + /* Note that even when no rate limit is applied we need to yield + * with no pending I/O here so that bdrv_drain_all() returns. + */ +- block_job_sleep_ns(&s->common, delay_ns); ++ job_sleep_ns(&s->common.job, delay_ns); + if (job_is_cancelled(&s->common.job)) { + break; + } +diff --git a/block/mirror.c b/block/mirror.c +index 95fc807..5d8f75c 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -595,7 +595,7 @@ static void mirror_throttle(MirrorBlockJob *s) + + if (now - s->last_pause_ns > BLOCK_JOB_SLICE_TIME) { + s->last_pause_ns = now; +- block_job_sleep_ns(&s->common, 0); ++ job_sleep_ns(&s->common.job, 0); + } else { + job_pause_point(&s->common.job); + } +@@ -869,7 +869,7 @@ static void coroutine_fn mirror_run(void *opaque) + cnt == 0 ? BLOCK_JOB_SLICE_TIME : 0); + } + trace_mirror_before_sleep(s, cnt, s->synced, delay_ns); +- block_job_sleep_ns(&s->common, delay_ns); ++ job_sleep_ns(&s->common.job, delay_ns); + if (job_is_cancelled(&s->common.job) && + (!s->synced || s->common.force)) + { +diff --git a/block/stream.c b/block/stream.c +index 6d8b7b6..1faab02 100644 +--- a/block/stream.c ++++ b/block/stream.c +@@ -140,7 +140,7 @@ static void coroutine_fn stream_run(void *opaque) + /* Note that even when no rate limit is applied we need to yield + * with no pending I/O here so that bdrv_drain_all() returns. + */ +- block_job_sleep_ns(&s->common, delay_ns); ++ job_sleep_ns(&s->common.job, delay_ns); + if (job_is_cancelled(&s->common.job)) { + break; + } +diff --git a/blockjob.c b/blockjob.c +index 313b1ff..4dc360c 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -181,7 +181,6 @@ void block_job_free(Job *job) + block_job_detach_aio_context, bjob); + blk_unref(bjob->blk); + error_free(bjob->blocker); +- assert(!timer_pending(&bjob->job.sleep_timer)); + } + + static void block_job_attached_aio_context(AioContext *new_context, +@@ -290,13 +289,6 @@ const BlockJobDriver *block_job_driver(BlockJob *job) + return job->driver; + } + +-static void block_job_sleep_timer_cb(void *opaque) +-{ +- BlockJob *job = opaque; +- +- block_job_enter(job); +-} +- + static void block_job_decommission(BlockJob *job) + { + assert(job); +@@ -866,9 +858,6 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + job->opaque = opaque; + job->auto_finalize = !(flags & BLOCK_JOB_MANUAL_FINALIZE); + job->auto_dismiss = !(flags & BLOCK_JOB_MANUAL_DISMISS); +- aio_timer_init(qemu_get_aio_context(), &job->job.sleep_timer, +- QEMU_CLOCK_REALTIME, SCALE_NS, +- block_job_sleep_timer_cb, job); + + error_setg(&job->blocker, "block device is in use by block job: %s", + job_type_str(&job->job)); +@@ -931,22 +920,6 @@ void block_job_enter(BlockJob *job) + job_enter_cond(&job->job, NULL); + } + +-void block_job_sleep_ns(BlockJob *job, int64_t ns) +-{ +- assert(job->job.busy); +- +- /* Check cancellation *before* setting busy = false, too! */ +- if (job_is_cancelled(&job->job)) { +- return; +- } +- +- if (!job_should_pause(&job->job)) { +- job_do_yield(&job->job, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + ns); +- } +- +- job_pause_point(&job->job); +-} +- + void block_job_yield(BlockJob *job) + { + assert(job->job.busy); +diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h +index 0a614a8..8937f5b 100644 +--- a/include/block/blockjob_int.h ++++ b/include/block/blockjob_int.h +@@ -134,17 +134,6 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + void block_job_free(Job *job); + + /** +- * block_job_sleep_ns: +- * @job: The job that calls the function. +- * @ns: How many nanoseconds to stop for. +- * +- * Put the job to sleep (assuming that it wasn't canceled) for @ns +- * %QEMU_CLOCK_REALTIME nanoseconds. Canceling the job will immediately +- * interrupt the wait. +- */ +-void block_job_sleep_ns(BlockJob *job, int64_t ns); +- +-/** + * block_job_yield: + * @job: The job that calls the function. + * +diff --git a/include/qemu/job.h b/include/qemu/job.h +index 9dcff12..509408f 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -58,7 +58,7 @@ typedef struct Job { + Coroutine *co; + + /** +- * Timer that is used by @block_job_sleep_ns. Accessed under job_mutex (in ++ * Timer that is used by @job_sleep_ns. Accessed under job_mutex (in + * job.c). + */ + QEMUTimer sleep_timer; +@@ -168,6 +168,13 @@ void job_enter_cond(Job *job, bool(*fn)(Job *job)); + void job_start(Job *job); + + /** ++ * @job: The job to enter. ++ * ++ * Continue the specified job by entering the coroutine. ++ */ ++void job_enter(Job *job); ++ ++/** + * @job: The job that is ready to pause. + * + * Pause now if job_pause() has been called. Jobs that perform lots of I/O +@@ -175,6 +182,16 @@ void job_start(Job *job); + */ + void coroutine_fn job_pause_point(Job *job); + ++/** ++ * @job: The job that calls the function. ++ * @ns: How many nanoseconds to stop for. ++ * ++ * Put the job to sleep (assuming that it wasn't canceled) for @ns ++ * %QEMU_CLOCK_REALTIME nanoseconds. Canceling the job will immediately ++ * interrupt the wait. ++ */ ++void coroutine_fn job_sleep_ns(Job *job, int64_t ns); ++ + + /** Returns the JobType of a given Job. */ + JobType job_type(const Job *job); +diff --git a/job.c b/job.c +index 78497fd..1b8cba1 100644 +--- a/job.c ++++ b/job.c +@@ -152,6 +152,13 @@ Job *job_get(const char *id) + return NULL; + } + ++static void job_sleep_timer_cb(void *opaque) ++{ ++ Job *job = opaque; ++ ++ job_enter(job); ++} ++ + void *job_create(const char *job_id, const JobDriver *driver, AioContext *ctx, + Error **errp) + { +@@ -178,6 +185,9 @@ void *job_create(const char *job_id, const JobDriver *driver, AioContext *ctx, + job->pause_count = 1; + + job_state_transition(job, JOB_STATUS_CREATED); ++ aio_timer_init(qemu_get_aio_context(), &job->sleep_timer, ++ QEMU_CLOCK_REALTIME, SCALE_NS, ++ job_sleep_timer_cb, job); + + QLIST_INSERT_HEAD(&jobs, job, job_list); + +@@ -193,6 +203,7 @@ void job_unref(Job *job) + { + if (--job->refcnt == 0) { + assert(job->status == JOB_STATUS_NULL); ++ assert(!timer_pending(&job->sleep_timer)); + + if (job->driver->free) { + job->driver->free(job); +@@ -232,6 +243,11 @@ void job_enter_cond(Job *job, bool(*fn)(Job *job)) + aio_co_wake(job->co); + } + ++void job_enter(Job *job) ++{ ++ job_enter_cond(job, NULL); ++} ++ + /* Yield, and schedule a timer to reenter the coroutine after @ns nanoseconds. + * Reentering the job coroutine with block_job_enter() before the timer has + * expired is allowed and cancels the timer. +@@ -283,6 +299,22 @@ void coroutine_fn job_pause_point(Job *job) + } + } + ++void coroutine_fn job_sleep_ns(Job *job, int64_t ns) ++{ ++ assert(job->busy); ++ ++ /* Check cancellation *before* setting busy = false, too! */ ++ if (job_is_cancelled(job)) { ++ return; ++ } ++ ++ if (!job_should_pause(job)) { ++ job_do_yield(job, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + ns); ++ } ++ ++ job_pause_point(job); ++} ++ + /** + * All jobs must allow a pause point before entering their job proper. This + * ensures that jobs can be paused prior to being started, then resumed later. +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index c9f2f9b..50232f5 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -508,7 +508,7 @@ static void coroutine_fn test_job_start(void *opaque) + + block_job_event_ready(&s->common); + while (!s->should_complete) { +- block_job_sleep_ns(&s->common, 100000); ++ job_sleep_ns(&s->common.job, 100000); + } + + job_defer_to_main_loop(&s->common.job, test_job_completed, NULL); +@@ -553,7 +553,7 @@ static void test_blockjob_common(enum drain_type drain_type) + + g_assert_cmpint(job->job.pause_count, ==, 0); + g_assert_false(job->job.paused); +- g_assert_false(job->job.busy); /* We're in block_job_sleep_ns() */ ++ g_assert_false(job->job.busy); /* We're in job_sleep_ns() */ + + do_drain_begin(drain_type, src); + +@@ -571,7 +571,7 @@ static void test_blockjob_common(enum drain_type drain_type) + + g_assert_cmpint(job->job.pause_count, ==, 0); + g_assert_false(job->job.paused); +- g_assert_false(job->job.busy); /* We're in block_job_sleep_ns() */ ++ g_assert_false(job->job.busy); /* We're in job_sleep_ns() */ + + do_drain_begin(drain_type, target); + +@@ -589,7 +589,7 @@ static void test_blockjob_common(enum drain_type drain_type) + + g_assert_cmpint(job->job.pause_count, ==, 0); + g_assert_false(job->job.paused); +- g_assert_false(job->job.busy); /* We're in block_job_sleep_ns() */ ++ g_assert_false(job->job.busy); /* We're in job_sleep_ns() */ + + ret = block_job_complete_sync(job, &error_abort); + g_assert_cmpint(ret, ==, 0); +diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c +index 323e154..0e6162b 100644 +--- a/tests/test-blockjob-txn.c ++++ b/tests/test-blockjob-txn.c +@@ -45,7 +45,7 @@ static void coroutine_fn test_block_job_run(void *opaque) + + while (s->iterations--) { + if (s->use_timer) { +- block_job_sleep_ns(job, 0); ++ job_sleep_ns(&job->job, 0); + } else { + block_job_yield(job); + } +diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c +index 1d18325..b329bd5 100644 +--- a/tests/test-blockjob.c ++++ b/tests/test-blockjob.c +@@ -188,7 +188,7 @@ static void coroutine_fn cancel_job_start(void *opaque) + block_job_event_ready(&s->common); + } + +- block_job_sleep_ns(&s->common, 100000); ++ job_sleep_ns(&s->common.job, 100000); + } + + defer: +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Add-job_transition_to_ready.patch b/SOURCES/kvm-job-Add-job_transition_to_ready.patch new file mode 100644 index 0000000..53ddba5 --- /dev/null +++ b/SOURCES/kvm-job-Add-job_transition_to_ready.patch @@ -0,0 +1,267 @@ +From 0bf028e317ae12d5559465d15a5780de8abfe464 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:28 +0200 +Subject: [PATCH 59/89] job: Add job_transition_to_ready() + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-46-kwolf@redhat.com> +Patchwork-id: 81114 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 45/73] job: Add job_transition_to_ready() +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +The transition to the READY state was still performed in the BlockJob +layer, in the same function that sent the BLOCK_JOB_READY QMP event. + +This patch brings the state transition to the Job layer and implements +the QMP event using a notifier called from the Job layer, like we +already do for other events related to state transitions. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +(cherry picked from commit 2e1795b58131427719c7cd11f8b9b6984b3f24f8) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/mirror.c | 6 +++--- + blockjob.c | 33 ++++++++++++++++++--------------- + include/block/blockjob.h | 3 +++ + include/block/blockjob_int.h | 8 -------- + include/qemu/job.h | 9 ++++++--- + job.c | 16 +++++++++++++--- + tests/test-bdrv-drain.c | 2 +- + tests/test-blockjob.c | 2 +- + 8 files changed, 45 insertions(+), 34 deletions(-) + +diff --git a/block/mirror.c b/block/mirror.c +index 687f955..bdc1b5b 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -727,8 +727,8 @@ static void coroutine_fn mirror_run(void *opaque) + } + + if (s->bdev_length == 0) { +- /* Report BLOCK_JOB_READY and wait for complete. */ +- block_job_event_ready(&s->common); ++ /* Transition to the READY state and wait for complete. */ ++ job_transition_to_ready(&s->common.job); + s->synced = true; + while (!job_is_cancelled(&s->common.job) && !s->should_complete) { + job_yield(&s->common.job); +@@ -824,7 +824,7 @@ static void coroutine_fn mirror_run(void *opaque) + * report completion. This way, block-job-cancel will leave + * the target in a consistent state. + */ +- block_job_event_ready(&s->common); ++ job_transition_to_ready(&s->common.job); + s->synced = true; + } + +diff --git a/blockjob.c b/blockjob.c +index 38f18e9..da11b3b 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -338,6 +338,22 @@ static void block_job_event_pending(Notifier *n, void *opaque) + &error_abort); + } + ++static void block_job_event_ready(Notifier *n, void *opaque) ++{ ++ BlockJob *job = opaque; ++ ++ if (block_job_is_internal(job)) { ++ return; ++ } ++ ++ qapi_event_send_block_job_ready(job_type(&job->job), ++ job->job.id, ++ job->len, ++ job->offset, ++ job->speed, &error_abort); ++} ++ ++ + /* + * API for block job drivers and the block layer. These functions are + * declared in blockjob_int.h. +@@ -386,12 +402,14 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + job->finalize_cancelled_notifier.notify = block_job_event_cancelled; + job->finalize_completed_notifier.notify = block_job_event_completed; + job->pending_notifier.notify = block_job_event_pending; ++ job->ready_notifier.notify = block_job_event_ready; + + notifier_list_add(&job->job.on_finalize_cancelled, + &job->finalize_cancelled_notifier); + notifier_list_add(&job->job.on_finalize_completed, + &job->finalize_completed_notifier); + notifier_list_add(&job->job.on_pending, &job->pending_notifier); ++ notifier_list_add(&job->job.on_ready, &job->ready_notifier); + + error_setg(&job->blocker, "block device is in use by block job: %s", + job_type_str(&job->job)); +@@ -433,21 +451,6 @@ void block_job_user_resume(Job *job) + block_job_iostatus_reset(bjob); + } + +-void block_job_event_ready(BlockJob *job) +-{ +- job_state_transition(&job->job, JOB_STATUS_READY); +- +- if (block_job_is_internal(job)) { +- return; +- } +- +- qapi_event_send_block_job_ready(job_type(&job->job), +- job->job.id, +- job->len, +- job->offset, +- job->speed, &error_abort); +-} +- + BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err, + int is_read, int error) + { +diff --git a/include/block/blockjob.h b/include/block/blockjob.h +index 8e1e1ee..4fca45f 100644 +--- a/include/block/blockjob.h ++++ b/include/block/blockjob.h +@@ -76,6 +76,9 @@ typedef struct BlockJob { + /** Called when the job transitions to PENDING */ + Notifier pending_notifier; + ++ /** Called when the job transitions to READY */ ++ Notifier ready_notifier; ++ + /** BlockDriverStates that are involved in this block job */ + GSList *nodes; + } BlockJob; +diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h +index 806ac64..5cd50c6 100644 +--- a/include/block/blockjob_int.h ++++ b/include/block/blockjob_int.h +@@ -116,14 +116,6 @@ void block_job_drain(Job *job); + int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n); + + /** +- * block_job_event_ready: +- * @job: The job which is now ready to be completed. +- * +- * Send a BLOCK_JOB_READY event for the specified job. +- */ +-void block_job_event_ready(BlockJob *job); +- +-/** + * block_job_error_action: + * @job: The job to signal an error for. + * @on_err: The error action setting. +diff --git a/include/qemu/job.h b/include/qemu/job.h +index 487f9d9..bfc2bc5 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -132,6 +132,9 @@ typedef struct Job { + /** Notifiers called when the job transitions to PENDING */ + NotifierList on_pending; + ++ /** Notifiers called when the job transitions to READY */ ++ NotifierList on_ready; ++ + /** Element of the list of jobs */ + QLIST_ENTRY(Job) job_list; + +@@ -426,6 +429,9 @@ int job_apply_verb(Job *job, JobVerb verb, Error **errp); + /** The @job could not be started, free it. */ + void job_early_fail(Job *job); + ++/** Moves the @job from RUNNING to READY */ ++void job_transition_to_ready(Job *job); ++ + /** + * @job: The job being completed. + * @ret: The status code. +@@ -522,7 +528,4 @@ void job_defer_to_main_loop(Job *job, JobDeferToMainLoopFn *fn, void *opaque); + */ + int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp); + +-/* TODO To be removed from the public interface */ +-void job_state_transition(Job *job, JobStatus s1); +- + #endif +diff --git a/job.c b/job.c +index aa4c746..b5bd51b 100644 +--- a/job.c ++++ b/job.c +@@ -157,9 +157,7 @@ static int job_txn_apply(JobTxn *txn, int fn(Job *), bool lock) + return rc; + } + +- +-/* TODO Make static once the whole state machine is in job.c */ +-void job_state_transition(Job *job, JobStatus s1) ++static void job_state_transition(Job *job, JobStatus s1) + { + JobStatus s0 = job->status; + assert(s1 >= 0 && s1 <= JOB_STATUS__MAX); +@@ -321,6 +319,7 @@ void *job_create(const char *job_id, const JobDriver *driver, JobTxn *txn, + notifier_list_init(&job->on_finalize_cancelled); + notifier_list_init(&job->on_finalize_completed); + notifier_list_init(&job->on_pending); ++ notifier_list_init(&job->on_ready); + + job_state_transition(job, JOB_STATUS_CREATED); + aio_timer_init(qemu_get_aio_context(), &job->sleep_timer, +@@ -380,6 +379,11 @@ static void job_event_pending(Job *job) + notifier_list_notify(&job->on_pending, job); + } + ++static void job_event_ready(Job *job) ++{ ++ notifier_list_notify(&job->on_ready, job); ++} ++ + void job_enter_cond(Job *job, bool(*fn)(Job *job)) + { + if (!job_started(job)) { +@@ -799,6 +803,12 @@ static int job_transition_to_pending(Job *job) + return 0; + } + ++void job_transition_to_ready(Job *job) ++{ ++ job_state_transition(job, JOB_STATUS_READY); ++ job_event_ready(job); ++} ++ + static void job_completed_txn_success(Job *job) + { + JobTxn *txn = job->txn; +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index 3600ffd..2cba63b 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -505,7 +505,7 @@ static void coroutine_fn test_job_start(void *opaque) + { + TestBlockJob *s = opaque; + +- block_job_event_ready(&s->common); ++ job_transition_to_ready(&s->common.job); + while (!s->should_complete) { + job_sleep_ns(&s->common.job, 100000); + } +diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c +index 8180d03..e408d52 100644 +--- a/tests/test-blockjob.c ++++ b/tests/test-blockjob.c +@@ -186,7 +186,7 @@ static void coroutine_fn cancel_job_start(void *opaque) + } + + if (!job_is_ready(&s->common.job) && s->should_converge) { +- block_job_event_ready(&s->common); ++ job_transition_to_ready(&s->common.job); + } + + job_sleep_ns(&s->common.job, 100000); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Add-job_yield.patch b/SOURCES/kvm-job-Add-job_yield.patch new file mode 100644 index 0000000..c26d74c --- /dev/null +++ b/SOURCES/kvm-job-Add-job_yield.patch @@ -0,0 +1,191 @@ +From 053dd2951086a745e456f083d67e055f27029c3d Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:25 +0200 +Subject: [PATCH 56/89] job: Add job_yield() + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-43-kwolf@redhat.com> +Patchwork-id: 81120 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 42/73] job: Add job_yield() +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This moves block_job_yield() to the Job layer. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +(cherry picked from commit 198c49cc8d81e8eb0df3749d395599895c3a3a76) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/backup.c | 2 +- + block/mirror.c | 2 +- + blockjob.c | 16 ---------------- + include/block/blockjob_int.h | 8 -------- + include/qemu/job.h | 9 +++++++-- + job.c | 20 ++++++++++++++++++-- + tests/test-blockjob-txn.c | 2 +- + 7 files changed, 28 insertions(+), 31 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index b13f91d..6f4f3df 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -444,7 +444,7 @@ static void coroutine_fn backup_run(void *opaque) + while (!job_is_cancelled(&job->common.job)) { + /* Yield until the job is cancelled. We just let our before_write + * notify callback service CoW requests. */ +- block_job_yield(&job->common); ++ job_yield(&job->common.job); + } + } else if (job->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) { + ret = backup_run_incremental(job); +diff --git a/block/mirror.c b/block/mirror.c +index c63cf7c..687f955 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -731,7 +731,7 @@ static void coroutine_fn mirror_run(void *opaque) + block_job_event_ready(&s->common); + s->synced = true; + while (!job_is_cancelled(&s->common.job) && !s->should_complete) { +- block_job_yield(&s->common); ++ job_yield(&s->common.job); + } + s->common.job.cancelled = false; + goto immediate_exit; +diff --git a/blockjob.c b/blockjob.c +index 438baa1..f146fe0 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -431,22 +431,6 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + return job; + } + +-void block_job_yield(BlockJob *job) +-{ +- assert(job->job.busy); +- +- /* Check cancellation *before* setting busy = false, too! */ +- if (job_is_cancelled(&job->job)) { +- return; +- } +- +- if (!job_should_pause(&job->job)) { +- job_do_yield(&job->job, -1); +- } +- +- job_pause_point(&job->job); +-} +- + void block_job_iostatus_reset(BlockJob *job) + { + if (job->iostatus == BLOCK_DEVICE_IO_STATUS_OK) { +diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h +index 7df07b2..806ac64 100644 +--- a/include/block/blockjob_int.h ++++ b/include/block/blockjob_int.h +@@ -108,14 +108,6 @@ void block_job_user_resume(Job *job); + void block_job_drain(Job *job); + + /** +- * block_job_yield: +- * @job: The job that calls the function. +- * +- * Yield the block job coroutine. +- */ +-void block_job_yield(BlockJob *job); +- +-/** + * block_job_ratelimit_get_delay: + * + * Calculate and return delay for the next request in ns. See the documentation +diff --git a/include/qemu/job.h b/include/qemu/job.h +index bbe1b0c..94900ec 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -339,6 +339,13 @@ void coroutine_fn job_pause_point(Job *job); + + /** + * @job: The job that calls the function. ++ * ++ * Yield the job coroutine. ++ */ ++void job_yield(Job *job); ++ ++/** ++ * @job: The job that calls the function. + * @ns: How many nanoseconds to stop for. + * + * Put the job to sleep (assuming that it wasn't canceled) for @ns +@@ -508,8 +515,6 @@ int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp) + + /* TODO To be removed from the public interface */ + void job_state_transition(Job *job, JobStatus s1); +-void coroutine_fn job_do_yield(Job *job, uint64_t ns); +-bool job_should_pause(Job *job); + void job_do_dismiss(Job *job); + + #endif +diff --git a/job.c b/job.c +index 2e453f6..eede680 100644 +--- a/job.c ++++ b/job.c +@@ -226,7 +226,7 @@ static bool job_started(Job *job) + return job->co; + } + +-bool job_should_pause(Job *job) ++static bool job_should_pause(Job *job) + { + return job->pause_count > 0; + } +@@ -396,7 +396,7 @@ void job_enter(Job *job) + * + * If @ns is (uint64_t) -1, no timer is scheduled and job_enter() must be + * called explicitly. */ +-void coroutine_fn job_do_yield(Job *job, uint64_t ns) ++static void coroutine_fn job_do_yield(Job *job, uint64_t ns) + { + job_lock(); + if (ns != -1) { +@@ -441,6 +441,22 @@ void coroutine_fn job_pause_point(Job *job) + } + } + ++void job_yield(Job *job) ++{ ++ assert(job->busy); ++ ++ /* Check cancellation *before* setting busy = false, too! */ ++ if (job_is_cancelled(job)) { ++ return; ++ } ++ ++ if (!job_should_pause(job)) { ++ job_do_yield(job, -1); ++ } ++ ++ job_pause_point(job); ++} ++ + void coroutine_fn job_sleep_ns(Job *job, int64_t ns) + { + assert(job->busy); +diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c +index 34ee179..fce8366 100644 +--- a/tests/test-blockjob-txn.c ++++ b/tests/test-blockjob-txn.c +@@ -47,7 +47,7 @@ static void coroutine_fn test_block_job_run(void *opaque) + if (s->use_timer) { + job_sleep_ns(&job->job, 0); + } else { +- block_job_yield(job); ++ job_yield(&job->job); + } + + if (job_is_cancelled(&job->job)) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Add-lifecycle-QMP-commands.patch b/SOURCES/kvm-job-Add-lifecycle-QMP-commands.patch new file mode 100644 index 0000000..103e179 --- /dev/null +++ b/SOURCES/kvm-job-Add-lifecycle-QMP-commands.patch @@ -0,0 +1,324 @@ +From 50909c400b504bc133165f26971f621f915d5fdf Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:32 +0200 +Subject: [PATCH 63/89] job: Add lifecycle QMP commands + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-50-kwolf@redhat.com> +Patchwork-id: 81129 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 49/73] job: Add lifecycle QMP commands +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This adds QMP commands that control the transition between states of the +job lifecycle. + +Signed-off-by: Kevin Wolf +(cherry picked from commit 1a90bc8128ee7d16ce4abb131961e37084d75b16) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + MAINTAINERS | 1 + + Makefile.objs | 1 + + job-qmp.c | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + qapi/job.json | 99 +++++++++++++++++++++++++++++++++++++++++++ + trace-events | 9 ++++ + 5 files changed, 244 insertions(+) + create mode 100644 job-qmp.c + +diff --git a/MAINTAINERS b/MAINTAINERS +index 5aaf264..a783c92 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -1372,6 +1372,7 @@ S: Supported + F: blockjob.c + F: include/block/blockjob.h + F: job.c ++F: job-qmp.c + F: include/block/job.h + F: block/backup.c + F: block/commit.c +diff --git a/Makefile.objs b/Makefile.objs +index 3df8d58..c6c3554 100644 +--- a/Makefile.objs ++++ b/Makefile.objs +@@ -97,6 +97,7 @@ io-obj-y = io/ + ifeq ($(CONFIG_SOFTMMU),y) + common-obj-y = blockdev.o blockdev-nbd.o block/ + common-obj-y += bootdevice.o iothread.o ++common-obj-y += job-qmp.o + common-obj-y += net/ + common-obj-y += qdev-monitor.o device-hotplug.o + common-obj-$(CONFIG_WIN32) += os-win32.o +diff --git a/job-qmp.c b/job-qmp.c +new file mode 100644 +index 0000000..b2e18cf +--- /dev/null ++++ b/job-qmp.c +@@ -0,0 +1,134 @@ ++/* ++ * QMP interface for background jobs ++ * ++ * Copyright (c) 2011 IBM Corp. ++ * Copyright (c) 2012, 2018 Red Hat, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu-common.h" ++#include "qemu/job.h" ++#include "qapi/qapi-commands-job.h" ++#include "qapi/error.h" ++#include "trace-root.h" ++ ++/* Get a job using its ID and acquire its AioContext */ ++static Job *find_job(const char *id, AioContext **aio_context, Error **errp) ++{ ++ Job *job; ++ ++ *aio_context = NULL; ++ ++ job = job_get(id); ++ if (!job) { ++ error_setg(errp, "Job not found"); ++ return NULL; ++ } ++ ++ *aio_context = job->aio_context; ++ aio_context_acquire(*aio_context); ++ ++ return job; ++} ++ ++void qmp_job_cancel(const char *id, Error **errp) ++{ ++ AioContext *aio_context; ++ Job *job = find_job(id, &aio_context, errp); ++ ++ if (!job) { ++ return; ++ } ++ ++ trace_qmp_job_cancel(job); ++ job_user_cancel(job, true, errp); ++ aio_context_release(aio_context); ++} ++ ++void qmp_job_pause(const char *id, Error **errp) ++{ ++ AioContext *aio_context; ++ Job *job = find_job(id, &aio_context, errp); ++ ++ if (!job) { ++ return; ++ } ++ ++ trace_qmp_job_pause(job); ++ job_user_pause(job, errp); ++ aio_context_release(aio_context); ++} ++ ++void qmp_job_resume(const char *id, Error **errp) ++{ ++ AioContext *aio_context; ++ Job *job = find_job(id, &aio_context, errp); ++ ++ if (!job) { ++ return; ++ } ++ ++ trace_qmp_job_resume(job); ++ job_user_resume(job, errp); ++ aio_context_release(aio_context); ++} ++ ++void qmp_job_complete(const char *id, Error **errp) ++{ ++ AioContext *aio_context; ++ Job *job = find_job(id, &aio_context, errp); ++ ++ if (!job) { ++ return; ++ } ++ ++ trace_qmp_job_complete(job); ++ job_complete(job, errp); ++ aio_context_release(aio_context); ++} ++ ++void qmp_job_finalize(const char *id, Error **errp) ++{ ++ AioContext *aio_context; ++ Job *job = find_job(id, &aio_context, errp); ++ ++ if (!job) { ++ return; ++ } ++ ++ trace_qmp_job_finalize(job); ++ job_finalize(job, errp); ++ aio_context_release(aio_context); ++} ++ ++void qmp_job_dismiss(const char *id, Error **errp) ++{ ++ AioContext *aio_context; ++ Job *job = find_job(id, &aio_context, errp); ++ ++ if (!job) { ++ return; ++ } ++ ++ trace_qmp_job_dismiss(job); ++ job_dismiss(&job, errp); ++ aio_context_release(aio_context); ++} +diff --git a/qapi/job.json b/qapi/job.json +index 9fbdd0c..b84dc6c 100644 +--- a/qapi/job.json ++++ b/qapi/job.json +@@ -106,3 +106,102 @@ + { 'event': 'JOB_STATUS_CHANGE', + 'data': { 'id': 'str', + 'status': 'JobStatus' } } ++ ++## ++# @job-pause: ++# ++# Pause an active job. ++# ++# This command returns immediately after marking the active job for pausing. ++# Pausing an already paused job is an error. ++# ++# The job will pause as soon as possible, which means transitioning into the ++# PAUSED state if it was RUNNING, or into STANDBY if it was READY. The ++# corresponding JOB_STATUS_CHANGE event will be emitted. ++# ++# Cancelling a paused job automatically resumes it. ++# ++# @id: The job identifier. ++# ++# Since: 2.13 ++## ++{ 'command': 'job-pause', 'data': { 'id': 'str' } } ++ ++## ++# @job-resume: ++# ++# Resume a paused job. ++# ++# This command returns immediately after resuming a paused job. Resuming an ++# already running job is an error. ++# ++# @id : The job identifier. ++# ++# Since: 2.13 ++## ++{ 'command': 'job-resume', 'data': { 'id': 'str' } } ++ ++## ++# @job-cancel: ++# ++# Instruct an active background job to cancel at the next opportunity. ++# This command returns immediately after marking the active job for ++# cancellation. ++# ++# The job will cancel as soon as possible and then emit a JOB_STATUS_CHANGE ++# event. Usually, the status will change to ABORTING, but it is possible that ++# a job successfully completes (e.g. because it was almost done and there was ++# no opportunity to cancel earlier than completing the job) and transitions to ++# PENDING instead. ++# ++# @id: The job identifier. ++# ++# Since: 2.13 ++## ++{ 'command': 'job-cancel', 'data': { 'id': 'str' } } ++ ++ ++## ++# @job-complete: ++# ++# Manually trigger completion of an active job in the READY state. ++# ++# @id: The job identifier. ++# ++# Since: 2.13 ++## ++{ 'command': 'job-complete', 'data': { 'id': 'str' } } ++ ++## ++# @job-dismiss: ++# ++# Deletes a job that is in the CONCLUDED state. This command only needs to be ++# run explicitly for jobs that don't have automatic dismiss enabled. ++# ++# This command will refuse to operate on any job that has not yet reached its ++# terminal state, JOB_STATUS_CONCLUDED. For jobs that make use of JOB_READY ++# event, job-cancel or job-complete will still need to be used as appropriate. ++# ++# @id: The job identifier. ++# ++# Since: 2.13 ++## ++{ 'command': 'job-dismiss', 'data': { 'id': 'str' } } ++ ++## ++# @job-finalize: ++# ++# Instructs all jobs in a transaction (or a single job if it is not part of any ++# transaction) to finalize any graph changes and do any necessary cleanup. This ++# command requires that all involved jobs are in the PENDING state. ++# ++# For jobs in a transaction, instructing one job to finalize will force ++# ALL jobs in the transaction to finalize, so it is only necessary to instruct ++# a single member job to finalize. ++# ++# @id: The identifier of any job in the transaction, or of a job that is not ++# part of any transaction. ++# ++# Since: 2.13 ++## ++{ 'command': 'job-finalize', 'data': { 'id': 'str' } } +diff --git a/trace-events b/trace-events +index ef7579a..c445f54 100644 +--- a/trace-events ++++ b/trace-events +@@ -109,6 +109,15 @@ job_state_transition(void *job, int ret, const char *legal, const char *s0, con + job_apply_verb(void *job, const char *state, const char *verb, const char *legal) "job %p in state %s; applying verb %s (%s)" + job_completed(void *job, int ret, int jret) "job %p ret %d corrected ret %d" + ++# job-qmp.c ++qmp_job_cancel(void *job) "job %p" ++qmp_job_pause(void *job) "job %p" ++qmp_job_resume(void *job) "job %p" ++qmp_job_complete(void *job) "job %p" ++qmp_job_finalize(void *job) "job %p" ++qmp_job_dismiss(void *job) "job %p" ++ ++ + ### Guest events, keep at bottom + + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Add-query-jobs-QMP-command.patch b/SOURCES/kvm-job-Add-query-jobs-QMP-command.patch new file mode 100644 index 0000000..4f9edb3 --- /dev/null +++ b/SOURCES/kvm-job-Add-query-jobs-QMP-command.patch @@ -0,0 +1,175 @@ +From d32f4952587625fab92b42687273fbb9f89ae78c Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:33 +0200 +Subject: [PATCH 64/89] job: Add query-jobs QMP command + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-51-kwolf@redhat.com> +Patchwork-id: 81095 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 50/73] job: Add query-jobs QMP command +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This adds a minimal query-jobs implementation that shouldn't pose many +design questions. It can later be extended to expose more information, +and especially job-specific information. + +Signed-off-by: Kevin Wolf +(cherry picked from commit 456273b02474780537e2bb52a72213f63bb5227a) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + include/qemu/job.h | 3 +++ + job-qmp.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ + job.c | 2 +- + qapi/job.json | 46 ++++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 104 insertions(+), 1 deletion(-) + +diff --git a/include/qemu/job.h b/include/qemu/job.h +index 92d1d24..8c8badf 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -392,6 +392,9 @@ JobType job_type(const Job *job); + /** Returns the enum string for the JobType of a given Job. */ + const char *job_type_str(const Job *job); + ++/** Returns true if the job should not be visible to the management layer. */ ++bool job_is_internal(Job *job); ++ + /** Returns whether the job is scheduled for cancellation. */ + bool job_is_cancelled(Job *job); + +diff --git a/job-qmp.c b/job-qmp.c +index b2e18cf..7f38f63 100644 +--- a/job-qmp.c ++++ b/job-qmp.c +@@ -132,3 +132,57 @@ void qmp_job_dismiss(const char *id, Error **errp) + job_dismiss(&job, errp); + aio_context_release(aio_context); + } ++ ++static JobInfo *job_query_single(Job *job, Error **errp) ++{ ++ JobInfo *info; ++ const char *errmsg = NULL; ++ ++ assert(!job_is_internal(job)); ++ ++ if (job->ret < 0) { ++ errmsg = strerror(-job->ret); ++ } ++ ++ info = g_new(JobInfo, 1); ++ *info = (JobInfo) { ++ .id = g_strdup(job->id), ++ .type = job_type(job), ++ .status = job->status, ++ .current_progress = job->progress_current, ++ .total_progress = job->progress_total, ++ .has_error = !!errmsg, ++ .error = g_strdup(errmsg), ++ }; ++ ++ return info; ++} ++ ++JobInfoList *qmp_query_jobs(Error **errp) ++{ ++ JobInfoList *head = NULL, **p_next = &head; ++ Job *job; ++ ++ for (job = job_next(NULL); job; job = job_next(job)) { ++ JobInfoList *elem; ++ AioContext *aio_context; ++ ++ if (job_is_internal(job)) { ++ continue; ++ } ++ elem = g_new0(JobInfoList, 1); ++ aio_context = job->aio_context; ++ aio_context_acquire(aio_context); ++ elem->value = job_query_single(job, errp); ++ aio_context_release(aio_context); ++ if (!elem->value) { ++ g_free(elem); ++ qapi_free_JobInfoList(head); ++ return NULL; ++ } ++ *p_next = elem; ++ p_next = &elem->next; ++ } ++ ++ return head; ++} +diff --git a/job.c b/job.c +index 599a104..f026661 100644 +--- a/job.c ++++ b/job.c +@@ -158,7 +158,7 @@ static int job_txn_apply(JobTxn *txn, int fn(Job *), bool lock) + return rc; + } + +-static bool job_is_internal(Job *job) ++bool job_is_internal(Job *job) + { + return (job->id == NULL); + } +diff --git a/qapi/job.json b/qapi/job.json +index b84dc6c..970124d 100644 +--- a/qapi/job.json ++++ b/qapi/job.json +@@ -205,3 +205,49 @@ + # Since: 2.13 + ## + { 'command': 'job-finalize', 'data': { 'id': 'str' } } ++ ++## ++# @JobInfo: ++# ++# Information about a job. ++# ++# @id: The job identifier ++# ++# @type: The kind of job that is being performed ++# ++# @status: Current job state/status ++# ++# @current-progress: Progress made until now. The unit is arbitrary and the ++# value can only meaningfully be used for the ratio of ++# @current-progress to @total-progress. The value is ++# monotonically increasing. ++# ++# @total-progress: Estimated @current-progress value at the completion of ++# the job. This value can arbitrarily change while the ++# job is running, in both directions. ++# ++# @error: If this field is present, the job failed; if it is ++# still missing in the CONCLUDED state, this indicates ++# successful completion. ++# ++# The value is a human-readable error message to describe ++# the reason for the job failure. It should not be parsed ++# by applications. ++# ++# Since: 2.13 ++## ++{ 'struct': 'JobInfo', ++ 'data': { 'id': 'str', 'type': 'JobType', 'status': 'JobStatus', ++ 'current-progress': 'int', 'total-progress': 'int', ++ '*error': 'str' } } ++ ++## ++# @query-jobs: ++# ++# Return information about jobs. ++# ++# Returns: a list with a @JobInfo for each active job ++# ++# Since: 2.13 ++## ++{ 'command': 'query-jobs', 'returns': ['JobInfo'] } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Add-reference-counting.patch b/SOURCES/kvm-job-Add-reference-counting.patch new file mode 100644 index 0000000..7f8dfc1 --- /dev/null +++ b/SOURCES/kvm-job-Add-reference-counting.patch @@ -0,0 +1,446 @@ +From 3f7eb910b9ce698ebc33a039e6bbef1df1437072 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:05 +0200 +Subject: [PATCH 36/89] job: Add reference counting + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-23-kwolf@redhat.com> +Patchwork-id: 81073 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 22/73] job: Add reference counting +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This moves reference counting from BlockJob to Job. + +In order to keep calling the BlockJob cleanup code when the job is +deleted via job_unref(), introduce a new JobDriver.free callback. Every +block job must use block_job_free() for this callback, this is asserted +in block_job_create(). + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +Reviewed-by: John Snow +(cherry picked from commit 80fa2c756b3241f24015a7503a01f7999d4a942d) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/backup.c | 1 + + block/commit.c | 1 + + block/mirror.c | 2 ++ + block/stream.c | 1 + + blockjob.c | 48 +++++++++++++++++++------------------------- + include/block/blockjob.h | 21 ------------------- + include/block/blockjob_int.h | 7 +++++++ + include/qemu/job.h | 19 ++++++++++++++++-- + job.c | 22 ++++++++++++++++---- + qemu-img.c | 4 ++-- + tests/test-bdrv-drain.c | 1 + + tests/test-blockjob-txn.c | 1 + + tests/test-blockjob.c | 6 ++++-- + 13 files changed, 76 insertions(+), 58 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index baf8d43..cfdb89d 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -526,6 +526,7 @@ static const BlockJobDriver backup_job_driver = { + .job_driver = { + .instance_size = sizeof(BackupBlockJob), + .job_type = JOB_TYPE_BACKUP, ++ .free = block_job_free, + }, + .start = backup_run, + .commit = backup_commit, +diff --git a/block/commit.c b/block/commit.c +index 32d29c8..925c96a 100644 +--- a/block/commit.c ++++ b/block/commit.c +@@ -218,6 +218,7 @@ static const BlockJobDriver commit_job_driver = { + .job_driver = { + .instance_size = sizeof(CommitBlockJob), + .job_type = JOB_TYPE_COMMIT, ++ .free = block_job_free, + }, + .start = commit_run, + }; +diff --git a/block/mirror.c b/block/mirror.c +index 35fcc1f..0df4f70 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -989,6 +989,7 @@ static const BlockJobDriver mirror_job_driver = { + .job_driver = { + .instance_size = sizeof(MirrorBlockJob), + .job_type = JOB_TYPE_MIRROR, ++ .free = block_job_free, + }, + .start = mirror_run, + .complete = mirror_complete, +@@ -1001,6 +1002,7 @@ static const BlockJobDriver commit_active_job_driver = { + .job_driver = { + .instance_size = sizeof(MirrorBlockJob), + .job_type = JOB_TYPE_COMMIT, ++ .free = block_job_free, + }, + .start = mirror_run, + .complete = mirror_complete, +diff --git a/block/stream.c b/block/stream.c +index cb723f1..7273d22 100644 +--- a/block/stream.c ++++ b/block/stream.c +@@ -212,6 +212,7 @@ static const BlockJobDriver stream_job_driver = { + .job_driver = { + .instance_size = sizeof(StreamBlockJob), + .job_type = JOB_TYPE_STREAM, ++ .free = block_job_free, + }, + .start = stream_run, + }; +diff --git a/blockjob.c b/blockjob.c +index 0fba01e..0bf0a26 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -190,31 +190,25 @@ static void block_job_resume(BlockJob *job) + block_job_enter_cond(job, block_job_timer_not_pending); + } + +-void block_job_ref(BlockJob *job) +-{ +- ++job->refcnt; +-} +- + static void block_job_attached_aio_context(AioContext *new_context, + void *opaque); + static void block_job_detach_aio_context(void *opaque); + +-void block_job_unref(BlockJob *job) ++void block_job_free(Job *job) + { +- if (--job->refcnt == 0) { +- assert(job->job.status == JOB_STATUS_NULL); +- assert(!job->txn); +- BlockDriverState *bs = blk_bs(job->blk); +- bs->job = NULL; +- block_job_remove_all_bdrv(job); +- blk_remove_aio_context_notifier(job->blk, +- block_job_attached_aio_context, +- block_job_detach_aio_context, job); +- blk_unref(job->blk); +- error_free(job->blocker); +- assert(!timer_pending(&job->sleep_timer)); +- job_delete(&job->job); +- } ++ BlockJob *bjob = container_of(job, BlockJob, job); ++ BlockDriverState *bs = blk_bs(bjob->blk); ++ ++ assert(!bjob->txn); ++ ++ bs->job = NULL; ++ block_job_remove_all_bdrv(bjob); ++ blk_remove_aio_context_notifier(bjob->blk, ++ block_job_attached_aio_context, ++ block_job_detach_aio_context, bjob); ++ blk_unref(bjob->blk); ++ error_free(bjob->blocker); ++ assert(!timer_pending(&bjob->sleep_timer)); + } + + static void block_job_attached_aio_context(AioContext *new_context, +@@ -245,7 +239,7 @@ static void block_job_detach_aio_context(void *opaque) + BlockJob *job = opaque; + + /* In case the job terminates during aio_poll()... */ +- block_job_ref(job); ++ job_ref(&job->job); + + block_job_pause(job); + +@@ -253,7 +247,7 @@ static void block_job_detach_aio_context(void *opaque) + block_job_drain(job); + } + +- block_job_unref(job); ++ job_unref(&job->job); + } + + static char *child_job_get_parent_desc(BdrvChild *c) +@@ -367,7 +361,7 @@ static void block_job_decommission(BlockJob *job) + job->deferred_to_main_loop = true; + block_job_txn_del_job(job); + job_state_transition(&job->job, JOB_STATUS_NULL); +- block_job_unref(job); ++ job_unref(&job->job); + } + + static void block_job_do_dismiss(BlockJob *job) +@@ -506,14 +500,14 @@ static int block_job_finish_sync(BlockJob *job, + + assert(blk_bs(job->blk)->job == job); + +- block_job_ref(job); ++ job_ref(&job->job); + + if (finish) { + finish(job, &local_err); + } + if (local_err) { + error_propagate(errp, local_err); +- block_job_unref(job); ++ job_unref(&job->job); + return -EBUSY; + } + /* block_job_drain calls block_job_enter, and it should be enough to +@@ -526,7 +520,7 @@ static int block_job_finish_sync(BlockJob *job, + aio_poll(qemu_get_aio_context(), true); + } + ret = (job->cancelled && job->ret == 0) ? -ECANCELED : job->ret; +- block_job_unref(job); ++ job_unref(&job->job); + return ret; + } + +@@ -909,6 +903,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + } + + assert(is_block_job(&job->job)); ++ assert(job->job.driver->free == &block_job_free); + + job->driver = driver; + job->blk = blk; +@@ -917,7 +912,6 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + job->busy = false; + job->paused = true; + job->pause_count = 1; +- job->refcnt = 1; + job->auto_finalize = !(flags & BLOCK_JOB_MANUAL_FINALIZE); + job->auto_dismiss = !(flags & BLOCK_JOB_MANUAL_DISMISS); + aio_timer_init(qemu_get_aio_context(), &job->sleep_timer, +diff --git a/include/block/blockjob.h b/include/block/blockjob.h +index 01cdee6..087e782 100644 +--- a/include/block/blockjob.h ++++ b/include/block/blockjob.h +@@ -132,9 +132,6 @@ typedef struct BlockJob { + /** The opaque value that is passed to the completion function. */ + void *opaque; + +- /** Reference count of the block job */ +- int refcnt; +- + /** True when job has reported completion by calling block_job_completed. */ + bool completed; + +@@ -400,24 +397,6 @@ void block_job_iostatus_reset(BlockJob *job); + BlockJobTxn *block_job_txn_new(void); + + /** +- * block_job_ref: +- * +- * Add a reference to BlockJob refcnt, it will be decreased with +- * block_job_unref, and then be freed if it comes to be the last +- * reference. +- */ +-void block_job_ref(BlockJob *job); +- +-/** +- * block_job_unref: +- * +- * Release a reference that was previously acquired with block_job_ref +- * or block_job_create. If it's the last reference to the object, it will be +- * freed. +- */ +-void block_job_unref(BlockJob *job); +- +-/** + * block_job_txn_unref: + * + * Release a reference that was previously acquired with block_job_txn_add_job +diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h +index 1e62d6d..6f0fe3c 100644 +--- a/include/block/blockjob_int.h ++++ b/include/block/blockjob_int.h +@@ -144,6 +144,13 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + BlockCompletionFunc *cb, void *opaque, Error **errp); + + /** ++ * block_job_free: ++ * Callback to be used for JobDriver.free in all block jobs. Frees block job ++ * specific resources in @job. ++ */ ++void block_job_free(Job *job); ++ ++/** + * block_job_sleep_ns: + * @job: The job that calls the function. + * @ns: How many nanoseconds to stop for. +diff --git a/include/qemu/job.h b/include/qemu/job.h +index 0b78778..0751e2a 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -41,6 +41,9 @@ typedef struct Job { + /** The type of this job. */ + const JobDriver *driver; + ++ /** Reference count of the block job */ ++ int refcnt; ++ + /** Current state; See @JobStatus for details. */ + JobStatus status; + +@@ -57,6 +60,9 @@ struct JobDriver { + + /** Enum describing the operation */ + JobType job_type; ++ ++ /** Called when the job is freed */ ++ void (*free)(Job *job); + }; + + +@@ -69,8 +75,17 @@ struct JobDriver { + */ + void *job_create(const char *job_id, const JobDriver *driver, Error **errp); + +-/** Frees the @job object. */ +-void job_delete(Job *job); ++/** ++ * Add a reference to Job refcnt, it will be decreased with job_unref, and then ++ * be freed if it comes to be the last reference. ++ */ ++void job_ref(Job *job); ++ ++/** ++ * Release a reference that was previously acquired with job_ref() or ++ * job_create(). If it's the last reference to the object, it will be freed. ++ */ ++void job_unref(Job *job); + + /** Returns the JobType of a given Job. */ + JobType job_type(const Job *job); +diff --git a/job.c b/job.c +index b049a32..926f1de 100644 +--- a/job.c ++++ b/job.c +@@ -134,6 +134,7 @@ void *job_create(const char *job_id, const JobDriver *driver, Error **errp) + job = g_malloc0(driver->instance_size); + job->driver = driver; + job->id = g_strdup(job_id); ++ job->refcnt = 1; + + job_state_transition(job, JOB_STATUS_CREATED); + +@@ -142,10 +143,23 @@ void *job_create(const char *job_id, const JobDriver *driver, Error **errp) + return job; + } + +-void job_delete(Job *job) ++void job_ref(Job *job) + { +- QLIST_REMOVE(job, job_list); ++ ++job->refcnt; ++} ++ ++void job_unref(Job *job) ++{ ++ if (--job->refcnt == 0) { ++ assert(job->status == JOB_STATUS_NULL); + +- g_free(job->id); +- g_free(job); ++ if (job->driver->free) { ++ job->driver->free(job); ++ } ++ ++ QLIST_REMOVE(job, job_list); ++ ++ g_free(job->id); ++ g_free(job); ++ } + } +diff --git a/qemu-img.c b/qemu-img.c +index e2395b9..f745919 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -873,7 +873,7 @@ static void run_block_job(BlockJob *job, Error **errp) + int ret = 0; + + aio_context_acquire(aio_context); +- block_job_ref(job); ++ job_ref(&job->job); + do { + aio_poll(aio_context, true); + qemu_progress_print(job->len ? +@@ -885,7 +885,7 @@ static void run_block_job(BlockJob *job, Error **errp) + } else { + ret = job->ret; + } +- block_job_unref(job); ++ job_unref(&job->job); + aio_context_release(aio_context); + + /* publish completion progress only when success */ +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index fe9f412..f9e37d4 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -522,6 +522,7 @@ static void test_job_complete(BlockJob *job, Error **errp) + BlockJobDriver test_job_driver = { + .job_driver = { + .instance_size = sizeof(TestBlockJob), ++ .free = block_job_free, + }, + .start = test_job_start, + .complete = test_job_complete, +diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c +index 48b12d1..b49b28c 100644 +--- a/tests/test-blockjob-txn.c ++++ b/tests/test-blockjob-txn.c +@@ -76,6 +76,7 @@ static void test_block_job_cb(void *opaque, int ret) + static const BlockJobDriver test_block_job_driver = { + .job_driver = { + .instance_size = sizeof(TestBlockJob), ++ .free = block_job_free, + }, + .start = test_block_job_run, + }; +diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c +index 6ccd585..e24fc3f 100644 +--- a/tests/test-blockjob.c ++++ b/tests/test-blockjob.c +@@ -19,6 +19,7 @@ + static const BlockJobDriver test_block_job_driver = { + .job_driver = { + .instance_size = sizeof(BlockJob), ++ .free = block_job_free, + }, + }; + +@@ -196,6 +197,7 @@ static void coroutine_fn cancel_job_start(void *opaque) + static const BlockJobDriver test_cancel_driver = { + .job_driver = { + .instance_size = sizeof(CancelJob), ++ .free = block_job_free, + }, + .start = cancel_job_start, + .complete = cancel_job_complete, +@@ -210,7 +212,7 @@ static CancelJob *create_common(BlockJob **pjob) + blk = create_blk(NULL); + job = mk_job(blk, "Steve", &test_cancel_driver, true, + BLOCK_JOB_MANUAL_FINALIZE | BLOCK_JOB_MANUAL_DISMISS); +- block_job_ref(job); ++ job_ref(&job->job); + assert(job->job.status == JOB_STATUS_CREATED); + s = container_of(job, CancelJob, common); + s->blk = blk; +@@ -231,7 +233,7 @@ static void cancel_common(CancelJob *s) + block_job_dismiss(&dummy, &error_abort); + } + assert(job->job.status == JOB_STATUS_NULL); +- block_job_unref(job); ++ job_unref(&job->job); + destroy_blk(blk); + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Avoid-deadlocks-in-job_completed_txn_abort.patch b/SOURCES/kvm-job-Avoid-deadlocks-in-job_completed_txn_abort.patch new file mode 100644 index 0000000..35b5c8c --- /dev/null +++ b/SOURCES/kvm-job-Avoid-deadlocks-in-job_completed_txn_abort.patch @@ -0,0 +1,83 @@ +From c933e15569c9d9b3db7031d8c54712f819816f39 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:39 +0200 +Subject: [PATCH 48/49] job: Avoid deadlocks in job_completed_txn_abort() + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-42-kwolf@redhat.com> +Patchwork-id: 82194 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 41/42] job: Avoid deadlocks in job_completed_txn_abort() +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +Amongst others, job_finalize_single() calls the .prepare/.commit/.abort +callbacks of the individual job driver. Recently, their use was adapted +for all block jobs so that they involve code calling AIO_WAIT_WHILE() +now. Such code must be called under the AioContext lock for the +respective job, but without holding any other AioContext lock. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + job.c | 16 +++++++++++----- + 1 file changed, 11 insertions(+), 5 deletions(-) + +diff --git a/job.c b/job.c +index 42af9e2..5b53e43 100644 +--- a/job.c ++++ b/job.c +@@ -713,6 +713,7 @@ static void job_cancel_async(Job *job, bool force) + + static void job_completed_txn_abort(Job *job) + { ++ AioContext *outer_ctx = job->aio_context; + AioContext *ctx; + JobTxn *txn = job->txn; + Job *other_job; +@@ -726,23 +727,26 @@ static void job_completed_txn_abort(Job *job) + txn->aborting = true; + job_txn_ref(txn); + +- /* We are the first failed job. Cancel other jobs. */ +- QLIST_FOREACH(other_job, &txn->jobs, txn_list) { +- ctx = other_job->aio_context; +- aio_context_acquire(ctx); +- } ++ /* We can only hold the single job's AioContext lock while calling ++ * job_finalize_single() because the finalization callbacks can involve ++ * calls of AIO_WAIT_WHILE(), which could deadlock otherwise. */ ++ aio_context_release(outer_ctx); + + /* Other jobs are effectively cancelled by us, set the status for + * them; this job, however, may or may not be cancelled, depending + * on the caller, so leave it. */ + QLIST_FOREACH(other_job, &txn->jobs, txn_list) { + if (other_job != job) { ++ ctx = other_job->aio_context; ++ aio_context_acquire(ctx); + job_cancel_async(other_job, false); ++ aio_context_release(ctx); + } + } + while (!QLIST_EMPTY(&txn->jobs)) { + other_job = QLIST_FIRST(&txn->jobs); + ctx = other_job->aio_context; ++ aio_context_acquire(ctx); + if (!job_is_completed(other_job)) { + assert(job_is_cancelled(other_job)); + job_finish_sync(other_job, NULL, NULL); +@@ -751,6 +755,8 @@ static void job_completed_txn_abort(Job *job) + aio_context_release(ctx); + } + ++ aio_context_acquire(outer_ctx); ++ + job_txn_unref(txn); + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Convert-block_job_cancel_async-to-Job.patch b/SOURCES/kvm-job-Convert-block_job_cancel_async-to-Job.patch new file mode 100644 index 0000000..5629cd6 --- /dev/null +++ b/SOURCES/kvm-job-Convert-block_job_cancel_async-to-Job.patch @@ -0,0 +1,159 @@ +From c1d6c990e959598f6a1269756b481e4e4230ded8 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:17 +0200 +Subject: [PATCH 48/89] job: Convert block_job_cancel_async() to Job + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-35-kwolf@redhat.com> +Patchwork-id: 81072 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 34/73] job: Convert block_job_cancel_async() to Job +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +block_job_cancel_async() did two things that were still block job +specific: + +* Setting job->force. This field makes sense on the Job level, so we can + just move it. While at it, rename it to job->force_cancel to make its + purpose more obvious. + +* Resetting the I/O status. This can't be moved because generic Jobs + don't have an I/O status. What the function really implements is a + user resume, except without entering the coroutine. Consequently, it + makes sense to call the .user_resume driver callback here which + already resets the I/O status. + + The old block_job_cancel_async() has two separate if statements that + check job->iostatus != BLOCK_DEVICE_IO_STATUS_OK and job->user_paused. + However, the former condition always implies the latter (as is + asserted in block_job_iostatus_reset()), so changing the explicit call + of block_job_iostatus_reset() on the former condition with the + .user_resume callback on the latter condition is equivalent and + doesn't need to access any BlockJob specific state. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +(cherry picked from commit 004e95df98266da33e08c9f1731aca71b6d6d7c4) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/mirror.c | 4 ++-- + blockjob.c | 25 +++++++++++++------------ + include/block/blockjob.h | 6 ------ + include/qemu/job.h | 6 ++++++ + 4 files changed, 21 insertions(+), 20 deletions(-) + +diff --git a/block/mirror.c b/block/mirror.c +index e9a90ea..c3951d1 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -871,7 +871,7 @@ static void coroutine_fn mirror_run(void *opaque) + trace_mirror_before_sleep(s, cnt, s->synced, delay_ns); + job_sleep_ns(&s->common.job, delay_ns); + if (job_is_cancelled(&s->common.job) && +- (!s->synced || s->common.force)) ++ (!s->synced || s->common.job.force_cancel)) + { + break; + } +@@ -884,7 +884,7 @@ immediate_exit: + * or it was cancelled prematurely so that we do not guarantee that + * the target is a copy of the source. + */ +- assert(ret < 0 || ((s->common.force || !s->synced) && ++ assert(ret < 0 || ((s->common.job.force_cancel || !s->synced) && + job_is_cancelled(&s->common.job))); + assert(need_drain); + mirror_wait_for_all_io(s); +diff --git a/blockjob.c b/blockjob.c +index 34c57da..4cac367 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -270,19 +270,20 @@ static int block_job_prepare(BlockJob *job) + return job->job.ret; + } + +-static void block_job_cancel_async(BlockJob *job, bool force) ++static void job_cancel_async(Job *job, bool force) + { +- if (job->iostatus != BLOCK_DEVICE_IO_STATUS_OK) { +- block_job_iostatus_reset(job); +- } +- if (job->job.user_paused) { +- /* Do not call block_job_enter here, the caller will handle it. */ +- job->job.user_paused = false; +- job->job.pause_count--; ++ if (job->user_paused) { ++ /* Do not call job_enter here, the caller will handle it. */ ++ job->user_paused = false; ++ if (job->driver->user_resume) { ++ job->driver->user_resume(job); ++ } ++ assert(job->pause_count > 0); ++ job->pause_count--; + } +- job->job.cancelled = true; ++ job->cancelled = true; + /* To prevent 'force == false' overriding a previous 'force == true' */ +- job->force |= force; ++ job->force_cancel |= force; + } + + static int block_job_txn_apply(BlockJobTxn *txn, int fn(BlockJob *), bool lock) +@@ -367,7 +368,7 @@ static void block_job_completed_txn_abort(BlockJob *job) + * on the caller, so leave it. */ + QLIST_FOREACH(other_job, &txn->jobs, txn_list) { + if (other_job != job) { +- block_job_cancel_async(other_job, false); ++ job_cancel_async(&other_job->job, false); + } + } + while (!QLIST_EMPTY(&txn->jobs)) { +@@ -527,7 +528,7 @@ void block_job_cancel(BlockJob *job, bool force) + job_do_dismiss(&job->job); + return; + } +- block_job_cancel_async(job, force); ++ job_cancel_async(&job->job, force); + if (!job_started(&job->job)) { + block_job_completed(job, -ECANCELED); + } else if (job->job.deferred_to_main_loop) { +diff --git a/include/block/blockjob.h b/include/block/blockjob.h +index 3f405d1..d975efe 100644 +--- a/include/block/blockjob.h ++++ b/include/block/blockjob.h +@@ -51,12 +51,6 @@ typedef struct BlockJob { + BlockBackend *blk; + + /** +- * Set to true if the job should abort immediately without waiting +- * for data to be in sync. +- */ +- bool force; +- +- /** + * Set to true when the job is ready to be completed. + */ + bool ready; +diff --git a/include/qemu/job.h b/include/qemu/job.h +index 3e817be..2648c74 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -97,6 +97,12 @@ typedef struct Job { + */ + bool cancelled; + ++ /** ++ * Set to true if the job should abort immediately without waiting ++ * for data to be in sync. ++ */ ++ bool force_cancel; ++ + /** Set to true when the job has deferred work to the main loop. */ + bool deferred_to_main_loop; + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Create-Job-JobDriver-and-job_create.patch b/SOURCES/kvm-job-Create-Job-JobDriver-and-job_create.patch new file mode 100644 index 0000000..e162901 --- /dev/null +++ b/SOURCES/kvm-job-Create-Job-JobDriver-and-job_create.patch @@ -0,0 +1,571 @@ +From 0223091bd8c515f4eab85de49c039f1275dd8a66 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:47:59 +0200 +Subject: [PATCH 30/89] job: Create Job, JobDriver and job_create() + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-17-kwolf@redhat.com> +Patchwork-id: 81124 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 16/73] job: Create Job, JobDriver and job_create() +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This is the first step towards creating an infrastructure for generic +background jobs that aren't tied to a block device. For now, Job only +stores its ID and JobDriver, the rest stays in BlockJob. + +The following patches will move over more parts of BlockJob to Job if +they are meaningful outside the context of a block job. + +BlockJob.driver is now redundant, but this patch leaves it around to +avoid unnecessary churn. The next patches will get rid of almost all of +its uses anyway so that it can be removed later with much less churn. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +Reviewed-by: John Snow +(cherry picked from commit 33e9e9bd62d9ae00880d9e12ad8a5b7d2c00e8a5) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + MAINTAINERS | 2 ++ + Makefile.objs | 2 +- + block/backup.c | 4 ++- + block/commit.c | 4 ++- + block/mirror.c | 10 +++++--- + block/stream.c | 4 ++- + blockjob.c | 46 ++++++++++++++++----------------- + include/block/blockjob.h | 9 +++---- + include/block/blockjob_int.h | 4 +-- + include/qemu/job.h | 60 ++++++++++++++++++++++++++++++++++++++++++++ + job.c | 48 +++++++++++++++++++++++++++++++++++ + tests/test-bdrv-drain.c | 4 ++- + tests/test-blockjob-txn.c | 4 ++- + tests/test-blockjob.c | 12 ++++++--- + 14 files changed, 169 insertions(+), 44 deletions(-) + create mode 100644 include/qemu/job.h + create mode 100644 job.c + +diff --git a/MAINTAINERS b/MAINTAINERS +index ad5edc8..c5e3dfb 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -1371,6 +1371,8 @@ L: qemu-block@nongnu.org + S: Supported + F: blockjob.c + F: include/block/blockjob.h ++F: job.c ++F: include/block/job.h + F: block/backup.c + F: block/commit.c + F: block/stream.c +diff --git a/Makefile.objs b/Makefile.objs +index c6c9b8f..92b73fc 100644 +--- a/Makefile.objs ++++ b/Makefile.objs +@@ -63,7 +63,7 @@ chardev-obj-y = chardev/ + # block-obj-y is code used by both qemu system emulation and qemu-img + + block-obj-y += nbd/ +-block-obj-y += block.o blockjob.o ++block-obj-y += block.o blockjob.o job.o + block-obj-y += block/ scsi/ + block-obj-y += qemu-io-cmds.o + block-obj-$(CONFIG_REPLICATION) += replication.o +diff --git a/block/backup.c b/block/backup.c +index e14d995..9e672bb 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -523,7 +523,9 @@ static void coroutine_fn backup_run(void *opaque) + } + + static const BlockJobDriver backup_job_driver = { +- .instance_size = sizeof(BackupBlockJob), ++ .job_driver = { ++ .instance_size = sizeof(BackupBlockJob), ++ }, + .job_type = BLOCK_JOB_TYPE_BACKUP, + .start = backup_run, + .commit = backup_commit, +diff --git a/block/commit.c b/block/commit.c +index ba5df6a..18cbb2f 100644 +--- a/block/commit.c ++++ b/block/commit.c +@@ -215,7 +215,9 @@ out: + } + + static const BlockJobDriver commit_job_driver = { +- .instance_size = sizeof(CommitBlockJob), ++ .job_driver = { ++ .instance_size = sizeof(CommitBlockJob), ++ }, + .job_type = BLOCK_JOB_TYPE_COMMIT, + .start = commit_run, + }; +diff --git a/block/mirror.c b/block/mirror.c +index a4197bb..aa1d6b7 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -913,7 +913,7 @@ static void mirror_complete(BlockJob *job, Error **errp) + + if (!s->synced) { + error_setg(errp, "The active block job '%s' cannot be completed", +- job->id); ++ job->job.id); + return; + } + +@@ -986,7 +986,9 @@ static void mirror_drain(BlockJob *job) + } + + static const BlockJobDriver mirror_job_driver = { +- .instance_size = sizeof(MirrorBlockJob), ++ .job_driver = { ++ .instance_size = sizeof(MirrorBlockJob), ++ }, + .job_type = BLOCK_JOB_TYPE_MIRROR, + .start = mirror_run, + .complete = mirror_complete, +@@ -996,7 +998,9 @@ static const BlockJobDriver mirror_job_driver = { + }; + + static const BlockJobDriver commit_active_job_driver = { +- .instance_size = sizeof(MirrorBlockJob), ++ .job_driver = { ++ .instance_size = sizeof(MirrorBlockJob), ++ }, + .job_type = BLOCK_JOB_TYPE_COMMIT, + .start = mirror_run, + .complete = mirror_complete, +diff --git a/block/stream.c b/block/stream.c +index df9660d..f88fc75 100644 +--- a/block/stream.c ++++ b/block/stream.c +@@ -209,7 +209,9 @@ out: + } + + static const BlockJobDriver stream_job_driver = { +- .instance_size = sizeof(StreamBlockJob), ++ .job_driver = { ++ .instance_size = sizeof(StreamBlockJob), ++ }, + .job_type = BLOCK_JOB_TYPE_STREAM, + .start = stream_run, + }; +diff --git a/blockjob.c b/blockjob.c +index 112672a..1464856 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -34,7 +34,6 @@ + #include "qapi/qapi-events-block-core.h" + #include "qapi/qmp/qerror.h" + #include "qemu/coroutine.h" +-#include "qemu/id.h" + #include "qemu/timer.h" + + /* Right now, this mutex is only needed to synchronize accesses to job->busy +@@ -92,7 +91,8 @@ static int block_job_apply_verb(BlockJob *job, BlockJobVerb bv, Error **errp) + return 0; + } + error_setg(errp, "Job '%s' in state '%s' cannot accept command verb '%s'", +- job->id, BlockJobStatus_str(job->status), BlockJobVerb_str(bv)); ++ job->job.id, BlockJobStatus_str(job->status), ++ BlockJobVerb_str(bv)); + return -EPERM; + } + +@@ -159,7 +159,7 @@ BlockJob *block_job_get(const char *id) + BlockJob *job; + + QLIST_FOREACH(job, &block_jobs, job_list) { +- if (job->id && !strcmp(id, job->id)) { ++ if (job->job.id && !strcmp(id, job->job.id)) { + return job; + } + } +@@ -261,7 +261,7 @@ void block_job_unref(BlockJob *job) + block_job_detach_aio_context, job); + blk_unref(job->blk); + error_free(job->blocker); +- g_free(job->id); ++ g_free(job->job.id); + assert(!timer_pending(&job->sleep_timer)); + g_free(job); + } +@@ -311,7 +311,7 @@ static char *child_job_get_parent_desc(BdrvChild *c) + BlockJob *job = c->opaque; + return g_strdup_printf("%s job '%s'", + BlockJobType_str(job->driver->job_type), +- job->id); ++ job->job.id); + } + + static void child_job_drained_begin(BdrvChild *c) +@@ -365,7 +365,7 @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs, + + bool block_job_is_internal(BlockJob *job) + { +- return (job->id == NULL); ++ return (job->job.id == NULL); + } + + static bool block_job_started(BlockJob *job) +@@ -705,13 +705,13 @@ int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n) + void block_job_complete(BlockJob *job, Error **errp) + { + /* Should not be reachable via external interface for internal jobs */ +- assert(job->id); ++ assert(job->job.id); + if (block_job_apply_verb(job, BLOCK_JOB_VERB_COMPLETE, errp)) { + return; + } + if (job->pause_count || job->cancelled || !job->driver->complete) { + error_setg(errp, "The active block job '%s' cannot be completed", +- job->id); ++ job->job.id); + return; + } + +@@ -720,7 +720,7 @@ void block_job_complete(BlockJob *job, Error **errp) + + void block_job_finalize(BlockJob *job, Error **errp) + { +- assert(job && job->id); ++ assert(job && job->job.id); + if (block_job_apply_verb(job, BLOCK_JOB_VERB_FINALIZE, errp)) { + return; + } +@@ -731,7 +731,7 @@ void block_job_dismiss(BlockJob **jobptr, Error **errp) + { + BlockJob *job = *jobptr; + /* similarly to _complete, this is QMP-interface only. */ +- assert(job->id); ++ assert(job->job.id); + if (block_job_apply_verb(job, BLOCK_JOB_VERB_DISMISS, errp)) { + return; + } +@@ -848,7 +848,7 @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp) + } + info = g_new0(BlockJobInfo, 1); + info->type = g_strdup(BlockJobType_str(job->driver->job_type)); +- info->device = g_strdup(job->id); ++ info->device = g_strdup(job->job.id); + info->len = job->len; + info->busy = atomic_read(&job->busy); + info->paused = job->pause_count > 0; +@@ -879,7 +879,7 @@ static void block_job_event_cancelled(BlockJob *job) + } + + qapi_event_send_block_job_cancelled(job->driver->job_type, +- job->id, ++ job->job.id, + job->len, + job->offset, + job->speed, +@@ -893,7 +893,7 @@ static void block_job_event_completed(BlockJob *job, const char *msg) + } + + qapi_event_send_block_job_completed(job->driver->job_type, +- job->id, ++ job->job.id, + job->len, + job->offset, + job->speed, +@@ -907,7 +907,7 @@ static int block_job_event_pending(BlockJob *job) + block_job_state_transition(job, BLOCK_JOB_STATUS_PENDING); + if (!job->auto_finalize && !block_job_is_internal(job)) { + qapi_event_send_block_job_pending(job->driver->job_type, +- job->id, ++ job->job.id, + &error_abort); + } + return 0; +@@ -945,12 +945,6 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + error_setg(errp, "Cannot specify job ID for internal block job"); + return NULL; + } +- +- if (!id_wellformed(job_id)) { +- error_setg(errp, "Invalid job ID '%s'", job_id); +- return NULL; +- } +- + if (block_job_get(job_id)) { + error_setg(errp, "Job ID '%s' already in use", job_id); + return NULL; +@@ -964,9 +958,13 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + return NULL; + } + +- job = g_malloc0(driver->instance_size); ++ job = job_create(job_id, &driver->job_driver, errp); ++ if (job == NULL) { ++ blk_unref(blk); ++ return NULL; ++ } ++ + job->driver = driver; +- job->id = g_strdup(job_id); + job->blk = blk; + job->cb = cb; + job->opaque = opaque; +@@ -1187,7 +1185,7 @@ void block_job_event_ready(BlockJob *job) + } + + qapi_event_send_block_job_ready(job->driver->job_type, +- job->id, ++ job->job.id, + job->len, + job->offset, + job->speed, &error_abort); +@@ -1217,7 +1215,7 @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err, + abort(); + } + if (!block_job_is_internal(job)) { +- qapi_event_send_block_job_error(job->id, ++ qapi_event_send_block_job_error(job->job.id, + is_read ? IO_OPERATION_TYPE_READ : + IO_OPERATION_TYPE_WRITE, + action, &error_abort); +diff --git a/include/block/blockjob.h b/include/block/blockjob.h +index 0f56f72..640e649 100644 +--- a/include/block/blockjob.h ++++ b/include/block/blockjob.h +@@ -26,6 +26,7 @@ + #ifndef BLOCKJOB_H + #define BLOCKJOB_H + ++#include "qemu/job.h" + #include "block/block.h" + #include "qemu/ratelimit.h" + +@@ -40,6 +41,9 @@ typedef struct BlockJobTxn BlockJobTxn; + * Long-running operation on a BlockDriverState. + */ + typedef struct BlockJob { ++ /** Data belonging to the generic Job infrastructure */ ++ Job job; ++ + /** The job type, including the job vtable. */ + const BlockJobDriver *driver; + +@@ -47,11 +51,6 @@ typedef struct BlockJob { + BlockBackend *blk; + + /** +- * The ID of the block job. May be NULL for internal jobs. +- */ +- char *id; +- +- /** + * The coroutine that executes the job. If not NULL, it is + * reentered when busy is false and the job is cancelled. + */ +diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h +index 62ec964..e8eca44 100644 +--- a/include/block/blockjob_int.h ++++ b/include/block/blockjob_int.h +@@ -35,8 +35,8 @@ + * A class type for block job driver. + */ + struct BlockJobDriver { +- /** Derived BlockJob struct size */ +- size_t instance_size; ++ /** Generic JobDriver callbacks and settings */ ++ JobDriver job_driver; + + /** String describing the operation, part of query-block-jobs QMP API */ + BlockJobType job_type; +diff --git a/include/qemu/job.h b/include/qemu/job.h +new file mode 100644 +index 0000000..b4b49f1 +--- /dev/null ++++ b/include/qemu/job.h +@@ -0,0 +1,60 @@ ++/* ++ * Declarations for background jobs ++ * ++ * Copyright (c) 2011 IBM Corp. ++ * Copyright (c) 2012, 2018 Red Hat, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++ ++#ifndef JOB_H ++#define JOB_H ++ ++typedef struct JobDriver JobDriver; ++ ++/** ++ * Long-running operation. ++ */ ++typedef struct Job { ++ /** The ID of the job. May be NULL for internal jobs. */ ++ char *id; ++ ++ /** The type of this job. */ ++ const JobDriver *driver; ++} Job; ++ ++/** ++ * Callbacks and other information about a Job driver. ++ */ ++struct JobDriver { ++ /** Derived Job struct size */ ++ size_t instance_size; ++}; ++ ++ ++/** ++ * Create a new long-running job and return it. ++ * ++ * @job_id: The id of the newly-created job, or %NULL for internal jobs ++ * @driver: The class object for the newly-created job. ++ * @errp: Error object. ++ */ ++void *job_create(const char *job_id, const JobDriver *driver, Error **errp); ++ ++#endif +diff --git a/job.c b/job.c +new file mode 100644 +index 0000000..87fd484 +--- /dev/null ++++ b/job.c +@@ -0,0 +1,48 @@ ++/* ++ * Background jobs (long-running operations) ++ * ++ * Copyright (c) 2011 IBM Corp. ++ * Copyright (c) 2012, 2018 Red Hat, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu-common.h" ++#include "qapi/error.h" ++#include "qemu/job.h" ++#include "qemu/id.h" ++ ++void *job_create(const char *job_id, const JobDriver *driver, Error **errp) ++{ ++ Job *job; ++ ++ if (job_id) { ++ if (!id_wellformed(job_id)) { ++ error_setg(errp, "Invalid job ID '%s'", job_id); ++ return NULL; ++ } ++ } ++ ++ job = g_malloc0(driver->instance_size); ++ job->driver = driver; ++ job->id = g_strdup(job_id); ++ ++ return job; ++} +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index 7673de1..fe9f412 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -520,7 +520,9 @@ static void test_job_complete(BlockJob *job, Error **errp) + } + + BlockJobDriver test_job_driver = { +- .instance_size = sizeof(TestBlockJob), ++ .job_driver = { ++ .instance_size = sizeof(TestBlockJob), ++ }, + .start = test_job_start, + .complete = test_job_complete, + }; +diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c +index 5789893..48b12d1 100644 +--- a/tests/test-blockjob-txn.c ++++ b/tests/test-blockjob-txn.c +@@ -74,7 +74,9 @@ static void test_block_job_cb(void *opaque, int ret) + } + + static const BlockJobDriver test_block_job_driver = { +- .instance_size = sizeof(TestBlockJob), ++ .job_driver = { ++ .instance_size = sizeof(TestBlockJob), ++ }, + .start = test_block_job_run, + }; + +diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c +index 8946bfd..b820261 100644 +--- a/tests/test-blockjob.c ++++ b/tests/test-blockjob.c +@@ -17,7 +17,9 @@ + #include "sysemu/block-backend.h" + + static const BlockJobDriver test_block_job_driver = { +- .instance_size = sizeof(BlockJob), ++ .job_driver = { ++ .instance_size = sizeof(BlockJob), ++ }, + }; + + static void block_job_cb(void *opaque, int ret) +@@ -38,9 +40,9 @@ static BlockJob *mk_job(BlockBackend *blk, const char *id, + g_assert_null(errp); + g_assert_nonnull(job); + if (id) { +- g_assert_cmpstr(job->id, ==, id); ++ g_assert_cmpstr(job->job.id, ==, id); + } else { +- g_assert_cmpstr(job->id, ==, blk_name(blk)); ++ g_assert_cmpstr(job->job.id, ==, blk_name(blk)); + } + } else { + g_assert_nonnull(errp); +@@ -192,7 +194,9 @@ static void coroutine_fn cancel_job_start(void *opaque) + } + + static const BlockJobDriver test_cancel_driver = { +- .instance_size = sizeof(CancelJob), ++ .job_driver = { ++ .instance_size = sizeof(CancelJob), ++ }, + .start = cancel_job_start, + .complete = cancel_job_complete, + }; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Fix-missing-locking-due-to-mismerge.patch b/SOURCES/kvm-job-Fix-missing-locking-due-to-mismerge.patch new file mode 100644 index 0000000..18197df --- /dev/null +++ b/SOURCES/kvm-job-Fix-missing-locking-due-to-mismerge.patch @@ -0,0 +1,53 @@ +From a3a6c860441cfaa684fe819791628f9d43af98dc Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:24 +0200 +Subject: [PATCH 33/49] job: Fix missing locking due to mismerge + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-27-kwolf@redhat.com> +Patchwork-id: 82178 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 26/42] job: Fix missing locking due to mismerge +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +job_completed() had a problem with double locking that was recently +fixed independently by two different commits: + +"job: Fix nested aio_poll() hanging in job_txn_apply" +"jobs: add exit shim" + +One fix removed the first aio_context_acquire(), the other fix removed +the other one. Now we have a bug again and the code is run without any +locking. + +Add it back in one of the places. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +Reviewed-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + job.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/job.c b/job.c +index 5d117fb..db53163 100644 +--- a/job.c ++++ b/job.c +@@ -842,7 +842,11 @@ static void job_completed(Job *job) + static void job_exit(void *opaque) + { + Job *job = (Job *)opaque; ++ AioContext *ctx = job->aio_context; ++ ++ aio_context_acquire(ctx); + job_completed(job); ++ aio_context_release(ctx); + } + + /** +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Fix-nested-aio_poll-hanging-in-job_txn_apply.patch b/SOURCES/kvm-job-Fix-nested-aio_poll-hanging-in-job_txn_apply.patch new file mode 100644 index 0000000..b1e6220 --- /dev/null +++ b/SOURCES/kvm-job-Fix-nested-aio_poll-hanging-in-job_txn_apply.patch @@ -0,0 +1,103 @@ +From 2a9333d5c086c587c527afe9dc9936e3a1658e84 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:23 +0200 +Subject: [PATCH 32/49] job: Fix nested aio_poll() hanging in job_txn_apply + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-26-kwolf@redhat.com> +Patchwork-id: 82177 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 25/42] job: Fix nested aio_poll() hanging in job_txn_apply +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +From: Fam Zheng + +All callers have acquired ctx already. Doing that again results in +aio_poll() hang. This fixes the problem that a BDRV_POLL_WHILE() in the +callback cannot make progress because ctx is recursively locked, for +example, when drive-backup finishes. + +There are two callers of job_finalize(): + + fam@lemon:~/work/qemu [master]$ git grep -w -A1 '^\s*job_finalize' + blockdev.c: job_finalize(&job->job, errp); + blockdev.c- aio_context_release(aio_context); + -- + job-qmp.c: job_finalize(job, errp); + job-qmp.c- aio_context_release(aio_context); + -- + tests/test-blockjob.c: job_finalize(&job->job, &error_abort); + tests/test-blockjob.c- assert(job->job.status == JOB_STATUS_CONCLUDED); + +Ignoring the test, it's easy to see both callers to job_finalize (and +job_do_finalize) have acquired the context. + +Cc: qemu-stable@nongnu.org +Reported-by: Gu Nini +Reviewed-by: Eric Blake +Signed-off-by: Fam Zheng +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + job.c | 18 +++++------------- + 1 file changed, 5 insertions(+), 13 deletions(-) + +diff --git a/job.c b/job.c +index dfba4bc..5d117fb 100644 +--- a/job.c ++++ b/job.c +@@ -136,21 +136,13 @@ static void job_txn_del_job(Job *job) + } + } + +-static int job_txn_apply(JobTxn *txn, int fn(Job *), bool lock) ++static int job_txn_apply(JobTxn *txn, int fn(Job *)) + { +- AioContext *ctx; + Job *job, *next; + int rc = 0; + + QLIST_FOREACH_SAFE(job, &txn->jobs, txn_list, next) { +- if (lock) { +- ctx = job->aio_context; +- aio_context_acquire(ctx); +- } + rc = fn(job); +- if (lock) { +- aio_context_release(ctx); +- } + if (rc) { + break; + } +@@ -775,11 +767,11 @@ static void job_do_finalize(Job *job) + assert(job && job->txn); + + /* prepare the transaction to complete */ +- rc = job_txn_apply(job->txn, job_prepare, true); ++ rc = job_txn_apply(job->txn, job_prepare); + if (rc) { + job_completed_txn_abort(job); + } else { +- job_txn_apply(job->txn, job_finalize_single, true); ++ job_txn_apply(job->txn, job_finalize_single); + } + } + +@@ -825,10 +817,10 @@ static void job_completed_txn_success(Job *job) + assert(other_job->ret == 0); + } + +- job_txn_apply(txn, job_transition_to_pending, false); ++ job_txn_apply(txn, job_transition_to_pending); + + /* If no jobs need manual finalization, automatically do so */ +- if (job_txn_apply(txn, job_needs_finalize, false) == 0) { ++ if (job_txn_apply(txn, job_needs_finalize) == 0) { + job_do_finalize(job); + } + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Introduce-qapi-job.json.patch b/SOURCES/kvm-job-Introduce-qapi-job.json.patch new file mode 100644 index 0000000..d1f44ed --- /dev/null +++ b/SOURCES/kvm-job-Introduce-qapi-job.json.patch @@ -0,0 +1,381 @@ +From 4cbc960084f4dc3e4e760c0d79989edbed1157e8 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:30 +0200 +Subject: [PATCH 61/89] job: Introduce qapi/job.json + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-48-kwolf@redhat.com> +Patchwork-id: 81099 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 47/73] job: Introduce qapi/job.json +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This adds a separate schema file for all job-related definitions that +aren't tied to the block layer. + +For a start, move the enums JobType, JobStatus and JobVerb. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +(cherry picked from commit bf42508f24ee1368267b421e145fa90315b77936) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + MAINTAINERS | 1 + + Makefile | 9 +++++ + Makefile.objs | 4 +++ + qapi/block-core.json | 90 +----------------------------------------------- + qapi/job.json | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++ + qapi/qapi-schema.json | 1 + + 6 files changed, 110 insertions(+), 89 deletions(-) + create mode 100644 qapi/job.json + +diff --git a/MAINTAINERS b/MAINTAINERS +index c5e3dfb..5aaf264 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -1377,6 +1377,7 @@ F: block/backup.c + F: block/commit.c + F: block/stream.c + F: block/mirror.c ++F: qapi/job.json + T: git git://github.com/codyprime/qemu-kvm-jtc.git block + + Block QAPI, monitor, command line +diff --git a/Makefile b/Makefile +index bdd8223..c95553f 100644 +--- a/Makefile ++++ b/Makefile +@@ -98,6 +98,7 @@ GENERATED_FILES += qapi/qapi-types-char.h qapi/qapi-types-char.c + GENERATED_FILES += qapi/qapi-types-common.h qapi/qapi-types-common.c + GENERATED_FILES += qapi/qapi-types-crypto.h qapi/qapi-types-crypto.c + GENERATED_FILES += qapi/qapi-types-introspect.h qapi/qapi-types-introspect.c ++GENERATED_FILES += qapi/qapi-types-job.h qapi/qapi-types-job.c + GENERATED_FILES += qapi/qapi-types-migration.h qapi/qapi-types-migration.c + GENERATED_FILES += qapi/qapi-types-misc.h qapi/qapi-types-misc.c + GENERATED_FILES += qapi/qapi-types-net.h qapi/qapi-types-net.c +@@ -116,6 +117,7 @@ GENERATED_FILES += qapi/qapi-visit-char.h qapi/qapi-visit-char.c + GENERATED_FILES += qapi/qapi-visit-common.h qapi/qapi-visit-common.c + GENERATED_FILES += qapi/qapi-visit-crypto.h qapi/qapi-visit-crypto.c + GENERATED_FILES += qapi/qapi-visit-introspect.h qapi/qapi-visit-introspect.c ++GENERATED_FILES += qapi/qapi-visit-job.h qapi/qapi-visit-job.c + GENERATED_FILES += qapi/qapi-visit-migration.h qapi/qapi-visit-migration.c + GENERATED_FILES += qapi/qapi-visit-misc.h qapi/qapi-visit-misc.c + GENERATED_FILES += qapi/qapi-visit-net.h qapi/qapi-visit-net.c +@@ -133,6 +135,7 @@ GENERATED_FILES += qapi/qapi-commands-char.h qapi/qapi-commands-char.c + GENERATED_FILES += qapi/qapi-commands-common.h qapi/qapi-commands-common.c + GENERATED_FILES += qapi/qapi-commands-crypto.h qapi/qapi-commands-crypto.c + GENERATED_FILES += qapi/qapi-commands-introspect.h qapi/qapi-commands-introspect.c ++GENERATED_FILES += qapi/qapi-commands-job.h qapi/qapi-commands-job.c + GENERATED_FILES += qapi/qapi-commands-migration.h qapi/qapi-commands-migration.c + GENERATED_FILES += qapi/qapi-commands-misc.h qapi/qapi-commands-misc.c + GENERATED_FILES += qapi/qapi-commands-net.h qapi/qapi-commands-net.c +@@ -150,6 +153,7 @@ GENERATED_FILES += qapi/qapi-events-char.h qapi/qapi-events-char.c + GENERATED_FILES += qapi/qapi-events-common.h qapi/qapi-events-common.c + GENERATED_FILES += qapi/qapi-events-crypto.h qapi/qapi-events-crypto.c + GENERATED_FILES += qapi/qapi-events-introspect.h qapi/qapi-events-introspect.c ++GENERATED_FILES += qapi/qapi-events-job.h qapi/qapi-events-job.c + GENERATED_FILES += qapi/qapi-events-migration.h qapi/qapi-events-migration.c + GENERATED_FILES += qapi/qapi-events-misc.h qapi/qapi-events-misc.c + GENERATED_FILES += qapi/qapi-events-net.h qapi/qapi-events-net.c +@@ -585,6 +589,7 @@ qapi-modules = $(SRC_PATH)/qapi/qapi-schema.json $(SRC_PATH)/qapi/common.json \ + $(SRC_PATH)/qapi/char.json \ + $(SRC_PATH)/qapi/crypto.json \ + $(SRC_PATH)/qapi/introspect.json \ ++ $(SRC_PATH)/qapi/job.json \ + $(SRC_PATH)/qapi/migration.json \ + $(SRC_PATH)/qapi/misc.json \ + $(SRC_PATH)/qapi/net.json \ +@@ -604,6 +609,7 @@ qapi/qapi-types-char.c qapi/qapi-types-char.h \ + qapi/qapi-types-common.c qapi/qapi-types-common.h \ + qapi/qapi-types-crypto.c qapi/qapi-types-crypto.h \ + qapi/qapi-types-introspect.c qapi/qapi-types-introspect.h \ ++qapi/qapi-types-job.c qapi/qapi-types-job.h \ + qapi/qapi-types-migration.c qapi/qapi-types-migration.h \ + qapi/qapi-types-misc.c qapi/qapi-types-misc.h \ + qapi/qapi-types-net.c qapi/qapi-types-net.h \ +@@ -622,6 +628,7 @@ qapi/qapi-visit-char.c qapi/qapi-visit-char.h \ + qapi/qapi-visit-common.c qapi/qapi-visit-common.h \ + qapi/qapi-visit-crypto.c qapi/qapi-visit-crypto.h \ + qapi/qapi-visit-introspect.c qapi/qapi-visit-introspect.h \ ++qapi/qapi-visit-job.c qapi/qapi-visit-job.h \ + qapi/qapi-visit-migration.c qapi/qapi-visit-migration.h \ + qapi/qapi-visit-misc.c qapi/qapi-visit-misc.h \ + qapi/qapi-visit-net.c qapi/qapi-visit-net.h \ +@@ -639,6 +646,7 @@ qapi/qapi-commands-char.c qapi/qapi-commands-char.h \ + qapi/qapi-commands-common.c qapi/qapi-commands-common.h \ + qapi/qapi-commands-crypto.c qapi/qapi-commands-crypto.h \ + qapi/qapi-commands-introspect.c qapi/qapi-commands-introspect.h \ ++qapi/qapi-commands-job.c qapi/qapi-commands-job.h \ + qapi/qapi-commands-migration.c qapi/qapi-commands-migration.h \ + qapi/qapi-commands-misc.c qapi/qapi-commands-misc.h \ + qapi/qapi-commands-net.c qapi/qapi-commands-net.h \ +@@ -656,6 +664,7 @@ qapi/qapi-events-char.c qapi/qapi-events-char.h \ + qapi/qapi-events-common.c qapi/qapi-events-common.h \ + qapi/qapi-events-crypto.c qapi/qapi-events-crypto.h \ + qapi/qapi-events-introspect.c qapi/qapi-events-introspect.h \ ++qapi/qapi-events-job.c qapi/qapi-events-job.h \ + qapi/qapi-events-migration.c qapi/qapi-events-migration.h \ + qapi/qapi-events-misc.c qapi/qapi-events-misc.h \ + qapi/qapi-events-net.c qapi/qapi-events-net.h \ +diff --git a/Makefile.objs b/Makefile.objs +index 92b73fc..3df8d58 100644 +--- a/Makefile.objs ++++ b/Makefile.objs +@@ -10,6 +10,7 @@ util-obj-y += qapi/qapi-types-char.o + util-obj-y += qapi/qapi-types-common.o + util-obj-y += qapi/qapi-types-crypto.o + util-obj-y += qapi/qapi-types-introspect.o ++util-obj-y += qapi/qapi-types-job.o + util-obj-y += qapi/qapi-types-migration.o + util-obj-y += qapi/qapi-types-misc.o + util-obj-y += qapi/qapi-types-net.o +@@ -28,6 +29,7 @@ util-obj-y += qapi/qapi-visit-char.o + util-obj-y += qapi/qapi-visit-common.o + util-obj-y += qapi/qapi-visit-crypto.o + util-obj-y += qapi/qapi-visit-introspect.o ++util-obj-y += qapi/qapi-visit-job.o + util-obj-y += qapi/qapi-visit-migration.o + util-obj-y += qapi/qapi-visit-misc.o + util-obj-y += qapi/qapi-visit-net.o +@@ -45,6 +47,7 @@ util-obj-y += qapi/qapi-events-char.o + util-obj-y += qapi/qapi-events-common.o + util-obj-y += qapi/qapi-events-crypto.o + util-obj-y += qapi/qapi-events-introspect.o ++util-obj-y += qapi/qapi-events-job.o + util-obj-y += qapi/qapi-events-migration.o + util-obj-y += qapi/qapi-events-misc.o + util-obj-y += qapi/qapi-events-net.o +@@ -140,6 +143,7 @@ common-obj-y += qapi/qapi-commands-char.o + common-obj-y += qapi/qapi-commands-common.o + common-obj-y += qapi/qapi-commands-crypto.o + common-obj-y += qapi/qapi-commands-introspect.o ++common-obj-y += qapi/qapi-commands-job.o + common-obj-y += qapi/qapi-commands-migration.o + common-obj-y += qapi/qapi-commands-misc.o + common-obj-y += qapi/qapi-commands-net.o +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 85bf353..67e613a 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -6,6 +6,7 @@ + + { 'include': 'common.json' } + { 'include': 'crypto.json' } ++{ 'include': 'job.json' } + { 'include': 'sockets.json' } + + ## +@@ -1050,95 +1051,6 @@ + 'data': ['top', 'full', 'none', 'incremental'] } + + ## +-# @JobType: +-# +-# Type of a background job. +-# +-# @commit: block commit job type, see "block-commit" +-# +-# @stream: block stream job type, see "block-stream" +-# +-# @mirror: drive mirror job type, see "drive-mirror" +-# +-# @backup: drive backup job type, see "drive-backup" +-# +-# Since: 1.7 +-## +-{ 'enum': 'JobType', +- 'data': ['commit', 'stream', 'mirror', 'backup'] } +- +-## +-# @JobVerb: +-# +-# Represents command verbs that can be applied to a job. +-# +-# @cancel: see @block-job-cancel +-# +-# @pause: see @block-job-pause +-# +-# @resume: see @block-job-resume +-# +-# @set-speed: see @block-job-set-speed +-# +-# @complete: see @block-job-complete +-# +-# @dismiss: see @block-job-dismiss +-# +-# @finalize: see @block-job-finalize +-# +-# Since: 2.12 +-## +-{ 'enum': 'JobVerb', +- 'data': ['cancel', 'pause', 'resume', 'set-speed', 'complete', 'dismiss', +- 'finalize' ] } +- +-## +-# @JobStatus: +-# +-# Indicates the present state of a given job in its lifetime. +-# +-# @undefined: Erroneous, default state. Should not ever be visible. +-# +-# @created: The job has been created, but not yet started. +-# +-# @running: The job is currently running. +-# +-# @paused: The job is running, but paused. The pause may be requested by +-# either the QMP user or by internal processes. +-# +-# @ready: The job is running, but is ready for the user to signal completion. +-# This is used for long-running jobs like mirror that are designed to +-# run indefinitely. +-# +-# @standby: The job is ready, but paused. This is nearly identical to @paused. +-# The job may return to @ready or otherwise be canceled. +-# +-# @waiting: The job is waiting for other jobs in the transaction to converge +-# to the waiting state. This status will likely not be visible for +-# the last job in a transaction. +-# +-# @pending: The job has finished its work, but has finalization steps that it +-# needs to make prior to completing. These changes may require +-# manual intervention by the management process if manual was set +-# to true. These changes may still fail. +-# +-# @aborting: The job is in the process of being aborted, and will finish with +-# an error. The job will afterwards report that it is @concluded. +-# This status may not be visible to the management process. +-# +-# @concluded: The job has finished all work. If manual was set to true, the job +-# will remain in the query list until it is dismissed. +-# +-# @null: The job is in the process of being dismantled. This state should not +-# ever be visible externally. +-# +-# Since: 2.12 +-## +-{ 'enum': 'JobStatus', +- 'data': ['undefined', 'created', 'running', 'paused', 'ready', 'standby', +- 'waiting', 'pending', 'aborting', 'concluded', 'null' ] } +- +-## + # @BlockJobInfo: + # + # Information about a long-running block device operation. +diff --git a/qapi/job.json b/qapi/job.json +new file mode 100644 +index 0000000..a472c0c +--- /dev/null ++++ b/qapi/job.json +@@ -0,0 +1,94 @@ ++# -*- Mode: Python -*- ++ ++## ++# == Background jobs ++## ++ ++## ++# @JobType: ++# ++# Type of a background job. ++# ++# @commit: block commit job type, see "block-commit" ++# ++# @stream: block stream job type, see "block-stream" ++# ++# @mirror: drive mirror job type, see "drive-mirror" ++# ++# @backup: drive backup job type, see "drive-backup" ++# ++# Since: 1.7 ++## ++{ 'enum': 'JobType', ++ 'data': ['commit', 'stream', 'mirror', 'backup'] } ++ ++## ++# @JobStatus: ++# ++# Indicates the present state of a given job in its lifetime. ++# ++# @undefined: Erroneous, default state. Should not ever be visible. ++# ++# @created: The job has been created, but not yet started. ++# ++# @running: The job is currently running. ++# ++# @paused: The job is running, but paused. The pause may be requested by ++# either the QMP user or by internal processes. ++# ++# @ready: The job is running, but is ready for the user to signal completion. ++# This is used for long-running jobs like mirror that are designed to ++# run indefinitely. ++# ++# @standby: The job is ready, but paused. This is nearly identical to @paused. ++# The job may return to @ready or otherwise be canceled. ++# ++# @waiting: The job is waiting for other jobs in the transaction to converge ++# to the waiting state. This status will likely not be visible for ++# the last job in a transaction. ++# ++# @pending: The job has finished its work, but has finalization steps that it ++# needs to make prior to completing. These changes may require ++# manual intervention by the management process if manual was set ++# to true. These changes may still fail. ++# ++# @aborting: The job is in the process of being aborted, and will finish with ++# an error. The job will afterwards report that it is @concluded. ++# This status may not be visible to the management process. ++# ++# @concluded: The job has finished all work. If manual was set to true, the job ++# will remain in the query list until it is dismissed. ++# ++# @null: The job is in the process of being dismantled. This state should not ++# ever be visible externally. ++# ++# Since: 2.12 ++## ++{ 'enum': 'JobStatus', ++ 'data': ['undefined', 'created', 'running', 'paused', 'ready', 'standby', ++ 'waiting', 'pending', 'aborting', 'concluded', 'null' ] } ++ ++## ++# @JobVerb: ++# ++# Represents command verbs that can be applied to a job. ++# ++# @cancel: see @block-job-cancel ++# ++# @pause: see @block-job-pause ++# ++# @resume: see @block-job-resume ++# ++# @set-speed: see @block-job-set-speed ++# ++# @complete: see @block-job-complete ++# ++# @dismiss: see @block-job-dismiss ++# ++# @finalize: see @block-job-finalize ++# ++# Since: 2.12 ++## ++{ 'enum': 'JobVerb', ++ 'data': ['cancel', 'pause', 'resume', 'set-speed', 'complete', 'dismiss', ++ 'finalize' ] } +diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json +index 25bce78..65b6dc2 100644 +--- a/qapi/qapi-schema.json ++++ b/qapi/qapi-schema.json +@@ -84,6 +84,7 @@ + { 'include': 'crypto.json' } + { 'include': 'block.json' } + { 'include': 'char.json' } ++{ 'include': 'job.json' } + { 'include': 'net.json' } + { 'include': 'rocker.json' } + { 'include': 'tpm.json' } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Maintain-a-list-of-all-jobs.patch b/SOURCES/kvm-job-Maintain-a-list-of-all-jobs.patch new file mode 100644 index 0000000..27f6bfc --- /dev/null +++ b/SOURCES/kvm-job-Maintain-a-list-of-all-jobs.patch @@ -0,0 +1,262 @@ +From 40315feeaa8186057e85d18aa653a0916dc55bfd Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:03 +0200 +Subject: [PATCH 34/89] job: Maintain a list of all jobs + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-21-kwolf@redhat.com> +Patchwork-id: 81105 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 20/73] job: Maintain a list of all jobs +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This moves the job list from BlockJob to Job. Now we can check for +duplicate IDs in job_create(). + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +Reviewed-by: John Snow +(cherry picked from commit e7c1d78bbd5867804debeb7159b137fd9a6c44d3) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + blockjob.c | 46 ++++++++++++++++++++++++---------------------- + include/block/blockjob.h | 3 --- + include/qemu/job.h | 19 +++++++++++++++++++ + job.c | 31 +++++++++++++++++++++++++++++++ + 4 files changed, 74 insertions(+), 25 deletions(-) + +diff --git a/blockjob.c b/blockjob.c +index 430a67b..c69b2e7 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -129,8 +129,6 @@ struct BlockJobTxn { + int refcnt; + }; + +-static QLIST_HEAD(, BlockJob) block_jobs = QLIST_HEAD_INITIALIZER(block_jobs); +- + /* + * The block job API is composed of two categories of functions. + * +@@ -146,25 +144,34 @@ static QLIST_HEAD(, BlockJob) block_jobs = QLIST_HEAD_INITIALIZER(block_jobs); + * blockjob_int.h. + */ + +-BlockJob *block_job_next(BlockJob *job) ++static bool is_block_job(Job *job) + { +- if (!job) { +- return QLIST_FIRST(&block_jobs); +- } +- return QLIST_NEXT(job, job_list); ++ return job_type(job) == JOB_TYPE_BACKUP || ++ job_type(job) == JOB_TYPE_COMMIT || ++ job_type(job) == JOB_TYPE_MIRROR || ++ job_type(job) == JOB_TYPE_STREAM; ++} ++ ++BlockJob *block_job_next(BlockJob *bjob) ++{ ++ Job *job = bjob ? &bjob->job : NULL; ++ ++ do { ++ job = job_next(job); ++ } while (job && !is_block_job(job)); ++ ++ return job ? container_of(job, BlockJob, job) : NULL; + } + + BlockJob *block_job_get(const char *id) + { +- BlockJob *job; ++ Job *job = job_get(id); + +- QLIST_FOREACH(job, &block_jobs, job_list) { +- if (job->job.id && !strcmp(id, job->job.id)) { +- return job; +- } ++ if (job && is_block_job(job)) { ++ return container_of(job, BlockJob, job); ++ } else { ++ return NULL; + } +- +- return NULL; + } + + BlockJobTxn *block_job_txn_new(void) +@@ -253,7 +260,6 @@ void block_job_unref(BlockJob *job) + assert(job->status == BLOCK_JOB_STATUS_NULL); + assert(!job->txn); + BlockDriverState *bs = blk_bs(job->blk); +- QLIST_REMOVE(job, job_list); + bs->job = NULL; + block_job_remove_all_bdrv(job); + blk_remove_aio_context_notifier(job->blk, +@@ -812,7 +818,7 @@ void block_job_cancel_sync_all(void) + BlockJob *job; + AioContext *aio_context; + +- while ((job = QLIST_FIRST(&block_jobs))) { ++ while ((job = block_job_next(NULL))) { + aio_context = blk_get_aio_context(job->blk); + aio_context_acquire(aio_context); + block_job_cancel_sync(job); +@@ -942,10 +948,6 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + error_setg(errp, "Cannot specify job ID for internal block job"); + return NULL; + } +- if (block_job_get(job_id)) { +- error_setg(errp, "Job ID '%s' already in use", job_id); +- return NULL; +- } + } + + blk = blk_new(perm, shared_perm); +@@ -961,6 +963,8 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + return NULL; + } + ++ assert(is_block_job(&job->job)); ++ + job->driver = driver; + job->blk = blk; + job->cb = cb; +@@ -983,8 +987,6 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + + bdrv_op_unblock(bs, BLOCK_OP_TYPE_DATAPLANE, job->blocker); + +- QLIST_INSERT_HEAD(&block_jobs, job, job_list); +- + blk_add_aio_context_notifier(blk, block_job_attached_aio_context, + block_job_detach_aio_context, job); + +diff --git a/include/block/blockjob.h b/include/block/blockjob.h +index 640e649..10bd9f7 100644 +--- a/include/block/blockjob.h ++++ b/include/block/blockjob.h +@@ -105,9 +105,6 @@ typedef struct BlockJob { + */ + bool deferred_to_main_loop; + +- /** Element of the list of block jobs */ +- QLIST_ENTRY(BlockJob) job_list; +- + /** Status that is published by the query-block-jobs QMP API */ + BlockDeviceIoStatus iostatus; + +diff --git a/include/qemu/job.h b/include/qemu/job.h +index 43dc2e4..bae2b09 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -27,6 +27,7 @@ + #define JOB_H + + #include "qapi/qapi-types-block-core.h" ++#include "qemu/queue.h" + + typedef struct JobDriver JobDriver; + +@@ -39,6 +40,9 @@ typedef struct Job { + + /** The type of this job. */ + const JobDriver *driver; ++ ++ /** Element of the list of jobs */ ++ QLIST_ENTRY(Job) job_list; + } Job; + + /** +@@ -71,4 +75,19 @@ JobType job_type(const Job *job); + /** Returns the enum string for the JobType of a given Job. */ + const char *job_type_str(const Job *job); + ++/** ++ * Get the next element from the list of block jobs after @job, or the ++ * first one if @job is %NULL. ++ * ++ * Returns the requested job, or %NULL if there are no more jobs left. ++ */ ++Job *job_next(Job *job); ++ ++/** ++ * Get the job identified by @id (which must not be %NULL). ++ * ++ * Returns the requested job, or %NULL if it doesn't exist. ++ */ ++Job *job_get(const char *id); ++ + #endif +diff --git a/job.c b/job.c +index cfdd008..e57303c 100644 +--- a/job.c ++++ b/job.c +@@ -29,6 +29,8 @@ + #include "qemu/job.h" + #include "qemu/id.h" + ++static QLIST_HEAD(, Job) jobs = QLIST_HEAD_INITIALIZER(jobs); ++ + JobType job_type(const Job *job) + { + return job->driver->job_type; +@@ -39,6 +41,27 @@ const char *job_type_str(const Job *job) + return JobType_str(job_type(job)); + } + ++Job *job_next(Job *job) ++{ ++ if (!job) { ++ return QLIST_FIRST(&jobs); ++ } ++ return QLIST_NEXT(job, job_list); ++} ++ ++Job *job_get(const char *id) ++{ ++ Job *job; ++ ++ QLIST_FOREACH(job, &jobs, job_list) { ++ if (job->id && !strcmp(id, job->id)) { ++ return job; ++ } ++ } ++ ++ return NULL; ++} ++ + void *job_create(const char *job_id, const JobDriver *driver, Error **errp) + { + Job *job; +@@ -48,17 +71,25 @@ void *job_create(const char *job_id, const JobDriver *driver, Error **errp) + error_setg(errp, "Invalid job ID '%s'", job_id); + return NULL; + } ++ if (job_get(job_id)) { ++ error_setg(errp, "Job ID '%s' already in use", job_id); ++ return NULL; ++ } + } + + job = g_malloc0(driver->instance_size); + job->driver = driver; + job->id = g_strdup(job_id); + ++ QLIST_INSERT_HEAD(&jobs, job, job_list); ++ + return job; + } + + void job_delete(Job *job) + { ++ QLIST_REMOVE(job, job_list); ++ + g_free(job->id); + g_free(job); + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Move-.complete-callback-to-Job.patch b/SOURCES/kvm-job-Move-.complete-callback-to-Job.patch new file mode 100644 index 0000000..efb600a --- /dev/null +++ b/SOURCES/kvm-job-Move-.complete-callback-to-Job.patch @@ -0,0 +1,298 @@ +From dcfc2f6514b672e68b62effbbc04c88ca16ac89a Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:19 +0200 +Subject: [PATCH 50/89] job: Move .complete callback to Job + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-37-kwolf@redhat.com> +Patchwork-id: 81084 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 36/73] job: Move .complete callback to Job +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This moves the .complete callback that tells a READY job to complete +from BlockJobDriver to JobDriver. The wrapper function job_complete() +doesn't require anything block job specific any more and can be moved +to Job. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +(cherry picked from commit 3453d97243c72988c89a0105fa9546890eae7bd4) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/mirror.c | 10 +++++----- + blockdev.c | 2 +- + blockjob.c | 23 +++++------------------ + include/block/blockjob.h | 10 ---------- + include/block/blockjob_int.h | 6 ------ + include/qemu/job.h | 8 ++++++++ + job.c | 16 ++++++++++++++++ + tests/test-bdrv-drain.c | 6 +++--- + tests/test-blockjob.c | 10 +++++----- + 9 files changed, 43 insertions(+), 48 deletions(-) + +diff --git a/block/mirror.c b/block/mirror.c +index a579bd8..656237a 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -905,16 +905,16 @@ immediate_exit: + job_defer_to_main_loop(&s->common.job, mirror_exit, data); + } + +-static void mirror_complete(BlockJob *job, Error **errp) ++static void mirror_complete(Job *job, Error **errp) + { +- MirrorBlockJob *s = container_of(job, MirrorBlockJob, common); ++ MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job); + BlockDriverState *target; + + target = blk_bs(s->target); + + if (!s->synced) { + error_setg(errp, "The active block job '%s' cannot be completed", +- job->job.id); ++ job->id); + return; + } + +@@ -995,8 +995,8 @@ static const BlockJobDriver mirror_job_driver = { + .drain = block_job_drain, + .start = mirror_run, + .pause = mirror_pause, ++ .complete = mirror_complete, + }, +- .complete = mirror_complete, + .attached_aio_context = mirror_attached_aio_context, + .drain = mirror_drain, + }; +@@ -1010,8 +1010,8 @@ static const BlockJobDriver commit_active_job_driver = { + .drain = block_job_drain, + .start = mirror_run, + .pause = mirror_pause, ++ .complete = mirror_complete, + }, +- .complete = mirror_complete, + .attached_aio_context = mirror_attached_aio_context, + .drain = mirror_drain, + }; +diff --git a/blockdev.c b/blockdev.c +index 89df7d9..c2b2be1 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -3941,7 +3941,7 @@ void qmp_block_job_complete(const char *device, Error **errp) + } + + trace_qmp_block_job_complete(job); +- block_job_complete(job, errp); ++ job_complete(&job->job, errp); + aio_context_release(aio_context); + } + +diff --git a/blockjob.c b/blockjob.c +index 63e1669..0ca7672 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -481,24 +481,6 @@ int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n) + return ratelimit_calculate_delay(&job->limit, n); + } + +-void block_job_complete(BlockJob *job, Error **errp) +-{ +- /* Should not be reachable via external interface for internal jobs */ +- assert(job->job.id); +- if (job_apply_verb(&job->job, JOB_VERB_COMPLETE, errp)) { +- return; +- } +- if (job->job.pause_count || job_is_cancelled(&job->job) || +- !job->driver->complete) +- { +- error_setg(errp, "The active block job '%s' cannot be completed", +- job->job.id); +- return; +- } +- +- job->driver->complete(job, errp); +-} +- + void block_job_finalize(BlockJob *job, Error **errp) + { + assert(job && job->job.id); +@@ -571,6 +553,11 @@ void block_job_cancel_sync_all(void) + } + } + ++static void block_job_complete(BlockJob *job, Error **errp) ++{ ++ job_complete(&job->job, errp); ++} ++ + int block_job_complete_sync(BlockJob *job, Error **errp) + { + return block_job_finish_sync(job, &block_job_complete, errp); +diff --git a/include/block/blockjob.h b/include/block/blockjob.h +index d975efe..85ce18a 100644 +--- a/include/block/blockjob.h ++++ b/include/block/blockjob.h +@@ -154,16 +154,6 @@ void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp); + void block_job_cancel(BlockJob *job, bool force); + + /** +- * block_job_complete: +- * @job: The job to be completed. +- * @errp: Error object. +- * +- * Asynchronously complete the specified job. +- */ +-void block_job_complete(BlockJob *job, Error **errp); +- +- +-/** + * block_job_finalize: + * @job: The job to fully commit and finish. + * @errp: Error object. +diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h +index 38fe22d..b8ca7bb 100644 +--- a/include/block/blockjob_int.h ++++ b/include/block/blockjob_int.h +@@ -39,12 +39,6 @@ struct BlockJobDriver { + JobDriver job_driver; + + /** +- * Optional callback for job types whose completion must be triggered +- * manually. +- */ +- void (*complete)(BlockJob *job, Error **errp); +- +- /** + * If the callback is not NULL, prepare will be invoked when all the jobs + * belonging to the same transaction complete; or upon this job's completion + * if it is not in a transaction. +diff --git a/include/qemu/job.h b/include/qemu/job.h +index aebc195..8f7f71a 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -167,6 +167,12 @@ struct JobDriver { + */ + void (*user_resume)(Job *job); + ++ /** ++ * Optional callback for job types whose completion must be triggered ++ * manually. ++ */ ++ void (*complete)(Job *job, Error **errp); ++ + /* + * If the callback is not NULL, it will be invoked when the job has to be + * synchronously cancelled or completed; it should drain any activities +@@ -363,6 +369,8 @@ int job_apply_verb(Job *job, JobVerb verb, Error **errp); + /** The @job could not be started, free it. */ + void job_early_fail(Job *job); + ++/** Asynchronously complete the specified @job. */ ++void job_complete(Job *job, Error **errp);; + + typedef void JobDeferToMainLoopFn(Job *job, void *opaque); + +diff --git a/job.c b/job.c +index 3772a35..8ceac0b 100644 +--- a/job.c ++++ b/job.c +@@ -556,6 +556,22 @@ int job_finalize_single(Job *job) + return 0; + } + ++void job_complete(Job *job, Error **errp) ++{ ++ /* Should not be reachable via external interface for internal jobs */ ++ assert(job->id); ++ if (job_apply_verb(job, JOB_VERB_COMPLETE, errp)) { ++ return; ++ } ++ if (job->pause_count || job_is_cancelled(job) || !job->driver->complete) { ++ error_setg(errp, "The active block job '%s' cannot be completed", ++ job->id); ++ return; ++ } ++ ++ job->driver->complete(job, errp); ++} ++ + + typedef struct { + Job *job; +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index 58ea566..b428aac 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -514,9 +514,9 @@ static void coroutine_fn test_job_start(void *opaque) + job_defer_to_main_loop(&s->common.job, test_job_completed, NULL); + } + +-static void test_job_complete(BlockJob *job, Error **errp) ++static void test_job_complete(Job *job, Error **errp) + { +- TestBlockJob *s = container_of(job, TestBlockJob, common); ++ TestBlockJob *s = container_of(job, TestBlockJob, common.job); + s->should_complete = true; + } + +@@ -527,8 +527,8 @@ BlockJobDriver test_job_driver = { + .user_resume = block_job_user_resume, + .drain = block_job_drain, + .start = test_job_start, ++ .complete = test_job_complete, + }, +- .complete = test_job_complete, + }; + + static void test_blockjob_common(enum drain_type drain_type) +diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c +index 592a136..e44c608 100644 +--- a/tests/test-blockjob.c ++++ b/tests/test-blockjob.c +@@ -171,9 +171,9 @@ static void cancel_job_completed(Job *job, void *opaque) + block_job_completed(bjob, 0); + } + +-static void cancel_job_complete(BlockJob *job, Error **errp) ++static void cancel_job_complete(Job *job, Error **errp) + { +- CancelJob *s = container_of(job, CancelJob, common); ++ CancelJob *s = container_of(job, CancelJob, common.job); + s->should_complete = true; + } + +@@ -204,8 +204,8 @@ static const BlockJobDriver test_cancel_driver = { + .user_resume = block_job_user_resume, + .drain = block_job_drain, + .start = cancel_job_start, ++ .complete = cancel_job_complete, + }, +- .complete = cancel_job_complete, + }; + + static CancelJob *create_common(BlockJob **pjob) +@@ -333,7 +333,7 @@ static void test_cancel_pending(void) + block_job_enter(job); + assert(job->job.status == JOB_STATUS_READY); + +- block_job_complete(job, &error_abort); ++ job_complete(&job->job, &error_abort); + block_job_enter(job); + while (!s->completed) { + aio_poll(qemu_get_aio_context(), true); +@@ -357,7 +357,7 @@ static void test_cancel_concluded(void) + block_job_enter(job); + assert(job->job.status == JOB_STATUS_READY); + +- block_job_complete(job, &error_abort); ++ job_complete(&job->job, &error_abort); + block_job_enter(job); + while (!s->completed) { + aio_poll(qemu_get_aio_context(), true); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Move-BlockJobCreateFlags-to-Job.patch b/SOURCES/kvm-job-Move-BlockJobCreateFlags-to-Job.patch new file mode 100644 index 0000000..40b0663 --- /dev/null +++ b/SOURCES/kvm-job-Move-BlockJobCreateFlags-to-Job.patch @@ -0,0 +1,423 @@ +From 4d3f866a590d0c5005bd864cc2ee7bb8187f6dbb Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:13 +0200 +Subject: [PATCH 44/89] job: Move BlockJobCreateFlags to Job + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-31-kwolf@redhat.com> +Patchwork-id: 81106 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 30/73] job: Move BlockJobCreateFlags to Job +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This renames the BlockJobCreateFlags constants, moves a few JOB_INTERNAL +checks to job_create() and the auto_{finalize,dismiss} fields from +BlockJob to Job. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +(cherry picked from commit bb02b65c7d57e4f2136f39bfba95cc68d89eb216) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/commit.c | 2 +- + block/mirror.c | 2 +- + block/replication.c | 4 ++-- + block/stream.c | 2 +- + blockdev.c | 14 +++++++------- + blockjob.c | 27 +++++++-------------------- + include/block/blockjob.h | 17 ----------------- + include/block/blockjob_int.h | 3 +-- + include/qemu/job.h | 20 +++++++++++++++++++- + job.c | 11 ++++++++++- + qemu-img.c | 2 +- + tests/test-blockjob-txn.c | 2 +- + tests/test-blockjob.c | 4 ++-- + 13 files changed, 53 insertions(+), 57 deletions(-) + +diff --git a/block/commit.c b/block/commit.c +index c4a98e5..7a6ae59 100644 +--- a/block/commit.c ++++ b/block/commit.c +@@ -282,7 +282,7 @@ void commit_start(const char *job_id, BlockDriverState *bs, + } + + s = block_job_create(job_id, &commit_job_driver, NULL, bs, 0, BLK_PERM_ALL, +- speed, BLOCK_JOB_DEFAULT, NULL, NULL, errp); ++ speed, JOB_DEFAULT, NULL, NULL, errp); + if (!s) { + return; + } +diff --git a/block/mirror.c b/block/mirror.c +index 9a7226f..5091e72 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -1284,7 +1284,7 @@ void mirror_start(const char *job_id, BlockDriverState *bs, + } + is_none_mode = mode == MIRROR_SYNC_MODE_NONE; + base = mode == MIRROR_SYNC_MODE_TOP ? backing_bs(bs) : NULL; +- mirror_start_job(job_id, bs, BLOCK_JOB_DEFAULT, target, replaces, ++ mirror_start_job(job_id, bs, JOB_DEFAULT, target, replaces, + speed, granularity, buf_size, backing_mode, + on_source_error, on_target_error, unmap, NULL, NULL, + &mirror_job_driver, is_none_mode, base, false, +diff --git a/block/replication.c b/block/replication.c +index 3f7500e..8241400 100644 +--- a/block/replication.c ++++ b/block/replication.c +@@ -566,7 +566,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, + job = backup_job_create(NULL, s->secondary_disk->bs, s->hidden_disk->bs, + 0, MIRROR_SYNC_MODE_NONE, NULL, false, + BLOCKDEV_ON_ERROR_REPORT, +- BLOCKDEV_ON_ERROR_REPORT, BLOCK_JOB_INTERNAL, ++ BLOCKDEV_ON_ERROR_REPORT, JOB_INTERNAL, + backup_job_completed, bs, NULL, &local_err); + if (local_err) { + error_propagate(errp, local_err); +@@ -691,7 +691,7 @@ static void replication_stop(ReplicationState *rs, bool failover, Error **errp) + + s->stage = BLOCK_REPLICATION_FAILOVER; + commit_active_start(NULL, s->active_disk->bs, s->secondary_disk->bs, +- BLOCK_JOB_INTERNAL, 0, BLOCKDEV_ON_ERROR_REPORT, ++ JOB_INTERNAL, 0, BLOCKDEV_ON_ERROR_REPORT, + NULL, replication_done, bs, true, errp); + break; + default: +diff --git a/block/stream.c b/block/stream.c +index e81b488..eee0253 100644 +--- a/block/stream.c ++++ b/block/stream.c +@@ -242,7 +242,7 @@ void stream_start(const char *job_id, BlockDriverState *bs, + BLK_PERM_GRAPH_MOD, + BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED | + BLK_PERM_WRITE, +- speed, BLOCK_JOB_DEFAULT, NULL, NULL, errp); ++ speed, JOB_DEFAULT, NULL, NULL, errp); + if (!s) { + goto fail; + } +diff --git a/blockdev.c b/blockdev.c +index 0fa1990..89df7d9 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -3291,7 +3291,7 @@ void qmp_block_commit(bool has_job_id, const char *job_id, const char *device, + goto out; + } + commit_active_start(has_job_id ? job_id : NULL, bs, base_bs, +- BLOCK_JOB_DEFAULT, speed, on_error, ++ JOB_DEFAULT, speed, on_error, + filter_node_name, NULL, NULL, false, &local_err); + } else { + BlockDriverState *overlay_bs = bdrv_find_overlay(bs, top_bs); +@@ -3322,7 +3322,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn, + AioContext *aio_context; + QDict *options = NULL; + Error *local_err = NULL; +- int flags, job_flags = BLOCK_JOB_DEFAULT; ++ int flags, job_flags = JOB_DEFAULT; + int64_t size; + bool set_backing_hd = false; + +@@ -3445,10 +3445,10 @@ static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn, + } + } + if (!backup->auto_finalize) { +- job_flags |= BLOCK_JOB_MANUAL_FINALIZE; ++ job_flags |= JOB_MANUAL_FINALIZE; + } + if (!backup->auto_dismiss) { +- job_flags |= BLOCK_JOB_MANUAL_DISMISS; ++ job_flags |= JOB_MANUAL_DISMISS; + } + + job = backup_job_create(backup->job_id, bs, target_bs, backup->speed, +@@ -3489,7 +3489,7 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn, + Error *local_err = NULL; + AioContext *aio_context; + BlockJob *job = NULL; +- int job_flags = BLOCK_JOB_DEFAULT; ++ int job_flags = JOB_DEFAULT; + + if (!backup->has_speed) { + backup->speed = 0; +@@ -3538,10 +3538,10 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn, + } + } + if (!backup->auto_finalize) { +- job_flags |= BLOCK_JOB_MANUAL_FINALIZE; ++ job_flags |= JOB_MANUAL_FINALIZE; + } + if (!backup->auto_dismiss) { +- job_flags |= BLOCK_JOB_MANUAL_DISMISS; ++ job_flags |= JOB_MANUAL_DISMISS; + } + job = backup_job_create(backup->job_id, bs, target_bs, backup->speed, + backup->sync, NULL, backup->compress, +diff --git a/blockjob.c b/blockjob.c +index a1d1f48..d9d8ff7 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -285,7 +285,7 @@ static void block_job_do_dismiss(BlockJob *job) + static void block_job_conclude(BlockJob *job) + { + job_state_transition(&job->job, JOB_STATUS_CONCLUDED); +- if (job->auto_dismiss || !job_started(&job->job)) { ++ if (job->job.auto_dismiss || !job_started(&job->job)) { + block_job_do_dismiss(job); + } + } +@@ -483,7 +483,7 @@ static void block_job_completed_txn_abort(BlockJob *job) + + static int block_job_needs_finalize(BlockJob *job) + { +- return !job->auto_finalize; ++ return !job->job.auto_finalize; + } + + static void block_job_do_finalize(BlockJob *job) +@@ -688,8 +688,8 @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp) + info->io_status = job->iostatus; + info->ready = job->ready; + info->status = job->job.status; +- info->auto_finalize = job->auto_finalize; +- info->auto_dismiss = job->auto_dismiss; ++ info->auto_finalize = job->job.auto_finalize; ++ info->auto_dismiss = job->job.auto_dismiss; + info->has_error = job->ret != 0; + info->error = job->ret ? g_strdup(strerror(-job->ret)) : NULL; + return info; +@@ -736,7 +736,7 @@ static void block_job_event_completed(BlockJob *job, const char *msg) + static int block_job_event_pending(BlockJob *job) + { + job_state_transition(&job->job, JOB_STATUS_PENDING); +- if (!job->auto_finalize && !block_job_is_internal(job)) { ++ if (!job->job.auto_finalize && !block_job_is_internal(job)) { + qapi_event_send_block_job_pending(job_type(&job->job), + job->job.id, + &error_abort); +@@ -763,19 +763,8 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + return NULL; + } + +- if (job_id == NULL && !(flags & BLOCK_JOB_INTERNAL)) { ++ if (job_id == NULL && !(flags & JOB_INTERNAL)) { + job_id = bdrv_get_device_name(bs); +- if (!*job_id) { +- error_setg(errp, "An explicit job ID is required for this node"); +- return NULL; +- } +- } +- +- if (job_id) { +- if (flags & BLOCK_JOB_INTERNAL) { +- error_setg(errp, "Cannot specify job ID for internal block job"); +- return NULL; +- } + } + + blk = blk_new(perm, shared_perm); +@@ -786,7 +775,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + } + + job = job_create(job_id, &driver->job_driver, blk_get_aio_context(blk), +- errp); ++ flags, errp); + if (job == NULL) { + blk_unref(blk); + return NULL; +@@ -800,8 +789,6 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + job->blk = blk; + job->cb = cb; + job->opaque = opaque; +- job->auto_finalize = !(flags & BLOCK_JOB_MANUAL_FINALIZE); +- job->auto_dismiss = !(flags & BLOCK_JOB_MANUAL_DISMISS); + + error_setg(&job->blocker, "block device is in use by block job: %s", + job_type_str(&job->job)); +diff --git a/include/block/blockjob.h b/include/block/blockjob.h +index 3e94e18..f9aaaaa 100644 +--- a/include/block/blockjob.h ++++ b/include/block/blockjob.h +@@ -91,27 +91,10 @@ typedef struct BlockJob { + /** ret code passed to block_job_completed. */ + int ret; + +- /** True if this job should automatically finalize itself */ +- bool auto_finalize; +- +- /** True if this job should automatically dismiss itself */ +- bool auto_dismiss; +- + BlockJobTxn *txn; + QLIST_ENTRY(BlockJob) txn_list; + } BlockJob; + +-typedef enum BlockJobCreateFlags { +- /* Default behavior */ +- BLOCK_JOB_DEFAULT = 0x00, +- /* BlockJob is not QMP-created and should not send QMP events */ +- BLOCK_JOB_INTERNAL = 0x01, +- /* BlockJob requires manual finalize step */ +- BLOCK_JOB_MANUAL_FINALIZE = 0x02, +- /* BlockJob requires manual dismiss step */ +- BLOCK_JOB_MANUAL_DISMISS = 0x04, +-} BlockJobCreateFlags; +- + /** + * block_job_next: + * @job: A block job, or %NULL. +diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h +index 7e705ae..88639f7 100644 +--- a/include/block/blockjob_int.h ++++ b/include/block/blockjob_int.h +@@ -106,8 +106,7 @@ struct BlockJobDriver { + * @bs: The block + * @perm, @shared_perm: Permissions to request for @bs + * @speed: The maximum speed, in bytes per second, or 0 for unlimited. +- * @flags: Creation flags for the Block Job. +- * See @BlockJobCreateFlags ++ * @flags: Creation flags for the Block Job. See @JobCreateFlags. + * @cb: Completion function for the job. + * @opaque: Opaque pointer value passed to @cb. + * @errp: Error object. +diff --git a/include/qemu/job.h b/include/qemu/job.h +index 858f3be..9783e40 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -99,6 +99,12 @@ typedef struct Job { + /** Set to true when the job has deferred work to the main loop. */ + bool deferred_to_main_loop; + ++ /** True if this job should automatically finalize itself */ ++ bool auto_finalize; ++ ++ /** True if this job should automatically dismiss itself */ ++ bool auto_dismiss; ++ + /** Element of the list of jobs */ + QLIST_ENTRY(Job) job_list; + } Job; +@@ -140,6 +146,17 @@ struct JobDriver { + void (*free)(Job *job); + }; + ++typedef enum JobCreateFlags { ++ /* Default behavior */ ++ JOB_DEFAULT = 0x00, ++ /* Job is not QMP-created and should not send QMP events */ ++ JOB_INTERNAL = 0x01, ++ /* Job requires manual finalize step */ ++ JOB_MANUAL_FINALIZE = 0x02, ++ /* Job requires manual dismiss step */ ++ JOB_MANUAL_DISMISS = 0x04, ++} JobCreateFlags; ++ + + /** + * Create a new long-running job and return it. +@@ -147,10 +164,11 @@ struct JobDriver { + * @job_id: The id of the newly-created job, or %NULL for internal jobs + * @driver: The class object for the newly-created job. + * @ctx: The AioContext to run the job coroutine in. ++ * @flags: Creation flags for the job. See @JobCreateFlags. + * @errp: Error object. + */ + void *job_create(const char *job_id, const JobDriver *driver, AioContext *ctx, +- Error **errp); ++ int flags, Error **errp); + + /** + * Add a reference to Job refcnt, it will be decreased with job_unref, and then +diff --git a/job.c b/job.c +index aaacfcc..dd46170 100644 +--- a/job.c ++++ b/job.c +@@ -182,11 +182,15 @@ static void job_sleep_timer_cb(void *opaque) + } + + void *job_create(const char *job_id, const JobDriver *driver, AioContext *ctx, +- Error **errp) ++ int flags, Error **errp) + { + Job *job; + + if (job_id) { ++ if (flags & JOB_INTERNAL) { ++ error_setg(errp, "Cannot specify job ID for internal job"); ++ return NULL; ++ } + if (!id_wellformed(job_id)) { + error_setg(errp, "Invalid job ID '%s'", job_id); + return NULL; +@@ -195,6 +199,9 @@ void *job_create(const char *job_id, const JobDriver *driver, AioContext *ctx, + error_setg(errp, "Job ID '%s' already in use", job_id); + return NULL; + } ++ } else if (!(flags & JOB_INTERNAL)) { ++ error_setg(errp, "An explicit job ID is required"); ++ return NULL; + } + + job = g_malloc0(driver->instance_size); +@@ -205,6 +212,8 @@ void *job_create(const char *job_id, const JobDriver *driver, AioContext *ctx, + job->busy = false; + job->paused = true; + job->pause_count = 1; ++ job->auto_finalize = !(flags & JOB_MANUAL_FINALIZE); ++ job->auto_dismiss = !(flags & JOB_MANUAL_DISMISS); + + job_state_transition(job, JOB_STATUS_CREATED); + aio_timer_init(qemu_get_aio_context(), &job->sleep_timer, +diff --git a/qemu-img.c b/qemu-img.c +index f5bb0ef..843dc6a 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -1026,7 +1026,7 @@ static int img_commit(int argc, char **argv) + + aio_context = bdrv_get_aio_context(bs); + aio_context_acquire(aio_context); +- commit_active_start("commit", bs, base_bs, BLOCK_JOB_DEFAULT, 0, ++ commit_active_start("commit", bs, base_bs, JOB_DEFAULT, 0, + BLOCKDEV_ON_ERROR_REPORT, NULL, common_block_job_cb, + &cbi, false, &local_err); + aio_context_release(aio_context); +diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c +index 93d1ff0..60e9fa2 100644 +--- a/tests/test-blockjob-txn.c ++++ b/tests/test-blockjob-txn.c +@@ -107,7 +107,7 @@ static BlockJob *test_block_job_start(unsigned int iterations, + + snprintf(job_id, sizeof(job_id), "job%u", counter++); + s = block_job_create(job_id, &test_block_job_driver, txn, bs, +- 0, BLK_PERM_ALL, 0, BLOCK_JOB_DEFAULT, ++ 0, BLK_PERM_ALL, 0, JOB_DEFAULT, + test_block_job_cb, data, &error_abort); + s->iterations = iterations; + s->use_timer = use_timer; +diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c +index ceb5960..8bb0aa8 100644 +--- a/tests/test-blockjob.c ++++ b/tests/test-blockjob.c +@@ -59,7 +59,7 @@ static BlockJob *do_test_id(BlockBackend *blk, const char *id, + bool should_succeed) + { + return mk_job(blk, id, &test_block_job_driver, +- should_succeed, BLOCK_JOB_DEFAULT); ++ should_succeed, JOB_DEFAULT); + } + + /* This creates a BlockBackend (optionally with a name) with a +@@ -214,7 +214,7 @@ static CancelJob *create_common(BlockJob **pjob) + + blk = create_blk(NULL); + job = mk_job(blk, "Steve", &test_cancel_driver, true, +- BLOCK_JOB_MANUAL_FINALIZE | BLOCK_JOB_MANUAL_DISMISS); ++ JOB_MANUAL_FINALIZE | JOB_MANUAL_DISMISS); + job_ref(&job->job); + assert(job->job.status == JOB_STATUS_CREATED); + s = container_of(job, CancelJob, common); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Move-cancelled-to-Job.patch b/SOURCES/kvm-job-Move-cancelled-to-Job.patch new file mode 100644 index 0000000..6c75ba7 --- /dev/null +++ b/SOURCES/kvm-job-Move-cancelled-to-Job.patch @@ -0,0 +1,439 @@ +From e799889203d2f06adac2c1636b15be360e50f5a2 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:06 +0200 +Subject: [PATCH 37/89] job: Move cancelled to Job + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-24-kwolf@redhat.com> +Patchwork-id: 81103 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 23/73] job: Move cancelled to Job +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +We cannot yet move the whole logic around job cancelling to Job because +it depends on quite a few other things that are still only in BlockJob, +but we can move the cancelled field at least. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +Reviewed-by: John Snow +(cherry picked from commit daa7f2f9467bc5624f04f28d4b01b88f08c6589c) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/backup.c | 6 +++--- + block/commit.c | 4 ++-- + block/mirror.c | 20 ++++++++++---------- + block/stream.c | 4 ++-- + blockjob.c | 28 +++++++++++++--------------- + include/block/blockjob.h | 8 -------- + include/block/blockjob_int.h | 8 -------- + include/qemu/job.h | 11 +++++++++++ + job.c | 5 +++++ + tests/test-blockjob-txn.c | 6 +++--- + tests/test-blockjob.c | 2 +- + 11 files changed, 50 insertions(+), 52 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index cfdb89d..ef0aa0e 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -329,7 +329,7 @@ static bool coroutine_fn yield_and_check(BackupBlockJob *job) + { + uint64_t delay_ns; + +- if (block_job_is_cancelled(&job->common)) { ++ if (job_is_cancelled(&job->common.job)) { + return true; + } + +@@ -339,7 +339,7 @@ static bool coroutine_fn yield_and_check(BackupBlockJob *job) + job->bytes_read = 0; + block_job_sleep_ns(&job->common, delay_ns); + +- if (block_job_is_cancelled(&job->common)) { ++ if (job_is_cancelled(&job->common.job)) { + return true; + } + +@@ -441,7 +441,7 @@ static void coroutine_fn backup_run(void *opaque) + if (job->sync_mode == MIRROR_SYNC_MODE_NONE) { + /* All bits are set in copy_bitmap to allow any cluster to be copied. + * This does not actually require them to be copied. */ +- while (!block_job_is_cancelled(&job->common)) { ++ while (!job_is_cancelled(&job->common.job)) { + /* Yield until the job is cancelled. We just let our before_write + * notify callback service CoW requests. */ + block_job_yield(&job->common); +diff --git a/block/commit.c b/block/commit.c +index 925c96a..85baea8 100644 +--- a/block/commit.c ++++ b/block/commit.c +@@ -90,7 +90,7 @@ static void commit_complete(BlockJob *job, void *opaque) + * the normal backing chain can be restored. */ + blk_unref(s->base); + +- if (!block_job_is_cancelled(&s->common) && ret == 0) { ++ if (!job_is_cancelled(&s->common.job) && ret == 0) { + /* success */ + ret = bdrv_drop_intermediate(s->commit_top_bs, base, + s->backing_file_str); +@@ -172,7 +172,7 @@ static void coroutine_fn commit_run(void *opaque) + * with no pending I/O here so that bdrv_drain_all() returns. + */ + block_job_sleep_ns(&s->common, delay_ns); +- if (block_job_is_cancelled(&s->common)) { ++ if (job_is_cancelled(&s->common.job)) { + break; + } + /* Copy if allocated above the base */ +diff --git a/block/mirror.c b/block/mirror.c +index 0df4f70..424072e 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -622,7 +622,7 @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s) + + mirror_throttle(s); + +- if (block_job_is_cancelled(&s->common)) { ++ if (job_is_cancelled(&s->common.job)) { + s->initial_zeroing_ongoing = false; + return 0; + } +@@ -650,7 +650,7 @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s) + + mirror_throttle(s); + +- if (block_job_is_cancelled(&s->common)) { ++ if (job_is_cancelled(&s->common.job)) { + return 0; + } + +@@ -695,7 +695,7 @@ static void coroutine_fn mirror_run(void *opaque) + checking for a NULL string */ + int ret = 0; + +- if (block_job_is_cancelled(&s->common)) { ++ if (job_is_cancelled(&s->common.job)) { + goto immediate_exit; + } + +@@ -729,10 +729,10 @@ static void coroutine_fn mirror_run(void *opaque) + /* Report BLOCK_JOB_READY and wait for complete. */ + block_job_event_ready(&s->common); + s->synced = true; +- while (!block_job_is_cancelled(&s->common) && !s->should_complete) { ++ while (!job_is_cancelled(&s->common.job) && !s->should_complete) { + block_job_yield(&s->common); + } +- s->common.cancelled = false; ++ s->common.job.cancelled = false; + goto immediate_exit; + } + +@@ -768,7 +768,7 @@ static void coroutine_fn mirror_run(void *opaque) + s->last_pause_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); + if (!s->is_none_mode) { + ret = mirror_dirty_init(s); +- if (ret < 0 || block_job_is_cancelled(&s->common)) { ++ if (ret < 0 || job_is_cancelled(&s->common.job)) { + goto immediate_exit; + } + } +@@ -828,7 +828,7 @@ static void coroutine_fn mirror_run(void *opaque) + } + + should_complete = s->should_complete || +- block_job_is_cancelled(&s->common); ++ job_is_cancelled(&s->common.job); + cnt = bdrv_get_dirty_count(s->dirty_bitmap); + } + +@@ -856,7 +856,7 @@ static void coroutine_fn mirror_run(void *opaque) + * completion. + */ + assert(QLIST_EMPTY(&bs->tracked_requests)); +- s->common.cancelled = false; ++ s->common.job.cancelled = false; + need_drain = false; + break; + } +@@ -869,7 +869,7 @@ static void coroutine_fn mirror_run(void *opaque) + } + trace_mirror_before_sleep(s, cnt, s->synced, delay_ns); + block_job_sleep_ns(&s->common, delay_ns); +- if (block_job_is_cancelled(&s->common) && ++ if (job_is_cancelled(&s->common.job) && + (!s->synced || s->common.force)) + { + break; +@@ -884,7 +884,7 @@ immediate_exit: + * the target is a copy of the source. + */ + assert(ret < 0 || ((s->common.force || !s->synced) && +- block_job_is_cancelled(&s->common))); ++ job_is_cancelled(&s->common.job))); + assert(need_drain); + mirror_wait_for_all_io(s); + } +diff --git a/block/stream.c b/block/stream.c +index 7273d22..22c71ae 100644 +--- a/block/stream.c ++++ b/block/stream.c +@@ -66,7 +66,7 @@ static void stream_complete(BlockJob *job, void *opaque) + BlockDriverState *base = s->base; + Error *local_err = NULL; + +- if (!block_job_is_cancelled(&s->common) && bs->backing && ++ if (!job_is_cancelled(&s->common.job) && bs->backing && + data->ret == 0) { + const char *base_id = NULL, *base_fmt = NULL; + if (base) { +@@ -141,7 +141,7 @@ static void coroutine_fn stream_run(void *opaque) + * with no pending I/O here so that bdrv_drain_all() returns. + */ + block_job_sleep_ns(&s->common, delay_ns); +- if (block_job_is_cancelled(&s->common)) { ++ if (job_is_cancelled(&s->common.job)) { + break; + } + +diff --git a/blockjob.c b/blockjob.c +index 0bf0a26..f4f9956 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -379,7 +379,7 @@ static void block_job_conclude(BlockJob *job) + + static void block_job_update_rc(BlockJob *job) + { +- if (!job->ret && block_job_is_cancelled(job)) { ++ if (!job->ret && job_is_cancelled(&job->job)) { + job->ret = -ECANCELED; + } + if (job->ret) { +@@ -438,7 +438,7 @@ static int block_job_finalize_single(BlockJob *job) + + /* Emit events only if we actually started */ + if (block_job_started(job)) { +- if (block_job_is_cancelled(job)) { ++ if (job_is_cancelled(&job->job)) { + block_job_event_cancelled(job); + } else { + const char *msg = NULL; +@@ -464,7 +464,7 @@ static void block_job_cancel_async(BlockJob *job, bool force) + job->user_paused = false; + job->pause_count--; + } +- job->cancelled = true; ++ job->job.cancelled = true; + /* To prevent 'force == false' overriding a previous 'force == true' */ + job->force |= force; + } +@@ -519,7 +519,8 @@ static int block_job_finish_sync(BlockJob *job, + while (!job->completed) { + aio_poll(qemu_get_aio_context(), true); + } +- ret = (job->cancelled && job->ret == 0) ? -ECANCELED : job->ret; ++ ret = (job_is_cancelled(&job->job) && job->ret == 0) ++ ? -ECANCELED : job->ret; + job_unref(&job->job); + return ret; + } +@@ -557,7 +558,7 @@ static void block_job_completed_txn_abort(BlockJob *job) + other_job = QLIST_FIRST(&txn->jobs); + ctx = blk_get_aio_context(other_job->blk); + if (!other_job->completed) { +- assert(other_job->cancelled); ++ assert(job_is_cancelled(&other_job->job)); + block_job_finish_sync(other_job, NULL, NULL); + } + block_job_finalize_single(other_job); +@@ -651,7 +652,9 @@ void block_job_complete(BlockJob *job, Error **errp) + if (job_apply_verb(&job->job, JOB_VERB_COMPLETE, errp)) { + return; + } +- if (job->pause_count || job->cancelled || !job->driver->complete) { ++ if (job->pause_count || job_is_cancelled(&job->job) || ++ !job->driver->complete) ++ { + error_setg(errp, "The active block job '%s' cannot be completed", + job->job.id); + return; +@@ -1006,7 +1009,7 @@ void coroutine_fn block_job_pause_point(BlockJob *job) + if (!block_job_should_pause(job)) { + return; + } +- if (block_job_is_cancelled(job)) { ++ if (job_is_cancelled(&job->job)) { + return; + } + +@@ -1014,7 +1017,7 @@ void coroutine_fn block_job_pause_point(BlockJob *job) + job->driver->pause(job); + } + +- if (block_job_should_pause(job) && !block_job_is_cancelled(job)) { ++ if (block_job_should_pause(job) && !job_is_cancelled(&job->job)) { + JobStatus status = job->job.status; + job_state_transition(&job->job, status == JOB_STATUS_READY + ? JOB_STATUS_STANDBY +@@ -1066,17 +1069,12 @@ void block_job_enter(BlockJob *job) + block_job_enter_cond(job, NULL); + } + +-bool block_job_is_cancelled(BlockJob *job) +-{ +- return job->cancelled; +-} +- + void block_job_sleep_ns(BlockJob *job, int64_t ns) + { + assert(job->busy); + + /* Check cancellation *before* setting busy = false, too! */ +- if (block_job_is_cancelled(job)) { ++ if (job_is_cancelled(&job->job)) { + return; + } + +@@ -1092,7 +1090,7 @@ void block_job_yield(BlockJob *job) + assert(job->busy); + + /* Check cancellation *before* setting busy = false, too! */ +- if (block_job_is_cancelled(job)) { ++ if (job_is_cancelled(&job->job)) { + return; + } + +diff --git a/include/block/blockjob.h b/include/block/blockjob.h +index 087e782..1e708f4 100644 +--- a/include/block/blockjob.h ++++ b/include/block/blockjob.h +@@ -57,14 +57,6 @@ typedef struct BlockJob { + Coroutine *co; + + /** +- * Set to true if the job should cancel itself. The flag must +- * always be tested just before toggling the busy flag from false +- * to true. After a job has been cancelled, it should only yield +- * if #aio_poll will ("sooner or later") reenter the coroutine. +- */ +- bool cancelled; +- +- /** + * Set to true if the job should abort immediately without waiting + * for data to be in sync. + */ +diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h +index 6f0fe3c..d64f30e 100644 +--- a/include/block/blockjob_int.h ++++ b/include/block/blockjob_int.h +@@ -196,14 +196,6 @@ void block_job_early_fail(BlockJob *job); + void block_job_completed(BlockJob *job, int ret); + + /** +- * block_job_is_cancelled: +- * @job: The job being queried. +- * +- * Returns whether the job is scheduled for cancellation. +- */ +-bool block_job_is_cancelled(BlockJob *job); +- +-/** + * block_job_pause_point: + * @job: The job that is ready to pause. + * +diff --git a/include/qemu/job.h b/include/qemu/job.h +index 0751e2a..5dfbec5 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -47,6 +47,14 @@ typedef struct Job { + /** Current state; See @JobStatus for details. */ + JobStatus status; + ++ /** ++ * Set to true if the job should cancel itself. The flag must ++ * always be tested just before toggling the busy flag from false ++ * to true. After a job has been cancelled, it should only yield ++ * if #aio_poll will ("sooner or later") reenter the coroutine. ++ */ ++ bool cancelled; ++ + /** Element of the list of jobs */ + QLIST_ENTRY(Job) job_list; + } Job; +@@ -93,6 +101,9 @@ JobType job_type(const Job *job); + /** Returns the enum string for the JobType of a given Job. */ + const char *job_type_str(const Job *job); + ++/** Returns whether the job is scheduled for cancellation. */ ++bool job_is_cancelled(Job *job); ++ + /** + * Get the next element from the list of block jobs after @job, or the + * first one if @job is %NULL. +diff --git a/job.c b/job.c +index 926f1de..1abca6a 100644 +--- a/job.c ++++ b/job.c +@@ -95,6 +95,11 @@ const char *job_type_str(const Job *job) + return JobType_str(job_type(job)); + } + ++bool job_is_cancelled(Job *job) ++{ ++ return job->cancelled; ++} ++ + Job *job_next(Job *job) + { + if (!job) { +diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c +index b49b28c..26b4bbb 100644 +--- a/tests/test-blockjob-txn.c ++++ b/tests/test-blockjob-txn.c +@@ -29,7 +29,7 @@ static void test_block_job_complete(BlockJob *job, void *opaque) + BlockDriverState *bs = blk_bs(job->blk); + int rc = (intptr_t)opaque; + +- if (block_job_is_cancelled(job)) { ++ if (job_is_cancelled(&job->job)) { + rc = -ECANCELED; + } + +@@ -49,7 +49,7 @@ static void coroutine_fn test_block_job_run(void *opaque) + block_job_yield(job); + } + +- if (block_job_is_cancelled(job)) { ++ if (job_is_cancelled(&job->job)) { + break; + } + } +@@ -66,7 +66,7 @@ typedef struct { + static void test_block_job_cb(void *opaque, int ret) + { + TestBlockJobCBData *data = opaque; +- if (!ret && block_job_is_cancelled(&data->job->common)) { ++ if (!ret && job_is_cancelled(&data->job->common.job)) { + ret = -ECANCELED; + } + *data->result = ret; +diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c +index e24fc3f..fa31481 100644 +--- a/tests/test-blockjob.c ++++ b/tests/test-blockjob.c +@@ -179,7 +179,7 @@ static void coroutine_fn cancel_job_start(void *opaque) + CancelJob *s = opaque; + + while (!s->should_complete) { +- if (block_job_is_cancelled(&s->common)) { ++ if (job_is_cancelled(&s->common.job)) { + goto defer; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Move-completion-and-cancellation-to-Job.patch b/SOURCES/kvm-job-Move-completion-and-cancellation-to-Job.patch new file mode 100644 index 0000000..daa2617 --- /dev/null +++ b/SOURCES/kvm-job-Move-completion-and-cancellation-to-Job.patch @@ -0,0 +1,843 @@ +From 9b04fa7921806440d3eec89b90667dd77761f149 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:23 +0200 +Subject: [PATCH 54/89] job: Move completion and cancellation to Job + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-41-kwolf@redhat.com> +Patchwork-id: 81116 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 40/73] job: Move completion and cancellation to Job +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This moves the top-level job completion and cancellation functions from +BlockJob to Job. + +Signed-off-by: Kevin Wolf +(cherry picked from commit 3d70ff53b6bf90d9eec6f97024ec9895f6799d9e) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block.c | 4 ++- + block/backup.c | 3 +- + block/commit.c | 6 ++-- + block/mirror.c | 6 ++-- + block/replication.c | 4 +-- + block/stream.c | 2 +- + block/trace-events | 3 -- + blockdev.c | 8 ++--- + blockjob.c | 76 --------------------------------------- + include/block/blockjob.h | 55 ----------------------------- + include/block/blockjob_int.h | 18 ---------- + include/qemu/job.h | 68 +++++++++++++++++++++++++++++------ + job.c | 84 +++++++++++++++++++++++++++++++++++++++----- + qemu-img.c | 2 +- + tests/test-bdrv-drain.c | 5 ++- + tests/test-blockjob-txn.c | 14 ++++---- + tests/test-blockjob.c | 21 ++++++----- + trace-events | 1 + + 18 files changed, 171 insertions(+), 209 deletions(-) + +diff --git a/block.c b/block.c +index d991a09..a83787f 100644 +--- a/block.c ++++ b/block.c +@@ -3374,7 +3374,9 @@ static void bdrv_close(BlockDriverState *bs) + + void bdrv_close_all(void) + { +- block_job_cancel_sync_all(); ++ /* TODO We do want to cancel all jobs instead of just block jobs on ++ * shutdown, but bdrv_close_all() isn't the right place any more. */ ++ job_cancel_sync_all(); + nbd_export_close_all(); + + /* Drop references from requests still in flight, such as canceled block +diff --git a/block/backup.c b/block/backup.c +index 6172f90..b13f91d 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -319,10 +319,9 @@ typedef struct { + + static void backup_complete(Job *job, void *opaque) + { +- BlockJob *bjob = container_of(job, BlockJob, job); + BackupCompleteData *data = opaque; + +- block_job_completed(bjob, data->ret); ++ job_completed(job, data->ret); + g_free(data); + } + +diff --git a/block/commit.c b/block/commit.c +index 40d97a3..b0a847e 100644 +--- a/block/commit.c ++++ b/block/commit.c +@@ -112,12 +112,12 @@ static void commit_complete(Job *job, void *opaque) + blk_unref(s->top); + + /* If there is more than one reference to the job (e.g. if called from +- * job_finish_sync()), block_job_completed() won't free it and therefore +- * the blockers on the intermediate nodes remain. This would cause ++ * job_finish_sync()), job_completed() won't free it and therefore the ++ * blockers on the intermediate nodes remain. This would cause + * bdrv_set_backing_hd() to fail. */ + block_job_remove_all_bdrv(bjob); + +- block_job_completed(&s->common, ret); ++ job_completed(job, ret); + g_free(data); + + /* If bdrv_drop_intermediate() didn't already do that, remove the commit +diff --git a/block/mirror.c b/block/mirror.c +index 656237a..c63cf7c 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -498,7 +498,7 @@ static void mirror_exit(Job *job, void *opaque) + bdrv_release_dirty_bitmap(src, s->dirty_bitmap); + + /* Make sure that the source BDS doesn't go away before we called +- * block_job_completed(). */ ++ * job_completed(). */ + bdrv_ref(src); + bdrv_ref(mirror_top_bs); + bdrv_ref(target_bs); +@@ -581,7 +581,7 @@ static void mirror_exit(Job *job, void *opaque) + blk_set_perm(bjob->blk, 0, BLK_PERM_ALL, &error_abort); + blk_insert_bs(bjob->blk, mirror_top_bs, &error_abort); + +- block_job_completed(&s->common, data->ret); ++ job_completed(job, data->ret); + + g_free(data); + bdrv_drained_end(src); +@@ -954,7 +954,7 @@ static void mirror_complete(Job *job, Error **errp) + } + + s->should_complete = true; +- block_job_enter(&s->common); ++ job_enter(job); + } + + static void mirror_pause(Job *job) +diff --git a/block/replication.c b/block/replication.c +index 8241400..f3b2839 100644 +--- a/block/replication.c ++++ b/block/replication.c +@@ -145,7 +145,7 @@ static void replication_close(BlockDriverState *bs) + replication_stop(s->rs, false, NULL); + } + if (s->stage == BLOCK_REPLICATION_FAILOVER) { +- block_job_cancel_sync(s->active_disk->bs->job); ++ job_cancel_sync(&s->active_disk->bs->job->job); + } + + if (s->mode == REPLICATION_MODE_SECONDARY) { +@@ -679,7 +679,7 @@ static void replication_stop(ReplicationState *rs, bool failover, Error **errp) + * disk, secondary disk in backup_job_completed(). + */ + if (s->secondary_disk->bs->job) { +- block_job_cancel_sync(s->secondary_disk->bs->job); ++ job_cancel_sync(&s->secondary_disk->bs->job->job); + } + + if (!failover) { +diff --git a/block/stream.c b/block/stream.c +index b996278..8546c41 100644 +--- a/block/stream.c ++++ b/block/stream.c +@@ -93,7 +93,7 @@ out: + } + + g_free(s->backing_file_str); +- block_job_completed(&s->common, data->ret); ++ job_completed(job, data->ret); + g_free(data); + } + +diff --git a/block/trace-events b/block/trace-events +index 93b9279..2d59b53 100644 +--- a/block/trace-events ++++ b/block/trace-events +@@ -4,9 +4,6 @@ + bdrv_open_common(void *bs, const char *filename, int flags, const char *format_name) "bs %p filename \"%s\" flags 0x%x format_name \"%s\"" + bdrv_lock_medium(void *bs, bool locked) "bs %p locked %d" + +-# blockjob.c +-block_job_completed(void *job, int ret, int jret) "job %p ret %d corrected ret %d" +- + # block/block-backend.c + blk_co_preadv(void *blk, void *bs, int64_t offset, unsigned int bytes, int flags) "blk %p bs %p offset %"PRId64" bytes %u flags 0x%x" + blk_co_pwritev(void *blk, void *bs, int64_t offset, unsigned int bytes, int flags) "blk %p bs %p offset %"PRId64" bytes %u flags 0x%x" +diff --git a/blockdev.c b/blockdev.c +index 422b5ac..d6cd8ed 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -151,7 +151,7 @@ void blockdev_mark_auto_del(BlockBackend *blk) + aio_context_acquire(aio_context); + + if (bs->job) { +- block_job_cancel(bs->job, false); ++ job_cancel(&bs->job->job, false); + } + + aio_context_release(aio_context); +@@ -1967,7 +1967,7 @@ static void drive_backup_abort(BlkActionState *common) + aio_context = bdrv_get_aio_context(state->bs); + aio_context_acquire(aio_context); + +- block_job_cancel_sync(state->job); ++ job_cancel_sync(&state->job->job); + + aio_context_release(aio_context); + } +@@ -2065,7 +2065,7 @@ static void blockdev_backup_abort(BlkActionState *common) + aio_context = bdrv_get_aio_context(state->bs); + aio_context_acquire(aio_context); + +- block_job_cancel_sync(state->job); ++ job_cancel_sync(&state->job->job); + + aio_context_release(aio_context); + } +@@ -3898,7 +3898,7 @@ void qmp_block_job_cancel(const char *device, + } + + trace_qmp_block_job_cancel(job); +- block_job_user_cancel(job, force, errp); ++ job_user_cancel(&job->job, force, errp); + out: + aio_context_release(aio_context); + } +diff --git a/blockjob.c b/blockjob.c +index 14b21c8..438baa1 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -255,63 +255,6 @@ void block_job_dismiss(BlockJob **jobptr, Error **errp) + *jobptr = NULL; + } + +-void block_job_cancel(BlockJob *job, bool force) +-{ +- if (job->job.status == JOB_STATUS_CONCLUDED) { +- job_do_dismiss(&job->job); +- return; +- } +- job_cancel_async(&job->job, force); +- if (!job_started(&job->job)) { +- block_job_completed(job, -ECANCELED); +- } else if (job->job.deferred_to_main_loop) { +- job_completed_txn_abort(&job->job); +- } else { +- block_job_enter(job); +- } +-} +- +-void block_job_user_cancel(BlockJob *job, bool force, Error **errp) +-{ +- if (job_apply_verb(&job->job, JOB_VERB_CANCEL, errp)) { +- return; +- } +- block_job_cancel(job, force); +-} +- +-/* A wrapper around block_job_cancel() taking an Error ** parameter so it may be +- * used with job_finish_sync() without the need for (rather nasty) function +- * pointer casts there. */ +-static void block_job_cancel_err(Job *job, Error **errp) +-{ +- BlockJob *bjob = container_of(job, BlockJob, job); +- assert(is_block_job(job)); +- block_job_cancel(bjob, false); +-} +- +-int block_job_cancel_sync(BlockJob *job) +-{ +- return job_finish_sync(&job->job, &block_job_cancel_err, NULL); +-} +- +-void block_job_cancel_sync_all(void) +-{ +- BlockJob *job; +- AioContext *aio_context; +- +- while ((job = block_job_next(NULL))) { +- aio_context = blk_get_aio_context(job->blk); +- aio_context_acquire(aio_context); +- block_job_cancel_sync(job); +- aio_context_release(aio_context); +- } +-} +- +-int block_job_complete_sync(BlockJob *job, Error **errp) +-{ +- return job_finish_sync(&job->job, job_complete, errp); +-} +- + void block_job_progress_update(BlockJob *job, uint64_t done) + { + job->offset += done; +@@ -488,25 +431,6 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + return job; + } + +-void block_job_completed(BlockJob *job, int ret) +-{ +- assert(job && job->job.txn && !job_is_completed(&job->job)); +- assert(blk_bs(job->blk)->job == job); +- job->job.ret = ret; +- job_update_rc(&job->job); +- trace_block_job_completed(job, ret, job->job.ret); +- if (job->job.ret) { +- job_completed_txn_abort(&job->job); +- } else { +- job_completed_txn_success(&job->job); +- } +-} +- +-void block_job_enter(BlockJob *job) +-{ +- job_enter_cond(&job->job, NULL); +-} +- + void block_job_yield(BlockJob *job) + { + assert(job->job.busy); +diff --git a/include/block/blockjob.h b/include/block/blockjob.h +index 09e6bb4..e9ed7b8 100644 +--- a/include/block/blockjob.h ++++ b/include/block/blockjob.h +@@ -141,15 +141,6 @@ void block_job_remove_all_bdrv(BlockJob *job); + void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp); + + /** +- * block_job_cancel: +- * @job: The job to be canceled. +- * @force: Quit a job without waiting for data to be in sync. +- * +- * Asynchronously cancel the specified job. +- */ +-void block_job_cancel(BlockJob *job, bool force); +- +-/** + * block_job_dismiss: + * @job: The job to be dismissed. + * @errp: Error object. +@@ -186,52 +177,6 @@ void block_job_progress_set_remaining(BlockJob *job, uint64_t remaining); + BlockJobInfo *block_job_query(BlockJob *job, Error **errp); + + /** +- * block_job_user_cancel: +- * @job: The job to be cancelled. +- * @force: Quit a job without waiting for data to be in sync. +- * +- * Cancels the specified job, but may refuse to do so if the +- * operation isn't currently meaningful. +- */ +-void block_job_user_cancel(BlockJob *job, bool force, Error **errp); +- +-/** +- * block_job_cancel_sync: +- * @job: The job to be canceled. +- * +- * Synchronously cancel the job. The completion callback is called +- * before the function returns. The job may actually complete +- * instead of canceling itself; the circumstances under which this +- * happens depend on the kind of job that is active. +- * +- * Returns the return value from the job if the job actually completed +- * during the call, or -ECANCELED if it was canceled. +- */ +-int block_job_cancel_sync(BlockJob *job); +- +-/** +- * block_job_cancel_sync_all: +- * +- * Synchronously cancels all jobs using block_job_cancel_sync(). +- */ +-void block_job_cancel_sync_all(void); +- +-/** +- * block_job_complete_sync: +- * @job: The job to be completed. +- * @errp: Error object which may be set by block_job_complete(); this is not +- * necessarily set on every error, the job return value has to be +- * checked as well. +- * +- * Synchronously complete the job. The completion callback is called before the +- * function returns, unless it is NULL (which is permissible when using this +- * function). +- * +- * Returns the return value from the job. +- */ +-int block_job_complete_sync(BlockJob *job, Error **errp); +- +-/** + * block_job_iostatus_reset: + * @job: The job whose I/O status should be reset. + * +diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h +index 29a2802..7df07b2 100644 +--- a/include/block/blockjob_int.h ++++ b/include/block/blockjob_int.h +@@ -124,24 +124,6 @@ void block_job_yield(BlockJob *job); + int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n); + + /** +- * block_job_completed: +- * @job: The job being completed. +- * @ret: The status code. +- * +- * Call the completion function that was registered at creation time, and +- * free @job. +- */ +-void block_job_completed(BlockJob *job, int ret); +- +-/** +- * block_job_enter: +- * @job: The job to enter. +- * +- * Continue the specified job by entering the coroutine. +- */ +-void block_job_enter(BlockJob *job); +- +-/** + * block_job_event_ready: + * @job: The job which is now ready to be completed. + * +diff --git a/include/qemu/job.h b/include/qemu/job.h +index 39d74ab..bbe1b0c 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -74,8 +74,8 @@ typedef struct Job { + + /** + * Set to false by the job while the coroutine has yielded and may be +- * re-entered by block_job_enter(). There may still be I/O or event loop +- * activity pending. Accessed under block_job_mutex (in blockjob.c). ++ * re-entered by job_enter(). There may still be I/O or event loop activity ++ * pending. Accessed under block_job_mutex (in blockjob.c). + */ + bool busy; + +@@ -114,7 +114,7 @@ typedef struct Job { + /** True if this job should automatically dismiss itself */ + bool auto_dismiss; + +- /** ret code passed to block_job_completed. */ ++ /** ret code passed to job_completed. */ + int ret; + + /** The completion function that will be called when the job completes. */ +@@ -266,8 +266,8 @@ void job_txn_unref(JobTxn *txn); + * @job: Job to add to the transaction + * + * Add @job to the transaction. The @job must not already be in a transaction. +- * The caller must call either job_txn_unref() or block_job_completed() to +- * release the reference that is automatically grabbed here. ++ * The caller must call either job_txn_unref() or job_completed() to release ++ * the reference that is automatically grabbed here. + * + * If @txn is NULL, the function does nothing. + */ +@@ -416,8 +416,59 @@ int job_apply_verb(Job *job, JobVerb verb, Error **errp); + /** The @job could not be started, free it. */ + void job_early_fail(Job *job); + ++/** ++ * @job: The job being completed. ++ * @ret: The status code. ++ * ++ * Marks @job as completed. If @ret is non-zero, the job transaction it is part ++ * of is aborted. If @ret is zero, the job moves into the WAITING state. If it ++ * is the last job to complete in its transaction, all jobs in the transaction ++ * move from WAITING to PENDING. ++ */ ++void job_completed(Job *job, int ret); ++ + /** Asynchronously complete the specified @job. */ +-void job_complete(Job *job, Error **errp);; ++void job_complete(Job *job, Error **errp); ++ ++/** ++ * Asynchronously cancel the specified @job. If @force is true, the job should ++ * be cancelled immediately without waiting for a consistent state. ++ */ ++void job_cancel(Job *job, bool force); ++ ++/** ++ * Cancels the specified job like job_cancel(), but may refuse to do so if the ++ * operation isn't meaningful in the current state of the job. ++ */ ++void job_user_cancel(Job *job, bool force, Error **errp); ++ ++/** ++ * Synchronously cancel the @job. The completion callback is called ++ * before the function returns. The job may actually complete ++ * instead of canceling itself; the circumstances under which this ++ * happens depend on the kind of job that is active. ++ * ++ * Returns the return value from the job if the job actually completed ++ * during the call, or -ECANCELED if it was canceled. ++ */ ++int job_cancel_sync(Job *job); ++ ++/** Synchronously cancels all jobs using job_cancel_sync(). */ ++void job_cancel_sync_all(void); ++ ++/** ++ * @job: The job to be completed. ++ * @errp: Error object which may be set by job_complete(); this is not ++ * necessarily set on every error, the job return value has to be ++ * checked as well. ++ * ++ * Synchronously complete the job. The completion callback is called before the ++ * function returns, unless it is NULL (which is permissible when using this ++ * function). ++ * ++ * Returns the return value from the job. ++ */ ++int job_complete_sync(Job *job, Error **errp); + + /** + * For a @job that has finished its work and is pending awaiting explicit +@@ -459,11 +510,6 @@ int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp) + void job_state_transition(Job *job, JobStatus s1); + void coroutine_fn job_do_yield(Job *job, uint64_t ns); + bool job_should_pause(Job *job); +-bool job_started(Job *job); + void job_do_dismiss(Job *job); +-void job_update_rc(Job *job); +-void job_cancel_async(Job *job, bool force); +-void job_completed_txn_abort(Job *job); +-void job_completed_txn_success(Job *job); + + #endif +diff --git a/job.c b/job.c +index 4f6fd73..2e453f6 100644 +--- a/job.c ++++ b/job.c +@@ -221,7 +221,7 @@ bool job_is_completed(Job *job) + return false; + } + +-bool job_started(Job *job) ++static bool job_started(Job *job) + { + return job->co; + } +@@ -391,10 +391,10 @@ void job_enter(Job *job) + } + + /* Yield, and schedule a timer to reenter the coroutine after @ns nanoseconds. +- * Reentering the job coroutine with block_job_enter() before the timer has +- * expired is allowed and cancels the timer. ++ * Reentering the job coroutine with job_enter() before the timer has expired ++ * is allowed and cancels the timer. + * +- * If @ns is (uint64_t) -1, no timer is scheduled and block_job_enter() must be ++ * If @ns is (uint64_t) -1, no timer is scheduled and job_enter() must be + * called explicitly. */ + void coroutine_fn job_do_yield(Job *job, uint64_t ns) + { +@@ -579,7 +579,7 @@ static void job_conclude(Job *job) + } + } + +-void job_update_rc(Job *job) ++static void job_update_rc(Job *job) + { + if (!job->ret && job_is_cancelled(job)) { + job->ret = -ECANCELED; +@@ -644,7 +644,7 @@ static int job_finalize_single(Job *job) + return 0; + } + +-void job_cancel_async(Job *job, bool force) ++static void job_cancel_async(Job *job, bool force) + { + if (job->user_paused) { + /* Do not call job_enter here, the caller will handle it. */ +@@ -660,7 +660,7 @@ void job_cancel_async(Job *job, bool force) + job->force_cancel |= force; + } + +-void job_completed_txn_abort(Job *job) ++static void job_completed_txn_abort(Job *job) + { + AioContext *ctx; + JobTxn *txn = job->txn; +@@ -748,7 +748,7 @@ static int job_transition_to_pending(Job *job) + return 0; + } + +-void job_completed_txn_success(Job *job) ++static void job_completed_txn_success(Job *job) + { + JobTxn *txn = job->txn; + Job *other_job; +@@ -774,6 +774,74 @@ void job_completed_txn_success(Job *job) + } + } + ++void job_completed(Job *job, int ret) ++{ ++ assert(job && job->txn && !job_is_completed(job)); ++ job->ret = ret; ++ job_update_rc(job); ++ trace_job_completed(job, ret, job->ret); ++ if (job->ret) { ++ job_completed_txn_abort(job); ++ } else { ++ job_completed_txn_success(job); ++ } ++} ++ ++void job_cancel(Job *job, bool force) ++{ ++ if (job->status == JOB_STATUS_CONCLUDED) { ++ job_do_dismiss(job); ++ return; ++ } ++ job_cancel_async(job, force); ++ if (!job_started(job)) { ++ job_completed(job, -ECANCELED); ++ } else if (job->deferred_to_main_loop) { ++ job_completed_txn_abort(job); ++ } else { ++ job_enter(job); ++ } ++} ++ ++void job_user_cancel(Job *job, bool force, Error **errp) ++{ ++ if (job_apply_verb(job, JOB_VERB_CANCEL, errp)) { ++ return; ++ } ++ job_cancel(job, force); ++} ++ ++/* A wrapper around job_cancel() taking an Error ** parameter so it may be ++ * used with job_finish_sync() without the need for (rather nasty) function ++ * pointer casts there. */ ++static void job_cancel_err(Job *job, Error **errp) ++{ ++ job_cancel(job, false); ++} ++ ++int job_cancel_sync(Job *job) ++{ ++ return job_finish_sync(job, &job_cancel_err, NULL); ++} ++ ++void job_cancel_sync_all(void) ++{ ++ Job *job; ++ AioContext *aio_context; ++ ++ while ((job = job_next(NULL))) { ++ aio_context = job->aio_context; ++ aio_context_acquire(aio_context); ++ job_cancel_sync(job); ++ aio_context_release(aio_context); ++ } ++} ++ ++int job_complete_sync(Job *job, Error **errp) ++{ ++ return job_finish_sync(job, job_complete, errp); ++} ++ + void job_complete(Job *job, Error **errp) + { + /* Should not be reachable via external interface for internal jobs */ +diff --git a/qemu-img.c b/qemu-img.c +index 91b3151..734ea94 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -881,7 +881,7 @@ static void run_block_job(BlockJob *job, Error **errp) + } while (!job->ready && !job_is_completed(&job->job)); + + if (!job_is_completed(&job->job)) { +- ret = block_job_complete_sync(job, errp); ++ ret = job_complete_sync(&job->job, errp); + } else { + ret = job->job.ret; + } +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index b428aac..3600ffd 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -498,8 +498,7 @@ typedef struct TestBlockJob { + + static void test_job_completed(Job *job, void *opaque) + { +- BlockJob *bjob = container_of(job, BlockJob, job); +- block_job_completed(bjob, 0); ++ job_completed(job, 0); + } + + static void coroutine_fn test_job_start(void *opaque) +@@ -593,7 +592,7 @@ static void test_blockjob_common(enum drain_type drain_type) + g_assert_false(job->job.paused); + g_assert_false(job->job.busy); /* We're in job_sleep_ns() */ + +- ret = block_job_complete_sync(job, &error_abort); ++ ret = job_complete_sync(&job->job, &error_abort); + g_assert_cmpint(ret, ==, 0); + + blk_unref(blk_src); +diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c +index 6ee31d5..34ee179 100644 +--- a/tests/test-blockjob-txn.c ++++ b/tests/test-blockjob-txn.c +@@ -34,7 +34,7 @@ static void test_block_job_complete(Job *job, void *opaque) + rc = -ECANCELED; + } + +- block_job_completed(bjob, rc); ++ job_completed(job, rc); + bdrv_unref(bs); + } + +@@ -130,7 +130,7 @@ static void test_single_job(int expected) + job_start(&job->job); + + if (expected == -ECANCELED) { +- block_job_cancel(job, false); ++ job_cancel(&job->job, false); + } + + while (result == -EINPROGRESS) { +@@ -176,10 +176,10 @@ static void test_pair_jobs(int expected1, int expected2) + job_txn_unref(txn); + + if (expected1 == -ECANCELED) { +- block_job_cancel(job1, false); ++ job_cancel(&job1->job, false); + } + if (expected2 == -ECANCELED) { +- block_job_cancel(job2, false); ++ job_cancel(&job2->job, false); + } + + while (result1 == -EINPROGRESS || result2 == -EINPROGRESS) { +@@ -232,13 +232,13 @@ static void test_pair_jobs_fail_cancel_race(void) + job_start(&job1->job); + job_start(&job2->job); + +- block_job_cancel(job1, false); ++ job_cancel(&job1->job, false); + + /* Now make job2 finish before the main loop kicks jobs. This simulates + * the race between a pending kick and another job completing. + */ +- block_job_enter(job2); +- block_job_enter(job2); ++ job_enter(&job2->job); ++ job_enter(&job2->job); + + while (result1 == -EINPROGRESS || result2 == -EINPROGRESS) { + aio_poll(qemu_get_aio_context(), true); +diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c +index 1e052c2..46a7873 100644 +--- a/tests/test-blockjob.c ++++ b/tests/test-blockjob.c +@@ -165,10 +165,9 @@ typedef struct CancelJob { + + static void cancel_job_completed(Job *job, void *opaque) + { +- BlockJob *bjob = container_of(job, BlockJob, job); + CancelJob *s = opaque; + s->completed = true; +- block_job_completed(bjob, 0); ++ job_completed(job, 0); + } + + static void cancel_job_complete(Job *job, Error **errp) +@@ -232,7 +231,7 @@ static void cancel_common(CancelJob *s) + BlockBackend *blk = s->blk; + JobStatus sts = job->job.status; + +- block_job_cancel_sync(job); ++ job_cancel_sync(&job->job); + if (sts != JOB_STATUS_CREATED && sts != JOB_STATUS_CONCLUDED) { + BlockJob *dummy = job; + block_job_dismiss(&dummy, &error_abort); +@@ -275,7 +274,7 @@ static void test_cancel_paused(void) + assert(job->job.status == JOB_STATUS_RUNNING); + + job_user_pause(&job->job, &error_abort); +- block_job_enter(job); ++ job_enter(&job->job); + assert(job->job.status == JOB_STATUS_PAUSED); + + cancel_common(s); +@@ -292,7 +291,7 @@ static void test_cancel_ready(void) + assert(job->job.status == JOB_STATUS_RUNNING); + + s->should_converge = true; +- block_job_enter(job); ++ job_enter(&job->job); + assert(job->job.status == JOB_STATUS_READY); + + cancel_common(s); +@@ -309,11 +308,11 @@ static void test_cancel_standby(void) + assert(job->job.status == JOB_STATUS_RUNNING); + + s->should_converge = true; +- block_job_enter(job); ++ job_enter(&job->job); + assert(job->job.status == JOB_STATUS_READY); + + job_user_pause(&job->job, &error_abort); +- block_job_enter(job); ++ job_enter(&job->job); + assert(job->job.status == JOB_STATUS_STANDBY); + + cancel_common(s); +@@ -330,11 +329,11 @@ static void test_cancel_pending(void) + assert(job->job.status == JOB_STATUS_RUNNING); + + s->should_converge = true; +- block_job_enter(job); ++ job_enter(&job->job); + assert(job->job.status == JOB_STATUS_READY); + + job_complete(&job->job, &error_abort); +- block_job_enter(job); ++ job_enter(&job->job); + while (!s->completed) { + aio_poll(qemu_get_aio_context(), true); + } +@@ -354,11 +353,11 @@ static void test_cancel_concluded(void) + assert(job->job.status == JOB_STATUS_RUNNING); + + s->should_converge = true; +- block_job_enter(job); ++ job_enter(&job->job); + assert(job->job.status == JOB_STATUS_READY); + + job_complete(&job->job, &error_abort); +- block_job_enter(job); ++ job_enter(&job->job); + while (!s->completed) { + aio_poll(qemu_get_aio_context(), true); + } +diff --git a/trace-events b/trace-events +index 2507e13..ef7579a 100644 +--- a/trace-events ++++ b/trace-events +@@ -107,6 +107,7 @@ gdbstub_err_checksum_incorrect(uint8_t expected, uint8_t got) "got command packe + # job.c + job_state_transition(void *job, int ret, const char *legal, const char *s0, const char *s1) "job %p (ret: %d) attempting %s transition (%s-->%s)" + job_apply_verb(void *job, const char *state, const char *verb, const char *legal) "job %p in state %s; applying verb %s (%s)" ++job_completed(void *job, int ret, int jret) "job %p ret %d corrected ret %d" + + ### Guest events, keep at bottom + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Move-coroutine-and-related-code-to-Job.patch b/SOURCES/kvm-job-Move-coroutine-and-related-code-to-Job.patch new file mode 100644 index 0000000..0b9cb08 --- /dev/null +++ b/SOURCES/kvm-job-Move-coroutine-and-related-code-to-Job.patch @@ -0,0 +1,1257 @@ +From 0a25884271e9d6a99f0775c3b0c631d006ba2fc2 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:09 +0200 +Subject: [PATCH 40/89] job: Move coroutine and related code to Job + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-27-kwolf@redhat.com> +Patchwork-id: 81113 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 26/73] job: Move coroutine and related code to Job +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This commit moves some core functions for dealing with the job coroutine +from BlockJob to Job. This includes primarily entering the coroutine +(both for the first and reentering) and yielding explicitly and at pause +points. + +Signed-off-by: Kevin Wolf +Reviewed-by: John Snow +(cherry picked from commit da01ff7f38f52791f93fc3ca59afcfbb220f15af) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/backup.c | 2 +- + block/commit.c | 4 +- + block/mirror.c | 22 ++--- + block/replication.c | 2 +- + block/stream.c | 4 +- + blockdev.c | 8 +- + blockjob.c | 219 ++++++++----------------------------------- + include/block/blockjob.h | 40 -------- + include/block/blockjob_int.h | 26 ----- + include/qemu/job.h | 76 +++++++++++++++ + job.c | 137 +++++++++++++++++++++++++++ + tests/test-bdrv-drain.c | 38 ++++---- + tests/test-blockjob-txn.c | 12 +-- + tests/test-blockjob.c | 14 +-- + 14 files changed, 305 insertions(+), 299 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index 22dd368..7d9aad9 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -528,8 +528,8 @@ static const BlockJobDriver backup_job_driver = { + .instance_size = sizeof(BackupBlockJob), + .job_type = JOB_TYPE_BACKUP, + .free = block_job_free, ++ .start = backup_run, + }, +- .start = backup_run, + .commit = backup_commit, + .abort = backup_abort, + .clean = backup_clean, +diff --git a/block/commit.c b/block/commit.c +index d326766..2fbc310 100644 +--- a/block/commit.c ++++ b/block/commit.c +@@ -220,8 +220,8 @@ static const BlockJobDriver commit_job_driver = { + .instance_size = sizeof(CommitBlockJob), + .job_type = JOB_TYPE_COMMIT, + .free = block_job_free, ++ .start = commit_run, + }, +- .start = commit_run, + }; + + static int coroutine_fn bdrv_commit_top_preadv(BlockDriverState *bs, +@@ -371,7 +371,7 @@ void commit_start(const char *job_id, BlockDriverState *bs, + s->on_error = on_error; + + trace_commit_start(bs, base, top, s); +- block_job_start(&s->common); ++ job_start(&s->common.job); + return; + + fail: +diff --git a/block/mirror.c b/block/mirror.c +index 90d4ac9..95fc807 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -126,7 +126,7 @@ static void mirror_iteration_done(MirrorOp *op, int ret) + g_free(op); + + if (s->waiting_for_io) { +- qemu_coroutine_enter(s->common.co); ++ qemu_coroutine_enter(s->common.job.co); + } + } + +@@ -345,7 +345,7 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s) + mirror_wait_for_io(s); + } + +- block_job_pause_point(&s->common); ++ job_pause_point(&s->common.job); + + /* Find the number of consective dirty chunks following the first dirty + * one, and wait for in flight requests in them. */ +@@ -597,7 +597,7 @@ static void mirror_throttle(MirrorBlockJob *s) + s->last_pause_ns = now; + block_job_sleep_ns(&s->common, 0); + } else { +- block_job_pause_point(&s->common); ++ job_pause_point(&s->common.job); + } + } + +@@ -786,7 +786,7 @@ static void coroutine_fn mirror_run(void *opaque) + goto immediate_exit; + } + +- block_job_pause_point(&s->common); ++ job_pause_point(&s->common.job); + + cnt = bdrv_get_dirty_count(s->dirty_bitmap); + /* cnt is the number of dirty bytes remaining and s->bytes_in_flight is +@@ -957,9 +957,9 @@ static void mirror_complete(BlockJob *job, Error **errp) + block_job_enter(&s->common); + } + +-static void mirror_pause(BlockJob *job) ++static void mirror_pause(Job *job) + { +- MirrorBlockJob *s = container_of(job, MirrorBlockJob, common); ++ MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job); + + mirror_wait_for_all_io(s); + } +@@ -991,10 +991,10 @@ static const BlockJobDriver mirror_job_driver = { + .instance_size = sizeof(MirrorBlockJob), + .job_type = JOB_TYPE_MIRROR, + .free = block_job_free, ++ .start = mirror_run, ++ .pause = mirror_pause, + }, +- .start = mirror_run, + .complete = mirror_complete, +- .pause = mirror_pause, + .attached_aio_context = mirror_attached_aio_context, + .drain = mirror_drain, + }; +@@ -1004,10 +1004,10 @@ static const BlockJobDriver commit_active_job_driver = { + .instance_size = sizeof(MirrorBlockJob), + .job_type = JOB_TYPE_COMMIT, + .free = block_job_free, ++ .start = mirror_run, ++ .pause = mirror_pause, + }, +- .start = mirror_run, + .complete = mirror_complete, +- .pause = mirror_pause, + .attached_aio_context = mirror_attached_aio_context, + .drain = mirror_drain, + }; +@@ -1244,7 +1244,7 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs, + } + + trace_mirror_start(bs, s, opaque); +- block_job_start(&s->common); ++ job_start(&s->common.job); + return; + + fail: +diff --git a/block/replication.c b/block/replication.c +index 6c0c718..3f7500e 100644 +--- a/block/replication.c ++++ b/block/replication.c +@@ -574,7 +574,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, + aio_context_release(aio_context); + return; + } +- block_job_start(job); ++ job_start(&job->job); + break; + default: + aio_context_release(aio_context); +diff --git a/block/stream.c b/block/stream.c +index 0bba816..6d8b7b6 100644 +--- a/block/stream.c ++++ b/block/stream.c +@@ -213,8 +213,8 @@ static const BlockJobDriver stream_job_driver = { + .instance_size = sizeof(StreamBlockJob), + .job_type = JOB_TYPE_STREAM, + .free = block_job_free, ++ .start = stream_run, + }, +- .start = stream_run, + }; + + void stream_start(const char *job_id, BlockDriverState *bs, +@@ -262,7 +262,7 @@ void stream_start(const char *job_id, BlockDriverState *bs, + + s->on_error = on_error; + trace_stream_start(bs, base, s); +- block_job_start(&s->common); ++ job_start(&s->common.job); + return; + + fail: +diff --git a/blockdev.c b/blockdev.c +index 96a89cc..efb83c4 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -1952,7 +1952,7 @@ static void drive_backup_commit(BlkActionState *common) + aio_context_acquire(aio_context); + + assert(state->job); +- block_job_start(state->job); ++ job_start(&state->job->job); + + aio_context_release(aio_context); + } +@@ -2050,7 +2050,7 @@ static void blockdev_backup_commit(BlkActionState *common) + aio_context_acquire(aio_context); + + assert(state->job); +- block_job_start(state->job); ++ job_start(&state->job->job); + + aio_context_release(aio_context); + } +@@ -3472,7 +3472,7 @@ void qmp_drive_backup(DriveBackup *arg, Error **errp) + BlockJob *job; + job = do_drive_backup(arg, NULL, errp); + if (job) { +- block_job_start(job); ++ job_start(&job->job); + } + } + +@@ -3560,7 +3560,7 @@ void qmp_blockdev_backup(BlockdevBackup *arg, Error **errp) + BlockJob *job; + job = do_blockdev_backup(arg, NULL, errp); + if (job) { +- block_job_start(job); ++ job_start(&job->job); + } + } + +diff --git a/blockjob.c b/blockjob.c +index 3ede511..313b1ff 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -36,30 +36,9 @@ + #include "qemu/coroutine.h" + #include "qemu/timer.h" + +-/* Right now, this mutex is only needed to synchronize accesses to job->busy +- * and job->sleep_timer, such as concurrent calls to block_job_do_yield and +- * block_job_enter. */ +-static QemuMutex block_job_mutex; +- +-static void block_job_lock(void) +-{ +- qemu_mutex_lock(&block_job_mutex); +-} +- +-static void block_job_unlock(void) +-{ +- qemu_mutex_unlock(&block_job_mutex); +-} +- +-static void __attribute__((__constructor__)) block_job_init(void) +-{ +- qemu_mutex_init(&block_job_mutex); +-} +- + static void block_job_event_cancelled(BlockJob *job); + static void block_job_event_completed(BlockJob *job, const char *msg); + static int block_job_event_pending(BlockJob *job); +-static void block_job_enter_cond(BlockJob *job, bool(*fn)(BlockJob *job)); + + /* Transactional group of block jobs */ + struct BlockJobTxn { +@@ -161,33 +140,27 @@ static void block_job_txn_del_job(BlockJob *job) + } + } + +-/* Assumes the block_job_mutex is held */ +-static bool block_job_timer_pending(BlockJob *job) +-{ +- return timer_pending(&job->sleep_timer); +-} +- +-/* Assumes the block_job_mutex is held */ +-static bool block_job_timer_not_pending(BlockJob *job) ++/* Assumes the job_mutex is held */ ++static bool job_timer_not_pending(Job *job) + { +- return !block_job_timer_pending(job); ++ return !timer_pending(&job->sleep_timer); + } + + static void block_job_pause(BlockJob *job) + { +- job->pause_count++; ++ job->job.pause_count++; + } + + static void block_job_resume(BlockJob *job) + { +- assert(job->pause_count > 0); +- job->pause_count--; +- if (job->pause_count) { ++ assert(job->job.pause_count > 0); ++ job->job.pause_count--; ++ if (job->job.pause_count) { + return; + } + + /* kick only if no timer is pending */ +- block_job_enter_cond(job, block_job_timer_not_pending); ++ job_enter_cond(&job->job, job_timer_not_pending); + } + + static void block_job_attached_aio_context(AioContext *new_context, +@@ -208,7 +181,7 @@ void block_job_free(Job *job) + block_job_detach_aio_context, bjob); + blk_unref(bjob->blk); + error_free(bjob->blocker); +- assert(!timer_pending(&bjob->sleep_timer)); ++ assert(!timer_pending(&bjob->job.sleep_timer)); + } + + static void block_job_attached_aio_context(AioContext *new_context, +@@ -226,7 +199,7 @@ static void block_job_attached_aio_context(AioContext *new_context, + + static void block_job_drain(BlockJob *job) + { +- /* If job is !job->busy this kicks it into the next pause point. */ ++ /* If job is !job->job.busy this kicks it into the next pause point. */ + block_job_enter(job); + + blk_drain(job->blk); +@@ -244,7 +217,7 @@ static void block_job_detach_aio_context(void *opaque) + + block_job_pause(job); + +- while (!job->paused && !job->completed) { ++ while (!job->job.paused && !job->completed) { + block_job_drain(job); + } + +@@ -312,29 +285,11 @@ bool block_job_is_internal(BlockJob *job) + return (job->job.id == NULL); + } + +-static bool block_job_started(BlockJob *job) +-{ +- return job->co; +-} +- + const BlockJobDriver *block_job_driver(BlockJob *job) + { + return job->driver; + } + +-/** +- * All jobs must allow a pause point before entering their job proper. This +- * ensures that jobs can be paused prior to being started, then resumed later. +- */ +-static void coroutine_fn block_job_co_entry(void *opaque) +-{ +- BlockJob *job = opaque; +- +- assert(job && job->driver && job->driver->start); +- block_job_pause_point(job); +- job->driver->start(job); +-} +- + static void block_job_sleep_timer_cb(void *opaque) + { + BlockJob *job = opaque; +@@ -342,24 +297,12 @@ static void block_job_sleep_timer_cb(void *opaque) + block_job_enter(job); + } + +-void block_job_start(BlockJob *job) +-{ +- assert(job && !block_job_started(job) && job->paused && +- job->driver && job->driver->start); +- job->co = qemu_coroutine_create(block_job_co_entry, job); +- job->pause_count--; +- job->busy = true; +- job->paused = false; +- job_state_transition(&job->job, JOB_STATUS_RUNNING); +- bdrv_coroutine_enter(blk_bs(job->blk), job->co); +-} +- + static void block_job_decommission(BlockJob *job) + { + assert(job); + job->completed = true; +- job->busy = false; +- job->paused = false; ++ job->job.busy = false; ++ job->job.paused = false; + job->job.deferred_to_main_loop = true; + block_job_txn_del_job(job); + job_state_transition(&job->job, JOB_STATUS_NULL); +@@ -374,7 +317,7 @@ static void block_job_do_dismiss(BlockJob *job) + static void block_job_conclude(BlockJob *job) + { + job_state_transition(&job->job, JOB_STATUS_CONCLUDED); +- if (job->auto_dismiss || !block_job_started(job)) { ++ if (job->auto_dismiss || !job_started(&job->job)) { + block_job_do_dismiss(job); + } + } +@@ -439,7 +382,7 @@ static int block_job_finalize_single(BlockJob *job) + } + + /* Emit events only if we actually started */ +- if (block_job_started(job)) { ++ if (job_started(&job->job)) { + if (job_is_cancelled(&job->job)) { + block_job_event_cancelled(job); + } else { +@@ -464,7 +407,7 @@ static void block_job_cancel_async(BlockJob *job, bool force) + if (job->user_paused) { + /* Do not call block_job_enter here, the caller will handle it. */ + job->user_paused = false; +- job->pause_count--; ++ job->job.pause_count--; + } + job->job.cancelled = true; + /* To prevent 'force == false' overriding a previous 'force == true' */ +@@ -615,6 +558,12 @@ static void block_job_completed_txn_success(BlockJob *job) + } + } + ++/* Assumes the job_mutex is held */ ++static bool job_timer_pending(Job *job) ++{ ++ return timer_pending(&job->sleep_timer); ++} ++ + void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) + { + int64_t old_speed = job->speed; +@@ -635,7 +584,7 @@ void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) + } + + /* kick only if a timer is pending */ +- block_job_enter_cond(job, block_job_timer_pending); ++ job_enter_cond(&job->job, job_timer_pending); + } + + int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n) +@@ -654,7 +603,7 @@ void block_job_complete(BlockJob *job, Error **errp) + if (job_apply_verb(&job->job, JOB_VERB_COMPLETE, errp)) { + return; + } +- if (job->pause_count || job_is_cancelled(&job->job) || ++ if (job->job.pause_count || job_is_cancelled(&job->job) || + !job->driver->complete) + { + error_setg(errp, "The active block job '%s' cannot be completed", +@@ -708,7 +657,7 @@ bool block_job_user_paused(BlockJob *job) + void block_job_user_resume(BlockJob *job, Error **errp) + { + assert(job); +- if (!job->user_paused || job->pause_count <= 0) { ++ if (!job->user_paused || job->job.pause_count <= 0) { + error_setg(errp, "Can't resume a job that was not paused"); + return; + } +@@ -727,7 +676,7 @@ void block_job_cancel(BlockJob *job, bool force) + return; + } + block_job_cancel_async(job, force); +- if (!block_job_started(job)) { ++ if (!job_started(&job->job)) { + block_job_completed(job, -ECANCELED); + } else if (job->job.deferred_to_main_loop) { + block_job_completed_txn_abort(job); +@@ -797,8 +746,8 @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp) + info->type = g_strdup(job_type_str(&job->job)); + info->device = g_strdup(job->job.id); + info->len = job->len; +- info->busy = atomic_read(&job->busy); +- info->paused = job->pause_count > 0; ++ info->busy = atomic_read(&job->job.busy); ++ info->paused = job->job.pause_count > 0; + info->offset = job->offset; + info->speed = job->speed; + info->io_status = job->iostatus; +@@ -915,12 +864,9 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + job->blk = blk; + job->cb = cb; + job->opaque = opaque; +- job->busy = false; +- job->paused = true; +- job->pause_count = 1; + job->auto_finalize = !(flags & BLOCK_JOB_MANUAL_FINALIZE); + job->auto_dismiss = !(flags & BLOCK_JOB_MANUAL_DISMISS); +- aio_timer_init(qemu_get_aio_context(), &job->sleep_timer, ++ aio_timer_init(qemu_get_aio_context(), &job->job.sleep_timer, + QEMU_CLOCK_REALTIME, SCALE_NS, + block_job_sleep_timer_cb, job); + +@@ -980,128 +926,41 @@ void block_job_completed(BlockJob *job, int ret) + } + } + +-static bool block_job_should_pause(BlockJob *job) +-{ +- return job->pause_count > 0; +-} +- +-/* Yield, and schedule a timer to reenter the coroutine after @ns nanoseconds. +- * Reentering the job coroutine with block_job_enter() before the timer has +- * expired is allowed and cancels the timer. +- * +- * If @ns is (uint64_t) -1, no timer is scheduled and block_job_enter() must be +- * called explicitly. */ +-static void block_job_do_yield(BlockJob *job, uint64_t ns) +-{ +- block_job_lock(); +- if (ns != -1) { +- timer_mod(&job->sleep_timer, ns); +- } +- job->busy = false; +- block_job_unlock(); +- qemu_coroutine_yield(); +- +- /* Set by block_job_enter before re-entering the coroutine. */ +- assert(job->busy); +-} +- +-void coroutine_fn block_job_pause_point(BlockJob *job) +-{ +- assert(job && block_job_started(job)); +- +- if (!block_job_should_pause(job)) { +- return; +- } +- if (job_is_cancelled(&job->job)) { +- return; +- } +- +- if (job->driver->pause) { +- job->driver->pause(job); +- } +- +- if (block_job_should_pause(job) && !job_is_cancelled(&job->job)) { +- JobStatus status = job->job.status; +- job_state_transition(&job->job, status == JOB_STATUS_READY +- ? JOB_STATUS_STANDBY +- : JOB_STATUS_PAUSED); +- job->paused = true; +- block_job_do_yield(job, -1); +- job->paused = false; +- job_state_transition(&job->job, status); +- } +- +- if (job->driver->resume) { +- job->driver->resume(job); +- } +-} +- +-/* +- * Conditionally enter a block_job pending a call to fn() while +- * under the block_job_lock critical section. +- */ +-static void block_job_enter_cond(BlockJob *job, bool(*fn)(BlockJob *job)) +-{ +- if (!block_job_started(job)) { +- return; +- } +- if (job->job.deferred_to_main_loop) { +- return; +- } +- +- block_job_lock(); +- if (job->busy) { +- block_job_unlock(); +- return; +- } +- +- if (fn && !fn(job)) { +- block_job_unlock(); +- return; +- } +- +- assert(!job->job.deferred_to_main_loop); +- timer_del(&job->sleep_timer); +- job->busy = true; +- block_job_unlock(); +- aio_co_wake(job->co); +-} +- + void block_job_enter(BlockJob *job) + { +- block_job_enter_cond(job, NULL); ++ job_enter_cond(&job->job, NULL); + } + + void block_job_sleep_ns(BlockJob *job, int64_t ns) + { +- assert(job->busy); ++ assert(job->job.busy); + + /* Check cancellation *before* setting busy = false, too! */ + if (job_is_cancelled(&job->job)) { + return; + } + +- if (!block_job_should_pause(job)) { +- block_job_do_yield(job, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + ns); ++ if (!job_should_pause(&job->job)) { ++ job_do_yield(&job->job, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + ns); + } + +- block_job_pause_point(job); ++ job_pause_point(&job->job); + } + + void block_job_yield(BlockJob *job) + { +- assert(job->busy); ++ assert(job->job.busy); + + /* Check cancellation *before* setting busy = false, too! */ + if (job_is_cancelled(&job->job)) { + return; + } + +- if (!block_job_should_pause(job)) { +- block_job_do_yield(job, -1); ++ if (!job_should_pause(&job->job)) { ++ job_do_yield(&job->job, -1); + } + +- block_job_pause_point(job); ++ job_pause_point(&job->job); + } + + void block_job_iostatus_reset(BlockJob *job) +@@ -1109,7 +968,7 @@ void block_job_iostatus_reset(BlockJob *job) + if (job->iostatus == BLOCK_DEVICE_IO_STATUS_OK) { + return; + } +- assert(job->user_paused && job->pause_count > 0); ++ assert(job->user_paused && job->job.pause_count > 0); + job->iostatus = BLOCK_DEVICE_IO_STATUS_OK; + } + +diff --git a/include/block/blockjob.h b/include/block/blockjob.h +index 2a9e865..b60d919 100644 +--- a/include/block/blockjob.h ++++ b/include/block/blockjob.h +@@ -51,43 +51,18 @@ typedef struct BlockJob { + BlockBackend *blk; + + /** +- * The coroutine that executes the job. If not NULL, it is +- * reentered when busy is false and the job is cancelled. +- */ +- Coroutine *co; +- +- /** + * Set to true if the job should abort immediately without waiting + * for data to be in sync. + */ + bool force; + + /** +- * Counter for pause request. If non-zero, the block job is either paused, +- * or if busy == true will pause itself as soon as possible. +- */ +- int pause_count; +- +- /** + * Set to true if the job is paused by user. Can be unpaused with the + * block-job-resume QMP command. + */ + bool user_paused; + + /** +- * Set to false by the job while the coroutine has yielded and may be +- * re-entered by block_job_enter(). There may still be I/O or event loop +- * activity pending. Accessed under block_job_mutex (in blockjob.c). +- */ +- bool busy; +- +- /** +- * Set to true by the job while it is in a quiescent state, where +- * no I/O or event loop activity is pending. +- */ +- bool paused; +- +- /** + * Set to true when the job is ready to be completed. + */ + bool ready; +@@ -125,12 +100,6 @@ typedef struct BlockJob { + /** ret code passed to block_job_completed. */ + int ret; + +- /** +- * Timer that is used by @block_job_sleep_ns. Accessed under +- * block_job_mutex (in blockjob.c). +- */ +- QEMUTimer sleep_timer; +- + /** True if this job should automatically finalize itself */ + bool auto_finalize; + +@@ -208,15 +177,6 @@ void block_job_remove_all_bdrv(BlockJob *job); + void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp); + + /** +- * block_job_start: +- * @job: A job that has not yet been started. +- * +- * Begins execution of a block job. +- * Takes ownership of one reference to the job object. +- */ +-void block_job_start(BlockJob *job); +- +-/** + * block_job_cancel: + * @job: The job to be canceled. + * @force: Quit a job without waiting for data to be in sync. +diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h +index 0c2f8de..0a614a8 100644 +--- a/include/block/blockjob_int.h ++++ b/include/block/blockjob_int.h +@@ -38,9 +38,6 @@ struct BlockJobDriver { + /** Generic JobDriver callbacks and settings */ + JobDriver job_driver; + +- /** Mandatory: Entrypoint for the Coroutine. */ +- CoroutineEntry *start; +- + /** + * Optional callback for job types whose completion must be triggered + * manually. +@@ -85,20 +82,6 @@ struct BlockJobDriver { + */ + void (*clean)(BlockJob *job); + +- /** +- * If the callback is not NULL, it will be invoked when the job transitions +- * into the paused state. Paused jobs must not perform any asynchronous +- * I/O or event loop activity. This callback is used to quiesce jobs. +- */ +- void coroutine_fn (*pause)(BlockJob *job); +- +- /** +- * If the callback is not NULL, it will be invoked when the job transitions +- * out of the paused state. Any asynchronous I/O or event loop activity +- * should be restarted from this callback. +- */ +- void coroutine_fn (*resume)(BlockJob *job); +- + /* + * If the callback is not NULL, it will be invoked before the job is + * resumed in a new AioContext. This is the place to move any resources +@@ -196,15 +179,6 @@ void block_job_early_fail(BlockJob *job); + void block_job_completed(BlockJob *job, int ret); + + /** +- * block_job_pause_point: +- * @job: The job that is ready to pause. +- * +- * Pause now if block_job_pause() has been called. Block jobs that perform +- * lots of I/O must call this between requests so that the job can be paused. +- */ +-void coroutine_fn block_job_pause_point(BlockJob *job); +- +-/** + * block_job_enter: + * @job: The job to enter. + * +diff --git a/include/qemu/job.h b/include/qemu/job.h +index 933e0ab..9dcff12 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -28,6 +28,7 @@ + + #include "qapi/qapi-types-block-core.h" + #include "qemu/queue.h" ++#include "qemu/coroutine.h" + + typedef struct JobDriver JobDriver; + +@@ -51,6 +52,37 @@ typedef struct Job { + AioContext *aio_context; + + /** ++ * The coroutine that executes the job. If not NULL, it is reentered when ++ * busy is false and the job is cancelled. ++ */ ++ Coroutine *co; ++ ++ /** ++ * Timer that is used by @block_job_sleep_ns. Accessed under job_mutex (in ++ * job.c). ++ */ ++ QEMUTimer sleep_timer; ++ ++ /** ++ * Counter for pause request. If non-zero, the block job is either paused, ++ * or if busy == true will pause itself as soon as possible. ++ */ ++ int pause_count; ++ ++ /** ++ * Set to false by the job while the coroutine has yielded and may be ++ * re-entered by block_job_enter(). There may still be I/O or event loop ++ * activity pending. Accessed under block_job_mutex (in blockjob.c). ++ */ ++ bool busy; ++ ++ /** ++ * Set to true by the job while it is in a quiescent state, where ++ * no I/O or event loop activity is pending. ++ */ ++ bool paused; ++ ++ /** + * Set to true if the job should cancel itself. The flag must + * always be tested just before toggling the busy flag from false + * to true. After a job has been cancelled, it should only yield +@@ -75,6 +107,23 @@ struct JobDriver { + /** Enum describing the operation */ + JobType job_type; + ++ /** Mandatory: Entrypoint for the Coroutine. */ ++ CoroutineEntry *start; ++ ++ /** ++ * If the callback is not NULL, it will be invoked when the job transitions ++ * into the paused state. Paused jobs must not perform any asynchronous ++ * I/O or event loop activity. This callback is used to quiesce jobs. ++ */ ++ void coroutine_fn (*pause)(Job *job); ++ ++ /** ++ * If the callback is not NULL, it will be invoked when the job transitions ++ * out of the paused state. Any asynchronous I/O or event loop activity ++ * should be restarted from this callback. ++ */ ++ void coroutine_fn (*resume)(Job *job); ++ + /** Called when the job is freed */ + void (*free)(Job *job); + }; +@@ -103,6 +152,30 @@ void job_ref(Job *job); + */ + void job_unref(Job *job); + ++/** ++ * Conditionally enter the job coroutine if the job is ready to run, not ++ * already busy and fn() returns true. fn() is called while under the job_lock ++ * critical section. ++ */ ++void job_enter_cond(Job *job, bool(*fn)(Job *job)); ++ ++/** ++ * @job: A job that has not yet been started. ++ * ++ * Begins execution of a job. ++ * Takes ownership of one reference to the job object. ++ */ ++void job_start(Job *job); ++ ++/** ++ * @job: The job that is ready to pause. ++ * ++ * Pause now if job_pause() has been called. Jobs that perform lots of I/O ++ * must call this between requests so that the job can be paused. ++ */ ++void coroutine_fn job_pause_point(Job *job); ++ ++ + /** Returns the JobType of a given Job. */ + JobType job_type(const Job *job); + +@@ -153,5 +226,8 @@ void job_defer_to_main_loop(Job *job, JobDeferToMainLoopFn *fn, void *opaque); + + /* TODO To be removed from the public interface */ + void job_state_transition(Job *job, JobStatus s1); ++void coroutine_fn job_do_yield(Job *job, uint64_t ns); ++bool job_should_pause(Job *job); ++bool job_started(Job *job); + + #endif +diff --git a/job.c b/job.c +index c5a37fb..78497fd 100644 +--- a/job.c ++++ b/job.c +@@ -60,6 +60,26 @@ bool JobVerbTable[JOB_VERB__MAX][JOB_STATUS__MAX] = { + [JOB_VERB_DISMISS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, + }; + ++/* Right now, this mutex is only needed to synchronize accesses to job->busy ++ * and job->sleep_timer, such as concurrent calls to job_do_yield and ++ * job_enter. */ ++static QemuMutex job_mutex; ++ ++static void job_lock(void) ++{ ++ qemu_mutex_lock(&job_mutex); ++} ++ ++static void job_unlock(void) ++{ ++ qemu_mutex_unlock(&job_mutex); ++} ++ ++static void __attribute__((__constructor__)) job_init(void) ++{ ++ qemu_mutex_init(&job_mutex); ++} ++ + /* TODO Make static once the whole state machine is in job.c */ + void job_state_transition(Job *job, JobStatus s1) + { +@@ -101,6 +121,16 @@ bool job_is_cancelled(Job *job) + return job->cancelled; + } + ++bool job_started(Job *job) ++{ ++ return job->co; ++} ++ ++bool job_should_pause(Job *job) ++{ ++ return job->pause_count > 0; ++} ++ + Job *job_next(Job *job) + { + if (!job) { +@@ -143,6 +173,9 @@ void *job_create(const char *job_id, const JobDriver *driver, AioContext *ctx, + job->id = g_strdup(job_id); + job->refcnt = 1; + job->aio_context = ctx; ++ job->busy = false; ++ job->paused = true; ++ job->pause_count = 1; + + job_state_transition(job, JOB_STATUS_CREATED); + +@@ -172,6 +205,110 @@ void job_unref(Job *job) + } + } + ++void job_enter_cond(Job *job, bool(*fn)(Job *job)) ++{ ++ if (!job_started(job)) { ++ return; ++ } ++ if (job->deferred_to_main_loop) { ++ return; ++ } ++ ++ job_lock(); ++ if (job->busy) { ++ job_unlock(); ++ return; ++ } ++ ++ if (fn && !fn(job)) { ++ job_unlock(); ++ return; ++ } ++ ++ assert(!job->deferred_to_main_loop); ++ timer_del(&job->sleep_timer); ++ job->busy = true; ++ job_unlock(); ++ aio_co_wake(job->co); ++} ++ ++/* Yield, and schedule a timer to reenter the coroutine after @ns nanoseconds. ++ * Reentering the job coroutine with block_job_enter() before the timer has ++ * expired is allowed and cancels the timer. ++ * ++ * If @ns is (uint64_t) -1, no timer is scheduled and block_job_enter() must be ++ * called explicitly. */ ++void coroutine_fn job_do_yield(Job *job, uint64_t ns) ++{ ++ job_lock(); ++ if (ns != -1) { ++ timer_mod(&job->sleep_timer, ns); ++ } ++ job->busy = false; ++ job_unlock(); ++ qemu_coroutine_yield(); ++ ++ /* Set by job_enter_cond() before re-entering the coroutine. */ ++ assert(job->busy); ++} ++ ++void coroutine_fn job_pause_point(Job *job) ++{ ++ assert(job && job_started(job)); ++ ++ if (!job_should_pause(job)) { ++ return; ++ } ++ if (job_is_cancelled(job)) { ++ return; ++ } ++ ++ if (job->driver->pause) { ++ job->driver->pause(job); ++ } ++ ++ if (job_should_pause(job) && !job_is_cancelled(job)) { ++ JobStatus status = job->status; ++ job_state_transition(job, status == JOB_STATUS_READY ++ ? JOB_STATUS_STANDBY ++ : JOB_STATUS_PAUSED); ++ job->paused = true; ++ job_do_yield(job, -1); ++ job->paused = false; ++ job_state_transition(job, status); ++ } ++ ++ if (job->driver->resume) { ++ job->driver->resume(job); ++ } ++} ++ ++/** ++ * All jobs must allow a pause point before entering their job proper. This ++ * ensures that jobs can be paused prior to being started, then resumed later. ++ */ ++static void coroutine_fn job_co_entry(void *opaque) ++{ ++ Job *job = opaque; ++ ++ assert(job && job->driver && job->driver->start); ++ job_pause_point(job); ++ job->driver->start(job); ++} ++ ++ ++void job_start(Job *job) ++{ ++ assert(job && !job_started(job) && job->paused && ++ job->driver && job->driver->start); ++ job->co = qemu_coroutine_create(job_co_entry, job); ++ job->pause_count--; ++ job->busy = true; ++ job->paused = false; ++ job_state_transition(job, JOB_STATUS_RUNNING); ++ aio_co_enter(job->aio_context, job->co); ++} ++ + typedef struct { + Job *job; + JobDeferToMainLoopFn *fn; +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index 4f8cba8..c9f2f9b 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -524,8 +524,8 @@ BlockJobDriver test_job_driver = { + .job_driver = { + .instance_size = sizeof(TestBlockJob), + .free = block_job_free, ++ .start = test_job_start, + }, +- .start = test_job_start, + .complete = test_job_complete, + }; + +@@ -549,47 +549,47 @@ static void test_blockjob_common(enum drain_type drain_type) + job = block_job_create("job0", &test_job_driver, NULL, src, 0, BLK_PERM_ALL, + 0, 0, NULL, NULL, &error_abort); + block_job_add_bdrv(job, "target", target, 0, BLK_PERM_ALL, &error_abort); +- block_job_start(job); ++ job_start(&job->job); + +- g_assert_cmpint(job->pause_count, ==, 0); +- g_assert_false(job->paused); +- g_assert_false(job->busy); /* We're in block_job_sleep_ns() */ ++ g_assert_cmpint(job->job.pause_count, ==, 0); ++ g_assert_false(job->job.paused); ++ g_assert_false(job->job.busy); /* We're in block_job_sleep_ns() */ + + do_drain_begin(drain_type, src); + + if (drain_type == BDRV_DRAIN_ALL) { + /* bdrv_drain_all() drains both src and target */ +- g_assert_cmpint(job->pause_count, ==, 2); ++ g_assert_cmpint(job->job.pause_count, ==, 2); + } else { +- g_assert_cmpint(job->pause_count, ==, 1); ++ g_assert_cmpint(job->job.pause_count, ==, 1); + } + /* XXX We don't wait until the job is actually paused. Is this okay? */ +- /* g_assert_true(job->paused); */ +- g_assert_false(job->busy); /* The job is paused */ ++ /* g_assert_true(job->job.paused); */ ++ g_assert_false(job->job.busy); /* The job is paused */ + + do_drain_end(drain_type, src); + +- g_assert_cmpint(job->pause_count, ==, 0); +- g_assert_false(job->paused); +- g_assert_false(job->busy); /* We're in block_job_sleep_ns() */ ++ g_assert_cmpint(job->job.pause_count, ==, 0); ++ g_assert_false(job->job.paused); ++ g_assert_false(job->job.busy); /* We're in block_job_sleep_ns() */ + + do_drain_begin(drain_type, target); + + if (drain_type == BDRV_DRAIN_ALL) { + /* bdrv_drain_all() drains both src and target */ +- g_assert_cmpint(job->pause_count, ==, 2); ++ g_assert_cmpint(job->job.pause_count, ==, 2); + } else { +- g_assert_cmpint(job->pause_count, ==, 1); ++ g_assert_cmpint(job->job.pause_count, ==, 1); + } + /* XXX We don't wait until the job is actually paused. Is this okay? */ +- /* g_assert_true(job->paused); */ +- g_assert_false(job->busy); /* The job is paused */ ++ /* g_assert_true(job->job.paused); */ ++ g_assert_false(job->job.busy); /* The job is paused */ + + do_drain_end(drain_type, target); + +- g_assert_cmpint(job->pause_count, ==, 0); +- g_assert_false(job->paused); +- g_assert_false(job->busy); /* We're in block_job_sleep_ns() */ ++ g_assert_cmpint(job->job.pause_count, ==, 0); ++ g_assert_false(job->job.paused); ++ g_assert_false(job->job.busy); /* We're in block_job_sleep_ns() */ + + ret = block_job_complete_sync(job, &error_abort); + g_assert_cmpint(ret, ==, 0); +diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c +index c03f966..323e154 100644 +--- a/tests/test-blockjob-txn.c ++++ b/tests/test-blockjob-txn.c +@@ -78,8 +78,8 @@ static const BlockJobDriver test_block_job_driver = { + .job_driver = { + .instance_size = sizeof(TestBlockJob), + .free = block_job_free, ++ .start = test_block_job_run, + }, +- .start = test_block_job_run, + }; + + /* Create a block job that completes with a given return code after a given +@@ -125,7 +125,7 @@ static void test_single_job(int expected) + + txn = block_job_txn_new(); + job = test_block_job_start(1, true, expected, &result, txn); +- block_job_start(job); ++ job_start(&job->job); + + if (expected == -ECANCELED) { + block_job_cancel(job, false); +@@ -165,8 +165,8 @@ static void test_pair_jobs(int expected1, int expected2) + txn = block_job_txn_new(); + job1 = test_block_job_start(1, true, expected1, &result1, txn); + job2 = test_block_job_start(2, true, expected2, &result2, txn); +- block_job_start(job1); +- block_job_start(job2); ++ job_start(&job1->job); ++ job_start(&job2->job); + + /* Release our reference now to trigger as many nice + * use-after-free bugs as possible. +@@ -227,8 +227,8 @@ static void test_pair_jobs_fail_cancel_race(void) + txn = block_job_txn_new(); + job1 = test_block_job_start(1, true, -ECANCELED, &result1, txn); + job2 = test_block_job_start(2, false, 0, &result2, txn); +- block_job_start(job1); +- block_job_start(job2); ++ job_start(&job1->job); ++ job_start(&job2->job); + + block_job_cancel(job1, false); + +diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c +index 5f43bd7..1d18325 100644 +--- a/tests/test-blockjob.c ++++ b/tests/test-blockjob.c +@@ -199,8 +199,8 @@ static const BlockJobDriver test_cancel_driver = { + .job_driver = { + .instance_size = sizeof(CancelJob), + .free = block_job_free, ++ .start = cancel_job_start, + }, +- .start = cancel_job_start, + .complete = cancel_job_complete, + }; + +@@ -254,7 +254,7 @@ static void test_cancel_running(void) + + s = create_common(&job); + +- block_job_start(job); ++ job_start(&job->job); + assert(job->job.status == JOB_STATUS_RUNNING); + + cancel_common(s); +@@ -267,7 +267,7 @@ static void test_cancel_paused(void) + + s = create_common(&job); + +- block_job_start(job); ++ job_start(&job->job); + assert(job->job.status == JOB_STATUS_RUNNING); + + block_job_user_pause(job, &error_abort); +@@ -284,7 +284,7 @@ static void test_cancel_ready(void) + + s = create_common(&job); + +- block_job_start(job); ++ job_start(&job->job); + assert(job->job.status == JOB_STATUS_RUNNING); + + s->should_converge = true; +@@ -301,7 +301,7 @@ static void test_cancel_standby(void) + + s = create_common(&job); + +- block_job_start(job); ++ job_start(&job->job); + assert(job->job.status == JOB_STATUS_RUNNING); + + s->should_converge = true; +@@ -322,7 +322,7 @@ static void test_cancel_pending(void) + + s = create_common(&job); + +- block_job_start(job); ++ job_start(&job->job); + assert(job->job.status == JOB_STATUS_RUNNING); + + s->should_converge = true; +@@ -346,7 +346,7 @@ static void test_cancel_concluded(void) + + s = create_common(&job); + +- block_job_start(job); ++ job_start(&job->job); + assert(job->job.status == JOB_STATUS_RUNNING); + + s->should_converge = true; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Move-defer_to_main_loop-to-Job.patch b/SOURCES/kvm-job-Move-defer_to_main_loop-to-Job.patch new file mode 100644 index 0000000..0bbaf27 --- /dev/null +++ b/SOURCES/kvm-job-Move-defer_to_main_loop-to-Job.patch @@ -0,0 +1,535 @@ +From 1adf648f5842dd52698c338b0a4916606325ccb6 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:08 +0200 +Subject: [PATCH 39/89] job: Move defer_to_main_loop to Job + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-26-kwolf@redhat.com> +Patchwork-id: 81091 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 25/73] job: Move defer_to_main_loop to Job +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +Move the defer_to_main_loop functionality from BlockJob to Job. + +The code can be simplified because we can use job->aio_context in +job_defer_to_main_loop_bh() now, instead of having to access the +BlockDriverState. + +Probably taking the data->aio_context lock in addition was already +unnecessary in the old code because we didn't actually make use of +anything protected by the old AioContext except getting the new +AioContext, in case it changed between scheduling the BH and running it. +But it's certainly unnecessary now that the BDS isn't accessed at all +any more. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +Reviewed-by: John Snow +(cherry picked from commit 1908a5590c7d214b1b6886bc19b81076fb65cec9) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/backup.c | 7 +++--- + block/commit.c | 11 +++++---- + block/mirror.c | 15 ++++++------ + block/stream.c | 14 +++++------ + blockjob.c | 57 ++++---------------------------------------- + include/block/blockjob.h | 5 ---- + include/block/blockjob_int.h | 19 --------------- + include/qemu/job.h | 20 ++++++++++++++++ + job.c | 32 +++++++++++++++++++++++++ + tests/test-bdrv-drain.c | 7 +++--- + tests/test-blockjob-txn.c | 13 +++++----- + tests/test-blockjob.c | 7 +++--- + 12 files changed, 97 insertions(+), 110 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index ef0aa0e..22dd368 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -317,11 +317,12 @@ typedef struct { + int ret; + } BackupCompleteData; + +-static void backup_complete(BlockJob *job, void *opaque) ++static void backup_complete(Job *job, void *opaque) + { ++ BlockJob *bjob = container_of(job, BlockJob, job); + BackupCompleteData *data = opaque; + +- block_job_completed(job, data->ret); ++ block_job_completed(bjob, data->ret); + g_free(data); + } + +@@ -519,7 +520,7 @@ static void coroutine_fn backup_run(void *opaque) + + data = g_malloc(sizeof(*data)); + data->ret = ret; +- block_job_defer_to_main_loop(&job->common, backup_complete, data); ++ job_defer_to_main_loop(&job->common.job, backup_complete, data); + } + + static const BlockJobDriver backup_job_driver = { +diff --git a/block/commit.c b/block/commit.c +index 85baea8..d326766 100644 +--- a/block/commit.c ++++ b/block/commit.c +@@ -72,9 +72,10 @@ typedef struct { + int ret; + } CommitCompleteData; + +-static void commit_complete(BlockJob *job, void *opaque) ++static void commit_complete(Job *job, void *opaque) + { +- CommitBlockJob *s = container_of(job, CommitBlockJob, common); ++ CommitBlockJob *s = container_of(job, CommitBlockJob, common.job); ++ BlockJob *bjob = &s->common; + CommitCompleteData *data = opaque; + BlockDriverState *top = blk_bs(s->top); + BlockDriverState *base = blk_bs(s->base); +@@ -90,7 +91,7 @@ static void commit_complete(BlockJob *job, void *opaque) + * the normal backing chain can be restored. */ + blk_unref(s->base); + +- if (!job_is_cancelled(&s->common.job) && ret == 0) { ++ if (!job_is_cancelled(job) && ret == 0) { + /* success */ + ret = bdrv_drop_intermediate(s->commit_top_bs, base, + s->backing_file_str); +@@ -114,7 +115,7 @@ static void commit_complete(BlockJob *job, void *opaque) + * block_job_finish_sync()), block_job_completed() won't free it and + * therefore the blockers on the intermediate nodes remain. This would + * cause bdrv_set_backing_hd() to fail. */ +- block_job_remove_all_bdrv(job); ++ block_job_remove_all_bdrv(bjob); + + block_job_completed(&s->common, ret); + g_free(data); +@@ -211,7 +212,7 @@ out: + + data = g_malloc(sizeof(*data)); + data->ret = ret; +- block_job_defer_to_main_loop(&s->common, commit_complete, data); ++ job_defer_to_main_loop(&s->common.job, commit_complete, data); + } + + static const BlockJobDriver commit_job_driver = { +diff --git a/block/mirror.c b/block/mirror.c +index 424072e..90d4ac9 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -484,9 +484,10 @@ typedef struct { + int ret; + } MirrorExitData; + +-static void mirror_exit(BlockJob *job, void *opaque) ++static void mirror_exit(Job *job, void *opaque) + { +- MirrorBlockJob *s = container_of(job, MirrorBlockJob, common); ++ MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job); ++ BlockJob *bjob = &s->common; + MirrorExitData *data = opaque; + AioContext *replace_aio_context = NULL; + BlockDriverState *src = s->source; +@@ -568,7 +569,7 @@ static void mirror_exit(BlockJob *job, void *opaque) + * the blockers on the intermediate nodes so that the resulting state is + * valid. Also give up permissions on mirror_top_bs->backing, which might + * block the removal. */ +- block_job_remove_all_bdrv(job); ++ block_job_remove_all_bdrv(bjob); + bdrv_child_try_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL, + &error_abort); + bdrv_replace_node(mirror_top_bs, backing_bs(mirror_top_bs), &error_abort); +@@ -576,9 +577,9 @@ static void mirror_exit(BlockJob *job, void *opaque) + /* We just changed the BDS the job BB refers to (with either or both of the + * bdrv_replace_node() calls), so switch the BB back so the cleanup does + * the right thing. We don't need any permissions any more now. */ +- blk_remove_bs(job->blk); +- blk_set_perm(job->blk, 0, BLK_PERM_ALL, &error_abort); +- blk_insert_bs(job->blk, mirror_top_bs, &error_abort); ++ blk_remove_bs(bjob->blk); ++ blk_set_perm(bjob->blk, 0, BLK_PERM_ALL, &error_abort); ++ blk_insert_bs(bjob->blk, mirror_top_bs, &error_abort); + + block_job_completed(&s->common, data->ret); + +@@ -901,7 +902,7 @@ immediate_exit: + if (need_drain) { + bdrv_drained_begin(bs); + } +- block_job_defer_to_main_loop(&s->common, mirror_exit, data); ++ job_defer_to_main_loop(&s->common.job, mirror_exit, data); + } + + static void mirror_complete(BlockJob *job, Error **errp) +diff --git a/block/stream.c b/block/stream.c +index 22c71ae..0bba816 100644 +--- a/block/stream.c ++++ b/block/stream.c +@@ -58,16 +58,16 @@ typedef struct { + int ret; + } StreamCompleteData; + +-static void stream_complete(BlockJob *job, void *opaque) ++static void stream_complete(Job *job, void *opaque) + { +- StreamBlockJob *s = container_of(job, StreamBlockJob, common); ++ StreamBlockJob *s = container_of(job, StreamBlockJob, common.job); ++ BlockJob *bjob = &s->common; + StreamCompleteData *data = opaque; +- BlockDriverState *bs = blk_bs(job->blk); ++ BlockDriverState *bs = blk_bs(bjob->blk); + BlockDriverState *base = s->base; + Error *local_err = NULL; + +- if (!job_is_cancelled(&s->common.job) && bs->backing && +- data->ret == 0) { ++ if (!job_is_cancelled(job) && bs->backing && data->ret == 0) { + const char *base_id = NULL, *base_fmt = NULL; + if (base) { + base_id = s->backing_file_str; +@@ -88,7 +88,7 @@ out: + /* Reopen the image back in read-only mode if necessary */ + if (s->bs_flags != bdrv_get_flags(bs)) { + /* Give up write permissions before making it read-only */ +- blk_set_perm(job->blk, 0, BLK_PERM_ALL, &error_abort); ++ blk_set_perm(bjob->blk, 0, BLK_PERM_ALL, &error_abort); + bdrv_reopen(bs, s->bs_flags, NULL); + } + +@@ -205,7 +205,7 @@ out: + /* Modify backing chain and close BDSes in main loop */ + data = g_malloc(sizeof(*data)); + data->ret = ret; +- block_job_defer_to_main_loop(&s->common, stream_complete, data); ++ job_defer_to_main_loop(&s->common.job, stream_complete, data); + } + + static const BlockJobDriver stream_job_driver = { +diff --git a/blockjob.c b/blockjob.c +index 0a0b1c4..3ede511 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -360,7 +360,7 @@ static void block_job_decommission(BlockJob *job) + job->completed = true; + job->busy = false; + job->paused = false; +- job->deferred_to_main_loop = true; ++ job->job.deferred_to_main_loop = true; + block_job_txn_del_job(job); + job_state_transition(&job->job, JOB_STATUS_NULL); + job_unref(&job->job); +@@ -515,7 +515,7 @@ static int block_job_finish_sync(BlockJob *job, + /* block_job_drain calls block_job_enter, and it should be enough to + * induce progress until the job completes or moves to the main thread. + */ +- while (!job->deferred_to_main_loop && !job->completed) { ++ while (!job->job.deferred_to_main_loop && !job->completed) { + block_job_drain(job); + } + while (!job->completed) { +@@ -729,7 +729,7 @@ void block_job_cancel(BlockJob *job, bool force) + block_job_cancel_async(job, force); + if (!block_job_started(job)) { + block_job_completed(job, -ECANCELED); +- } else if (job->deferred_to_main_loop) { ++ } else if (job->job.deferred_to_main_loop) { + block_job_completed_txn_abort(job); + } else { + block_job_enter(job); +@@ -1045,7 +1045,7 @@ static void block_job_enter_cond(BlockJob *job, bool(*fn)(BlockJob *job)) + if (!block_job_started(job)) { + return; + } +- if (job->deferred_to_main_loop) { ++ if (job->job.deferred_to_main_loop) { + return; + } + +@@ -1060,7 +1060,7 @@ static void block_job_enter_cond(BlockJob *job, bool(*fn)(BlockJob *job)) + return; + } + +- assert(!job->deferred_to_main_loop); ++ assert(!job->job.deferred_to_main_loop); + timer_del(&job->sleep_timer); + job->busy = true; + block_job_unlock(); +@@ -1166,50 +1166,3 @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err, + } + return action; + } +- +-typedef struct { +- BlockJob *job; +- AioContext *aio_context; +- BlockJobDeferToMainLoopFn *fn; +- void *opaque; +-} BlockJobDeferToMainLoopData; +- +-static void block_job_defer_to_main_loop_bh(void *opaque) +-{ +- BlockJobDeferToMainLoopData *data = opaque; +- AioContext *aio_context; +- +- /* Prevent race with block_job_defer_to_main_loop() */ +- aio_context_acquire(data->aio_context); +- +- /* Fetch BDS AioContext again, in case it has changed */ +- aio_context = blk_get_aio_context(data->job->blk); +- if (aio_context != data->aio_context) { +- aio_context_acquire(aio_context); +- } +- +- data->fn(data->job, data->opaque); +- +- if (aio_context != data->aio_context) { +- aio_context_release(aio_context); +- } +- +- aio_context_release(data->aio_context); +- +- g_free(data); +-} +- +-void block_job_defer_to_main_loop(BlockJob *job, +- BlockJobDeferToMainLoopFn *fn, +- void *opaque) +-{ +- BlockJobDeferToMainLoopData *data = g_malloc(sizeof(*data)); +- data->job = job; +- data->aio_context = blk_get_aio_context(job->blk); +- data->fn = fn; +- data->opaque = opaque; +- job->deferred_to_main_loop = true; +- +- aio_bh_schedule_oneshot(qemu_get_aio_context(), +- block_job_defer_to_main_loop_bh, data); +-} +diff --git a/include/block/blockjob.h b/include/block/blockjob.h +index 1e708f4..2a9e865 100644 +--- a/include/block/blockjob.h ++++ b/include/block/blockjob.h +@@ -92,11 +92,6 @@ typedef struct BlockJob { + */ + bool ready; + +- /** +- * Set to true when the job has deferred work to the main loop. +- */ +- bool deferred_to_main_loop; +- + /** Status that is published by the query-block-jobs QMP API */ + BlockDeviceIoStatus iostatus; + +diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h +index d64f30e..0c2f8de 100644 +--- a/include/block/blockjob_int.h ++++ b/include/block/blockjob_int.h +@@ -233,23 +233,4 @@ void block_job_event_ready(BlockJob *job); + BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err, + int is_read, int error); + +-typedef void BlockJobDeferToMainLoopFn(BlockJob *job, void *opaque); +- +-/** +- * block_job_defer_to_main_loop: +- * @job: The job +- * @fn: The function to run in the main loop +- * @opaque: The opaque value that is passed to @fn +- * +- * This function must be called by the main job coroutine just before it +- * returns. @fn is executed in the main loop with the BlockDriverState +- * AioContext acquired. Block jobs must call bdrv_unref(), bdrv_close(), and +- * anything that uses bdrv_drain_all() in the main loop. +- * +- * The @job AioContext is held while @fn executes. +- */ +-void block_job_defer_to_main_loop(BlockJob *job, +- BlockJobDeferToMainLoopFn *fn, +- void *opaque); +- + #endif +diff --git a/include/qemu/job.h b/include/qemu/job.h +index 01e083f..933e0ab 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -58,6 +58,9 @@ typedef struct Job { + */ + bool cancelled; + ++ /** Set to true when the job has deferred work to the main loop. */ ++ bool deferred_to_main_loop; ++ + /** Element of the list of jobs */ + QLIST_ENTRY(Job) job_list; + } Job; +@@ -131,6 +134,23 @@ Job *job_get(const char *id); + */ + int job_apply_verb(Job *job, JobVerb verb, Error **errp); + ++typedef void JobDeferToMainLoopFn(Job *job, void *opaque); ++ ++/** ++ * @job: The job ++ * @fn: The function to run in the main loop ++ * @opaque: The opaque value that is passed to @fn ++ * ++ * This function must be called by the main job coroutine just before it ++ * returns. @fn is executed in the main loop with the job AioContext acquired. ++ * ++ * Block jobs must call bdrv_unref(), bdrv_close(), and anything that uses ++ * bdrv_drain_all() in the main loop. ++ * ++ * The @job AioContext is held while @fn executes. ++ */ ++void job_defer_to_main_loop(Job *job, JobDeferToMainLoopFn *fn, void *opaque); ++ + /* TODO To be removed from the public interface */ + void job_state_transition(Job *job, JobStatus s1); + +diff --git a/job.c b/job.c +index 01074d0..c5a37fb 100644 +--- a/job.c ++++ b/job.c +@@ -28,6 +28,7 @@ + #include "qapi/error.h" + #include "qemu/job.h" + #include "qemu/id.h" ++#include "qemu/main-loop.h" + #include "trace-root.h" + + static QLIST_HEAD(, Job) jobs = QLIST_HEAD_INITIALIZER(jobs); +@@ -170,3 +171,34 @@ void job_unref(Job *job) + g_free(job); + } + } ++ ++typedef struct { ++ Job *job; ++ JobDeferToMainLoopFn *fn; ++ void *opaque; ++} JobDeferToMainLoopData; ++ ++static void job_defer_to_main_loop_bh(void *opaque) ++{ ++ JobDeferToMainLoopData *data = opaque; ++ Job *job = data->job; ++ AioContext *aio_context = job->aio_context; ++ ++ aio_context_acquire(aio_context); ++ data->fn(data->job, data->opaque); ++ aio_context_release(aio_context); ++ ++ g_free(data); ++} ++ ++void job_defer_to_main_loop(Job *job, JobDeferToMainLoopFn *fn, void *opaque) ++{ ++ JobDeferToMainLoopData *data = g_malloc(sizeof(*data)); ++ data->job = job; ++ data->fn = fn; ++ data->opaque = opaque; ++ job->deferred_to_main_loop = true; ++ ++ aio_bh_schedule_oneshot(qemu_get_aio_context(), ++ job_defer_to_main_loop_bh, data); ++} +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index f9e37d4..4f8cba8 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -496,9 +496,10 @@ typedef struct TestBlockJob { + bool should_complete; + } TestBlockJob; + +-static void test_job_completed(BlockJob *job, void *opaque) ++static void test_job_completed(Job *job, void *opaque) + { +- block_job_completed(job, 0); ++ BlockJob *bjob = container_of(job, BlockJob, job); ++ block_job_completed(bjob, 0); + } + + static void coroutine_fn test_job_start(void *opaque) +@@ -510,7 +511,7 @@ static void coroutine_fn test_job_start(void *opaque) + block_job_sleep_ns(&s->common, 100000); + } + +- block_job_defer_to_main_loop(&s->common, test_job_completed, NULL); ++ job_defer_to_main_loop(&s->common.job, test_job_completed, NULL); + } + + static void test_job_complete(BlockJob *job, Error **errp) +diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c +index 26b4bbb..c03f966 100644 +--- a/tests/test-blockjob-txn.c ++++ b/tests/test-blockjob-txn.c +@@ -24,16 +24,17 @@ typedef struct { + int *result; + } TestBlockJob; + +-static void test_block_job_complete(BlockJob *job, void *opaque) ++static void test_block_job_complete(Job *job, void *opaque) + { +- BlockDriverState *bs = blk_bs(job->blk); ++ BlockJob *bjob = container_of(job, BlockJob, job); ++ BlockDriverState *bs = blk_bs(bjob->blk); + int rc = (intptr_t)opaque; + +- if (job_is_cancelled(&job->job)) { ++ if (job_is_cancelled(job)) { + rc = -ECANCELED; + } + +- block_job_completed(job, rc); ++ block_job_completed(bjob, rc); + bdrv_unref(bs); + } + +@@ -54,8 +55,8 @@ static void coroutine_fn test_block_job_run(void *opaque) + } + } + +- block_job_defer_to_main_loop(job, test_block_job_complete, +- (void *)(intptr_t)s->rc); ++ job_defer_to_main_loop(&job->job, test_block_job_complete, ++ (void *)(intptr_t)s->rc); + } + + typedef struct { +diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c +index fa31481..5f43bd7 100644 +--- a/tests/test-blockjob.c ++++ b/tests/test-blockjob.c +@@ -161,11 +161,12 @@ typedef struct CancelJob { + bool completed; + } CancelJob; + +-static void cancel_job_completed(BlockJob *job, void *opaque) ++static void cancel_job_completed(Job *job, void *opaque) + { ++ BlockJob *bjob = container_of(job, BlockJob, job); + CancelJob *s = opaque; + s->completed = true; +- block_job_completed(job, 0); ++ block_job_completed(bjob, 0); + } + + static void cancel_job_complete(BlockJob *job, Error **errp) +@@ -191,7 +192,7 @@ static void coroutine_fn cancel_job_start(void *opaque) + } + + defer: +- block_job_defer_to_main_loop(&s->common, cancel_job_completed, s); ++ job_defer_to_main_loop(&s->common.job, cancel_job_completed, s); + } + + static const BlockJobDriver test_cancel_driver = { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Move-job_finish_sync-to-Job.patch b/SOURCES/kvm-job-Move-job_finish_sync-to-Job.patch new file mode 100644 index 0000000..5646557 --- /dev/null +++ b/SOURCES/kvm-job-Move-job_finish_sync-to-Job.patch @@ -0,0 +1,199 @@ +From 29dceceeaac867e78dcf4b8ef121f361b14e06b4 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:20 +0200 +Subject: [PATCH 51/89] job: Move job_finish_sync() to Job + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-38-kwolf@redhat.com> +Patchwork-id: 81076 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 37/73] job: Move job_finish_sync() to Job +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +block_job_finish_sync() doesn't contain anything block job specific any +more, so it can be moved to Job. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +(cherry picked from commit 6a74c075aca731e7e945201a4ae2336b8e328433) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/commit.c | 6 +++--- + blockjob.c | 55 +++++++++--------------------------------------------- + include/qemu/job.h | 9 +++++++++ + job.c | 28 +++++++++++++++++++++++++++ + 4 files changed, 49 insertions(+), 49 deletions(-) + +diff --git a/block/commit.c b/block/commit.c +index 02a8af9..40d97a3 100644 +--- a/block/commit.c ++++ b/block/commit.c +@@ -112,9 +112,9 @@ static void commit_complete(Job *job, void *opaque) + blk_unref(s->top); + + /* If there is more than one reference to the job (e.g. if called from +- * block_job_finish_sync()), block_job_completed() won't free it and +- * therefore the blockers on the intermediate nodes remain. This would +- * cause bdrv_set_backing_hd() to fail. */ ++ * job_finish_sync()), block_job_completed() won't free it and therefore ++ * the blockers on the intermediate nodes remain. This would cause ++ * bdrv_set_backing_hd() to fail. */ + block_job_remove_all_bdrv(bjob); + + block_job_completed(&s->common, ret); +diff --git a/blockjob.c b/blockjob.c +index 0ca7672..1ed3e9c 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -307,40 +307,6 @@ static int block_job_txn_apply(BlockJobTxn *txn, int fn(BlockJob *), bool lock) + return rc; + } + +-static int block_job_finish_sync(BlockJob *job, +- void (*finish)(BlockJob *, Error **errp), +- Error **errp) +-{ +- Error *local_err = NULL; +- int ret; +- +- assert(blk_bs(job->blk)->job == job); +- +- job_ref(&job->job); +- +- if (finish) { +- finish(job, &local_err); +- } +- if (local_err) { +- error_propagate(errp, local_err); +- job_unref(&job->job); +- return -EBUSY; +- } +- /* job_drain calls job_enter, and it should be enough to induce progress +- * until the job completes or moves to the main thread. +- */ +- while (!job->job.deferred_to_main_loop && !job_is_completed(&job->job)) { +- job_drain(&job->job); +- } +- while (!job_is_completed(&job->job)) { +- aio_poll(qemu_get_aio_context(), true); +- } +- ret = (job_is_cancelled(&job->job) && job->job.ret == 0) +- ? -ECANCELED : job->job.ret; +- job_unref(&job->job); +- return ret; +-} +- + static void block_job_completed_txn_abort(BlockJob *job) + { + AioContext *ctx; +@@ -375,7 +341,7 @@ static void block_job_completed_txn_abort(BlockJob *job) + ctx = blk_get_aio_context(other_job->blk); + if (!job_is_completed(&other_job->job)) { + assert(job_is_cancelled(&other_job->job)); +- block_job_finish_sync(other_job, NULL, NULL); ++ job_finish_sync(&other_job->job, NULL, NULL); + } + job_finalize_single(&other_job->job); + aio_context_release(ctx); +@@ -528,16 +494,18 @@ void block_job_user_cancel(BlockJob *job, bool force, Error **errp) + } + + /* A wrapper around block_job_cancel() taking an Error ** parameter so it may be +- * used with block_job_finish_sync() without the need for (rather nasty) +- * function pointer casts there. */ +-static void block_job_cancel_err(BlockJob *job, Error **errp) ++ * used with job_finish_sync() without the need for (rather nasty) function ++ * pointer casts there. */ ++static void block_job_cancel_err(Job *job, Error **errp) + { +- block_job_cancel(job, false); ++ BlockJob *bjob = container_of(job, BlockJob, job); ++ assert(is_block_job(job)); ++ block_job_cancel(bjob, false); + } + + int block_job_cancel_sync(BlockJob *job) + { +- return block_job_finish_sync(job, &block_job_cancel_err, NULL); ++ return job_finish_sync(&job->job, &block_job_cancel_err, NULL); + } + + void block_job_cancel_sync_all(void) +@@ -553,14 +521,9 @@ void block_job_cancel_sync_all(void) + } + } + +-static void block_job_complete(BlockJob *job, Error **errp) +-{ +- job_complete(&job->job, errp); +-} +- + int block_job_complete_sync(BlockJob *job, Error **errp) + { +- return block_job_finish_sync(job, &block_job_complete, errp); ++ return job_finish_sync(&job->job, job_complete, errp); + } + + void block_job_progress_update(BlockJob *job, uint64_t done) +diff --git a/include/qemu/job.h b/include/qemu/job.h +index 8f7f71a..17e2cec 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -389,6 +389,15 @@ typedef void JobDeferToMainLoopFn(Job *job, void *opaque); + */ + void job_defer_to_main_loop(Job *job, JobDeferToMainLoopFn *fn, void *opaque); + ++/** ++ * Synchronously finishes the given @job. If @finish is given, it is called to ++ * trigger completion or cancellation of the job. ++ * ++ * Returns 0 if the job is successfully completed, -ECANCELED if the job was ++ * cancelled before completing, and -errno in other error cases. ++ */ ++int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp); ++ + /* TODO To be removed from the public interface */ + void job_state_transition(Job *job, JobStatus s1); + void coroutine_fn job_do_yield(Job *job, uint64_t ns); +diff --git a/job.c b/job.c +index 8ceac0b..aa74b4c 100644 +--- a/job.c ++++ b/job.c +@@ -603,3 +603,31 @@ void job_defer_to_main_loop(Job *job, JobDeferToMainLoopFn *fn, void *opaque) + aio_bh_schedule_oneshot(qemu_get_aio_context(), + job_defer_to_main_loop_bh, data); + } ++ ++int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp) ++{ ++ Error *local_err = NULL; ++ int ret; ++ ++ job_ref(job); ++ ++ if (finish) { ++ finish(job, &local_err); ++ } ++ if (local_err) { ++ error_propagate(errp, local_err); ++ job_unref(job); ++ return -EBUSY; ++ } ++ /* job_drain calls job_enter, and it should be enough to induce progress ++ * until the job completes or moves to the main thread. */ ++ while (!job->deferred_to_main_loop && !job_is_completed(job)) { ++ job_drain(job); ++ } ++ while (!job_is_completed(job)) { ++ aio_poll(qemu_get_aio_context(), true); ++ } ++ ret = (job_is_cancelled(job) && job->ret == 0) ? -ECANCELED : job->ret; ++ job_unref(job); ++ return ret; ++} +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Move-pause-resume-functions-to-Job.patch b/SOURCES/kvm-job-Move-pause-resume-functions-to-Job.patch new file mode 100644 index 0000000..ff159ba --- /dev/null +++ b/SOURCES/kvm-job-Move-pause-resume-functions-to-Job.patch @@ -0,0 +1,550 @@ +From 6e9a5d0ef7ada1b153e0808c0fe73eeab940cfbd Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:11 +0200 +Subject: [PATCH 42/89] job: Move pause/resume functions to Job + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-29-kwolf@redhat.com> +Patchwork-id: 81062 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 28/73] job: Move pause/resume functions to Job +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +While we already moved the state related to job pausing to Job, the +functions to do were still BlockJob only. This commit moves them over to +Job. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +Reviewed-by: John Snow +(cherry picked from commit b15de82867975e0b4acf644b5ee36d84904b6612) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/backup.c | 1 + + block/commit.c | 1 + + block/mirror.c | 2 ++ + block/stream.c | 1 + + blockdev.c | 6 ++-- + blockjob.c | 81 +++++++++----------------------------------- + include/block/blockjob.h | 32 ----------------- + include/block/blockjob_int.h | 7 ++++ + include/qemu/job.h | 37 ++++++++++++++++++++ + job.c | 59 ++++++++++++++++++++++++++++++++ + tests/test-bdrv-drain.c | 1 + + tests/test-blockjob-txn.c | 1 + + tests/test-blockjob.c | 6 ++-- + 13 files changed, 133 insertions(+), 102 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index f3a4f7c..4d011d5 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -528,6 +528,7 @@ static const BlockJobDriver backup_job_driver = { + .instance_size = sizeof(BackupBlockJob), + .job_type = JOB_TYPE_BACKUP, + .free = block_job_free, ++ .user_resume = block_job_user_resume, + .start = backup_run, + }, + .commit = backup_commit, +diff --git a/block/commit.c b/block/commit.c +index 1c6cb6c..c4a98e5 100644 +--- a/block/commit.c ++++ b/block/commit.c +@@ -220,6 +220,7 @@ static const BlockJobDriver commit_job_driver = { + .instance_size = sizeof(CommitBlockJob), + .job_type = JOB_TYPE_COMMIT, + .free = block_job_free, ++ .user_resume = block_job_user_resume, + .start = commit_run, + }, + }; +diff --git a/block/mirror.c b/block/mirror.c +index 5d8f75c..9a7226f 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -991,6 +991,7 @@ static const BlockJobDriver mirror_job_driver = { + .instance_size = sizeof(MirrorBlockJob), + .job_type = JOB_TYPE_MIRROR, + .free = block_job_free, ++ .user_resume = block_job_user_resume, + .start = mirror_run, + .pause = mirror_pause, + }, +@@ -1004,6 +1005,7 @@ static const BlockJobDriver commit_active_job_driver = { + .instance_size = sizeof(MirrorBlockJob), + .job_type = JOB_TYPE_COMMIT, + .free = block_job_free, ++ .user_resume = block_job_user_resume, + .start = mirror_run, + .pause = mirror_pause, + }, +diff --git a/block/stream.c b/block/stream.c +index 1faab02..e81b488 100644 +--- a/block/stream.c ++++ b/block/stream.c +@@ -214,6 +214,7 @@ static const BlockJobDriver stream_job_driver = { + .job_type = JOB_TYPE_STREAM, + .free = block_job_free, + .start = stream_run, ++ .user_resume = block_job_user_resume, + }, + }; + +diff --git a/blockdev.c b/blockdev.c +index efb83c4..0fa1990 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -3891,7 +3891,7 @@ void qmp_block_job_cancel(const char *device, + force = false; + } + +- if (block_job_user_paused(job) && !force) { ++ if (job_user_paused(&job->job) && !force) { + error_setg(errp, "The block job for device '%s' is currently paused", + device); + goto out; +@@ -3913,7 +3913,7 @@ void qmp_block_job_pause(const char *device, Error **errp) + } + + trace_qmp_block_job_pause(job); +- block_job_user_pause(job, errp); ++ job_user_pause(&job->job, errp); + aio_context_release(aio_context); + } + +@@ -3927,7 +3927,7 @@ void qmp_block_job_resume(const char *device, Error **errp) + } + + trace_qmp_block_job_resume(job); +- block_job_user_resume(job, errp); ++ job_user_resume(&job->job, errp); + aio_context_release(aio_context); + } + +diff --git a/blockjob.c b/blockjob.c +index 4dc360c..6334a54 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -140,29 +140,6 @@ static void block_job_txn_del_job(BlockJob *job) + } + } + +-/* Assumes the job_mutex is held */ +-static bool job_timer_not_pending(Job *job) +-{ +- return !timer_pending(&job->sleep_timer); +-} +- +-static void block_job_pause(BlockJob *job) +-{ +- job->job.pause_count++; +-} +- +-static void block_job_resume(BlockJob *job) +-{ +- assert(job->job.pause_count > 0); +- job->job.pause_count--; +- if (job->job.pause_count) { +- return; +- } +- +- /* kick only if no timer is pending */ +- job_enter_cond(&job->job, job_timer_not_pending); +-} +- + static void block_job_attached_aio_context(AioContext *new_context, + void *opaque); + static void block_job_detach_aio_context(void *opaque); +@@ -193,7 +170,7 @@ static void block_job_attached_aio_context(AioContext *new_context, + job->driver->attached_aio_context(job, new_context); + } + +- block_job_resume(job); ++ job_resume(&job->job); + } + + static void block_job_drain(BlockJob *job) +@@ -214,7 +191,7 @@ static void block_job_detach_aio_context(void *opaque) + /* In case the job terminates during aio_poll()... */ + job_ref(&job->job); + +- block_job_pause(job); ++ job_pause(&job->job); + + while (!job->job.paused && !job->completed) { + block_job_drain(job); +@@ -233,13 +210,13 @@ static char *child_job_get_parent_desc(BdrvChild *c) + static void child_job_drained_begin(BdrvChild *c) + { + BlockJob *job = c->opaque; +- block_job_pause(job); ++ job_pause(&job->job); + } + + static void child_job_drained_end(BdrvChild *c) + { + BlockJob *job = c->opaque; +- block_job_resume(job); ++ job_resume(&job->job); + } + + static const BdrvChildRole child_job = { +@@ -396,9 +373,9 @@ static void block_job_cancel_async(BlockJob *job, bool force) + if (job->iostatus != BLOCK_DEVICE_IO_STATUS_OK) { + block_job_iostatus_reset(job); + } +- if (job->user_paused) { ++ if (job->job.user_paused) { + /* Do not call block_job_enter here, the caller will handle it. */ +- job->user_paused = false; ++ job->job.user_paused = false; + job->job.pause_count--; + } + job->job.cancelled = true; +@@ -628,39 +605,6 @@ void block_job_dismiss(BlockJob **jobptr, Error **errp) + *jobptr = NULL; + } + +-void block_job_user_pause(BlockJob *job, Error **errp) +-{ +- if (job_apply_verb(&job->job, JOB_VERB_PAUSE, errp)) { +- return; +- } +- if (job->user_paused) { +- error_setg(errp, "Job is already paused"); +- return; +- } +- job->user_paused = true; +- block_job_pause(job); +-} +- +-bool block_job_user_paused(BlockJob *job) +-{ +- return job->user_paused; +-} +- +-void block_job_user_resume(BlockJob *job, Error **errp) +-{ +- assert(job); +- if (!job->user_paused || job->job.pause_count <= 0) { +- error_setg(errp, "Can't resume a job that was not paused"); +- return; +- } +- if (job_apply_verb(&job->job, JOB_VERB_RESUME, errp)) { +- return; +- } +- block_job_iostatus_reset(job); +- job->user_paused = false; +- block_job_resume(job); +-} +- + void block_job_cancel(BlockJob *job, bool force) + { + if (job->job.status == JOB_STATUS_CONCLUDED) { +@@ -851,6 +795,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + + assert(is_block_job(&job->job)); + assert(job->job.driver->free == &block_job_free); ++ assert(job->job.driver->user_resume == &block_job_user_resume); + + job->driver = driver; + job->blk = blk; +@@ -941,10 +886,16 @@ void block_job_iostatus_reset(BlockJob *job) + if (job->iostatus == BLOCK_DEVICE_IO_STATUS_OK) { + return; + } +- assert(job->user_paused && job->job.pause_count > 0); ++ assert(job->job.user_paused && job->job.pause_count > 0); + job->iostatus = BLOCK_DEVICE_IO_STATUS_OK; + } + ++void block_job_user_resume(Job *job) ++{ ++ BlockJob *bjob = container_of(job, BlockJob, job); ++ block_job_iostatus_reset(bjob); ++} ++ + void block_job_event_ready(BlockJob *job) + { + job_state_transition(&job->job, JOB_STATUS_READY); +@@ -991,9 +942,9 @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err, + action, &error_abort); + } + if (action == BLOCK_ERROR_ACTION_STOP) { +- block_job_pause(job); ++ job_pause(&job->job); + /* make the pause user visible, which will be resumed from QMP. */ +- job->user_paused = true; ++ job->job.user_paused = true; + block_job_iostatus_set_err(job, error); + } + return action; +diff --git a/include/block/blockjob.h b/include/block/blockjob.h +index b60d919..556a8f6 100644 +--- a/include/block/blockjob.h ++++ b/include/block/blockjob.h +@@ -57,12 +57,6 @@ typedef struct BlockJob { + bool force; + + /** +- * Set to true if the job is paused by user. Can be unpaused with the +- * block-job-resume QMP command. +- */ +- bool user_paused; +- +- /** + * Set to true when the job is ready to be completed. + */ + bool ready; +@@ -248,32 +242,6 @@ void block_job_progress_set_remaining(BlockJob *job, uint64_t remaining); + BlockJobInfo *block_job_query(BlockJob *job, Error **errp); + + /** +- * block_job_user_pause: +- * @job: The job to be paused. +- * +- * Asynchronously pause the specified job. +- * Do not allow a resume until a matching call to block_job_user_resume. +- */ +-void block_job_user_pause(BlockJob *job, Error **errp); +- +-/** +- * block_job_paused: +- * @job: The job to query. +- * +- * Returns true if the job is user-paused. +- */ +-bool block_job_user_paused(BlockJob *job); +- +-/** +- * block_job_user_resume: +- * @job: The job to be resumed. +- * +- * Resume the specified job. +- * Must be paired with a preceding block_job_user_pause. +- */ +-void block_job_user_resume(BlockJob *job, Error **errp); +- +-/** + * block_job_user_cancel: + * @job: The job to be cancelled. + * @force: Quit a job without waiting for data to be in sync. +diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h +index 8937f5b..7e705ae 100644 +--- a/include/block/blockjob_int.h ++++ b/include/block/blockjob_int.h +@@ -134,6 +134,13 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + void block_job_free(Job *job); + + /** ++ * block_job_user_resume: ++ * Callback to be used for JobDriver.user_resume in all block jobs. Resets the ++ * iostatus when the user resumes @job. ++ */ ++void block_job_user_resume(Job *job); ++ ++/** + * block_job_yield: + * @job: The job that calls the function. + * +diff --git a/include/qemu/job.h b/include/qemu/job.h +index 509408f..bc63985 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -83,6 +83,12 @@ typedef struct Job { + bool paused; + + /** ++ * Set to true if the job is paused by user. Can be unpaused with the ++ * block-job-resume QMP command. ++ */ ++ bool user_paused; ++ ++ /** + * Set to true if the job should cancel itself. The flag must + * always be tested just before toggling the busy flag from false + * to true. After a job has been cancelled, it should only yield +@@ -124,6 +130,12 @@ struct JobDriver { + */ + void coroutine_fn (*resume)(Job *job); + ++ /** ++ * Called when the job is resumed by the user (i.e. user_paused becomes ++ * false). .user_resume is called before .resume. ++ */ ++ void (*user_resume)(Job *job); ++ + /** Called when the job is freed */ + void (*free)(Job *job); + }; +@@ -203,6 +215,31 @@ const char *job_type_str(const Job *job); + bool job_is_cancelled(Job *job); + + /** ++ * Request @job to pause at the next pause point. Must be paired with ++ * job_resume(). If the job is supposed to be resumed by user action, call ++ * job_user_pause() instead. ++ */ ++void job_pause(Job *job); ++ ++/** Resumes a @job paused with job_pause. */ ++void job_resume(Job *job); ++ ++/** ++ * Asynchronously pause the specified @job. ++ * Do not allow a resume until a matching call to job_user_resume. ++ */ ++void job_user_pause(Job *job, Error **errp); ++ ++/** Returns true if the job is user-paused. */ ++bool job_user_paused(Job *job); ++ ++/** ++ * Resume the specified @job. ++ * Must be paired with a preceding job_user_pause. ++ */ ++void job_user_resume(Job *job, Error **errp); ++ ++/** + * Get the next element from the list of block jobs after @job, or the + * first one if @job is %NULL. + * +diff --git a/job.c b/job.c +index 1b8cba1..fd10b1d 100644 +--- a/job.c ++++ b/job.c +@@ -341,6 +341,65 @@ void job_start(Job *job) + aio_co_enter(job->aio_context, job->co); + } + ++/* Assumes the block_job_mutex is held */ ++static bool job_timer_not_pending(Job *job) ++{ ++ return !timer_pending(&job->sleep_timer); ++} ++ ++void job_pause(Job *job) ++{ ++ job->pause_count++; ++} ++ ++void job_resume(Job *job) ++{ ++ assert(job->pause_count > 0); ++ job->pause_count--; ++ if (job->pause_count) { ++ return; ++ } ++ ++ /* kick only if no timer is pending */ ++ job_enter_cond(job, job_timer_not_pending); ++} ++ ++void job_user_pause(Job *job, Error **errp) ++{ ++ if (job_apply_verb(job, JOB_VERB_PAUSE, errp)) { ++ return; ++ } ++ if (job->user_paused) { ++ error_setg(errp, "Job is already paused"); ++ return; ++ } ++ job->user_paused = true; ++ job_pause(job); ++} ++ ++bool job_user_paused(Job *job) ++{ ++ return job->user_paused; ++} ++ ++void job_user_resume(Job *job, Error **errp) ++{ ++ assert(job); ++ if (!job->user_paused || job->pause_count <= 0) { ++ error_setg(errp, "Can't resume a job that was not paused"); ++ return; ++ } ++ if (job_apply_verb(job, JOB_VERB_RESUME, errp)) { ++ return; ++ } ++ if (job->driver->user_resume) { ++ job->driver->user_resume(job); ++ } ++ job->user_paused = false; ++ job_resume(job); ++} ++ ++ + typedef struct { + Job *job; + JobDeferToMainLoopFn *fn; +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index 50232f5..c993512 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -524,6 +524,7 @@ BlockJobDriver test_job_driver = { + .job_driver = { + .instance_size = sizeof(TestBlockJob), + .free = block_job_free, ++ .user_resume = block_job_user_resume, + .start = test_job_start, + }, + .complete = test_job_complete, +diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c +index 0e6162b..93d1ff0 100644 +--- a/tests/test-blockjob-txn.c ++++ b/tests/test-blockjob-txn.c +@@ -78,6 +78,7 @@ static const BlockJobDriver test_block_job_driver = { + .job_driver = { + .instance_size = sizeof(TestBlockJob), + .free = block_job_free, ++ .user_resume = block_job_user_resume, + .start = test_block_job_run, + }, + }; +diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c +index b329bd5..ceb5960 100644 +--- a/tests/test-blockjob.c ++++ b/tests/test-blockjob.c +@@ -20,6 +20,7 @@ static const BlockJobDriver test_block_job_driver = { + .job_driver = { + .instance_size = sizeof(BlockJob), + .free = block_job_free, ++ .user_resume = block_job_user_resume, + }, + }; + +@@ -199,6 +200,7 @@ static const BlockJobDriver test_cancel_driver = { + .job_driver = { + .instance_size = sizeof(CancelJob), + .free = block_job_free, ++ .user_resume = block_job_user_resume, + .start = cancel_job_start, + }, + .complete = cancel_job_complete, +@@ -270,7 +272,7 @@ static void test_cancel_paused(void) + job_start(&job->job); + assert(job->job.status == JOB_STATUS_RUNNING); + +- block_job_user_pause(job, &error_abort); ++ job_user_pause(&job->job, &error_abort); + block_job_enter(job); + assert(job->job.status == JOB_STATUS_PAUSED); + +@@ -308,7 +310,7 @@ static void test_cancel_standby(void) + block_job_enter(job); + assert(job->job.status == JOB_STATUS_READY); + +- block_job_user_pause(job, &error_abort); ++ job_user_pause(&job->job, &error_abort); + block_job_enter(job); + assert(job->job.status == JOB_STATUS_STANDBY); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Move-progress-fields-to-Job.patch b/SOURCES/kvm-job-Move-progress-fields-to-Job.patch new file mode 100644 index 0000000..fdf2694 --- /dev/null +++ b/SOURCES/kvm-job-Move-progress-fields-to-Job.patch @@ -0,0 +1,337 @@ +From 1da3dfa844e67f9948eddd18188307acb7f9fe95 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:29 +0200 +Subject: [PATCH 60/89] job: Move progress fields to Job + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-47-kwolf@redhat.com> +Patchwork-id: 81115 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 46/73] job: Move progress fields to Job +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +BlockJob has fields .offset and .len, which are actually misnomers today +because they are no longer tied to block device sizes, but just progress +counters. As such they make a lot of sense in generic Jobs. + +This patch moves the fields to Job and renames them to .progress_current +and .progress_total to describe their function better. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +(cherry picked from commit 30a5c887bf4a7e00d0e0ecbb08509e8ba2902620) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/backup.c | 8 ++++---- + block/commit.c | 4 ++-- + block/mirror.c | 4 ++-- + block/stream.c | 4 ++-- + blockjob.c | 26 ++++++++------------------ + include/block/blockjob.h | 25 ------------------------- + include/qemu/job.h | 28 ++++++++++++++++++++++++++++ + job.c | 10 ++++++++++ + qemu-img.c | 8 ++++++-- + 9 files changed, 62 insertions(+), 55 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index 6f4f3df..4e228e9 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -160,7 +160,7 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job, + * offset field is an opaque progress value, it is not a disk offset. + */ + job->bytes_read += n; +- block_job_progress_update(&job->common, n); ++ job_progress_update(&job->common.job, n); + } + + out: +@@ -406,8 +406,8 @@ static void backup_incremental_init_copy_bitmap(BackupBlockJob *job) + bdrv_set_dirty_iter(dbi, next_cluster * job->cluster_size); + } + +- /* TODO block_job_progress_set_remaining() would make more sense */ +- block_job_progress_update(&job->common, ++ /* TODO job_progress_set_remaining() would make more sense */ ++ job_progress_update(&job->common.job, + job->len - hbitmap_count(job->copy_bitmap) * job->cluster_size); + + bdrv_dirty_iter_free(dbi); +@@ -425,7 +425,7 @@ static void coroutine_fn backup_run(void *opaque) + qemu_co_rwlock_init(&job->flush_rwlock); + + nb_clusters = DIV_ROUND_UP(job->len, job->cluster_size); +- block_job_progress_set_remaining(&job->common, job->len); ++ job_progress_set_remaining(&job->common.job, job->len); + + job->copy_bitmap = hbitmap_alloc(nb_clusters, 0); + if (job->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) { +diff --git a/block/commit.c b/block/commit.c +index b0a847e..6206661 100644 +--- a/block/commit.c ++++ b/block/commit.c +@@ -150,7 +150,7 @@ static void coroutine_fn commit_run(void *opaque) + if (len < 0) { + goto out; + } +- block_job_progress_set_remaining(&s->common, len); ++ job_progress_set_remaining(&s->common.job, len); + + ret = base_len = blk_getlength(s->base); + if (base_len < 0) { +@@ -196,7 +196,7 @@ static void coroutine_fn commit_run(void *opaque) + } + } + /* Publish progress */ +- block_job_progress_update(&s->common, n); ++ job_progress_update(&s->common.job, n); + + if (copy) { + delay_ns = block_job_ratelimit_get_delay(&s->common, n); +diff --git a/block/mirror.c b/block/mirror.c +index bdc1b5b..dcb66ec 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -119,7 +119,7 @@ static void mirror_iteration_done(MirrorOp *op, int ret) + bitmap_set(s->cow_bitmap, chunk_num, nb_chunks); + } + if (!s->initial_zeroing_ongoing) { +- block_job_progress_update(&s->common, op->bytes); ++ job_progress_update(&s->common.job, op->bytes); + } + } + qemu_iovec_destroy(&op->qiov); +@@ -792,7 +792,7 @@ static void coroutine_fn mirror_run(void *opaque) + /* cnt is the number of dirty bytes remaining and s->bytes_in_flight is + * the number of bytes currently being processed; together those are + * the current remaining operation length */ +- block_job_progress_set_remaining(&s->common, s->bytes_in_flight + cnt); ++ job_progress_set_remaining(&s->common.job, s->bytes_in_flight + cnt); + + /* Note that even when no rate limit is applied we need to yield + * periodically with no pending I/O so that bdrv_drain_all() returns. +diff --git a/block/stream.c b/block/stream.c +index 8546c41..a5d6e0c 100644 +--- a/block/stream.c ++++ b/block/stream.c +@@ -121,7 +121,7 @@ static void coroutine_fn stream_run(void *opaque) + ret = len; + goto out; + } +- block_job_progress_set_remaining(&s->common, len); ++ job_progress_set_remaining(&s->common.job, len); + + buf = qemu_blockalign(bs, STREAM_BUFFER_SIZE); + +@@ -184,7 +184,7 @@ static void coroutine_fn stream_run(void *opaque) + ret = 0; + + /* Publish progress */ +- block_job_progress_update(&s->common, n); ++ job_progress_update(&s->common.job, n); + if (copy) { + delay_ns = block_job_ratelimit_get_delay(&s->common, n); + } else { +diff --git a/blockjob.c b/blockjob.c +index da11b3b..5c8ff6f 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -242,16 +242,6 @@ int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n) + return ratelimit_calculate_delay(&job->limit, n); + } + +-void block_job_progress_update(BlockJob *job, uint64_t done) +-{ +- job->offset += done; +-} +- +-void block_job_progress_set_remaining(BlockJob *job, uint64_t remaining) +-{ +- job->len = job->offset + remaining; +-} +- + BlockJobInfo *block_job_query(BlockJob *job, Error **errp) + { + BlockJobInfo *info; +@@ -263,10 +253,10 @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp) + info = g_new0(BlockJobInfo, 1); + info->type = g_strdup(job_type_str(&job->job)); + info->device = g_strdup(job->job.id); +- info->len = job->len; + info->busy = atomic_read(&job->job.busy); + info->paused = job->job.pause_count > 0; +- info->offset = job->offset; ++ info->offset = job->job.progress_current; ++ info->len = job->job.progress_total; + info->speed = job->speed; + info->io_status = job->iostatus; + info->ready = job_is_ready(&job->job), +@@ -296,8 +286,8 @@ static void block_job_event_cancelled(Notifier *n, void *opaque) + + qapi_event_send_block_job_cancelled(job_type(&job->job), + job->job.id, +- job->len, +- job->offset, ++ job->job.progress_total, ++ job->job.progress_current, + job->speed, + &error_abort); + } +@@ -317,8 +307,8 @@ static void block_job_event_completed(Notifier *n, void *opaque) + + qapi_event_send_block_job_completed(job_type(&job->job), + job->job.id, +- job->len, +- job->offset, ++ job->job.progress_total, ++ job->job.progress_current, + job->speed, + !!msg, + msg, +@@ -348,8 +338,8 @@ static void block_job_event_ready(Notifier *n, void *opaque) + + qapi_event_send_block_job_ready(job_type(&job->job), + job->job.id, +- job->len, +- job->offset, ++ job->job.progress_total, ++ job->job.progress_current, + job->speed, &error_abort); + } + +diff --git a/include/block/blockjob.h b/include/block/blockjob.h +index 4fca45f..3021d11 100644 +--- a/include/block/blockjob.h ++++ b/include/block/blockjob.h +@@ -52,12 +52,6 @@ typedef struct BlockJob { + /** Status that is published by the query-block-jobs QMP API */ + BlockDeviceIoStatus iostatus; + +- /** Offset that is published by the query-block-jobs QMP API */ +- int64_t offset; +- +- /** Length that is published by the query-block-jobs QMP API */ +- int64_t len; +- + /** Speed that was set with @block_job_set_speed. */ + int64_t speed; + +@@ -139,25 +133,6 @@ void block_job_remove_all_bdrv(BlockJob *job); + void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp); + + /** +- * block_job_progress_update: +- * @job: The job that has made progress +- * @done: How much progress the job made +- * +- * Updates the progress counter of the job. +- */ +-void block_job_progress_update(BlockJob *job, uint64_t done); +- +-/** +- * block_job_progress_set_remaining: +- * @job: The job whose expected progress end value is set +- * @remaining: Expected end value of the progress counter of the job +- * +- * Sets the expected end value of the progress counter of a job so that a +- * completion percentage can be calculated when the progress is updated. +- */ +-void block_job_progress_set_remaining(BlockJob *job, uint64_t remaining); +- +-/** + * block_job_query: + * @job: The job to get information about. + * +diff --git a/include/qemu/job.h b/include/qemu/job.h +index bfc2bc5..92d1d24 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -114,6 +114,16 @@ typedef struct Job { + /** True if this job should automatically dismiss itself */ + bool auto_dismiss; + ++ /** ++ * Current progress. The unit is arbitrary as long as the ratio between ++ * progress_current and progress_total represents the estimated percentage ++ * of work already done. ++ */ ++ int64_t progress_current; ++ ++ /** Estimated progress_current value at the completion of the job */ ++ int64_t progress_total; ++ + /** ret code passed to job_completed. */ + int ret; + +@@ -304,6 +314,24 @@ void job_ref(Job *job); + */ + void job_unref(Job *job); + ++/** ++ * @job: The job that has made progress ++ * @done: How much progress the job made since the last call ++ * ++ * Updates the progress counter of the job. ++ */ ++void job_progress_update(Job *job, uint64_t done); ++ ++/** ++ * @job: The job whose expected progress end value is set ++ * @remaining: Missing progress (on top of the current progress counter value) ++ * until the new expected end value is reached ++ * ++ * Sets the expected end value of the progress counter of a job so that a ++ * completion percentage can be calculated when the progress is updated. ++ */ ++void job_progress_set_remaining(Job *job, uint64_t remaining); ++ + /** To be called when a cancelled job is finalised. */ + void job_event_cancelled(Job *job); + +diff --git a/job.c b/job.c +index b5bd51b..2046d2f 100644 +--- a/job.c ++++ b/job.c +@@ -364,6 +364,16 @@ void job_unref(Job *job) + } + } + ++void job_progress_update(Job *job, uint64_t done) ++{ ++ job->progress_current += done; ++} ++ ++void job_progress_set_remaining(Job *job, uint64_t remaining) ++{ ++ job->progress_total = job->progress_current + remaining; ++} ++ + void job_event_cancelled(Job *job) + { + notifier_list_notify(&job->on_finalize_cancelled, job); +diff --git a/qemu-img.c b/qemu-img.c +index 3c449a2..9fc8e66 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -875,9 +875,13 @@ static void run_block_job(BlockJob *job, Error **errp) + aio_context_acquire(aio_context); + job_ref(&job->job); + do { ++ float progress = 0.0f; + aio_poll(aio_context, true); +- qemu_progress_print(job->len ? +- ((float)job->offset / job->len * 100.f) : 0.0f, 0); ++ if (job->job.progress_total) { ++ progress = (float)job->job.progress_current / ++ job->job.progress_total * 100.f; ++ } ++ qemu_progress_print(progress, 0); + } while (!job_is_ready(&job->job) && !job_is_completed(&job->job)); + + if (!job_is_completed(&job->job)) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Move-single-job-finalisation-to-Job.patch b/SOURCES/kvm-job-Move-single-job-finalisation-to-Job.patch new file mode 100644 index 0000000..473b584 --- /dev/null +++ b/SOURCES/kvm-job-Move-single-job-finalisation-to-Job.patch @@ -0,0 +1,736 @@ +From adcfa2a0ddbf68a34b24afcbfaaf03a19d1406ca Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:16 +0200 +Subject: [PATCH 47/89] job: Move single job finalisation to Job + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-34-kwolf@redhat.com> +Patchwork-id: 81070 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 33/73] job: Move single job finalisation to Job +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This moves the finalisation of a single job from BlockJob to Job. + +Some part of this code depends on job transactions, and job transactions +call this code, we introduce some temporary calls from Job functions to +BlockJob ones. This will be fixed once transactions move to Job, too. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +(cherry picked from commit 4ad351819b974d724e926fd23cdd66bec3c9768e) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/backup.c | 22 +++---- + block/commit.c | 2 +- + block/mirror.c | 2 +- + blockjob.c | 142 ++++++++----------------------------------- + include/block/blockjob.h | 9 --- + include/block/blockjob_int.h | 36 ----------- + include/qemu/job.h | 53 +++++++++++++++- + job.c | 100 +++++++++++++++++++++++++++++- + qemu-img.c | 2 +- + tests/test-blockjob.c | 10 +-- + 10 files changed, 194 insertions(+), 184 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index 4d011d5..bd31282 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -207,25 +207,25 @@ static void backup_cleanup_sync_bitmap(BackupBlockJob *job, int ret) + } + } + +-static void backup_commit(BlockJob *job) ++static void backup_commit(Job *job) + { +- BackupBlockJob *s = container_of(job, BackupBlockJob, common); ++ BackupBlockJob *s = container_of(job, BackupBlockJob, common.job); + if (s->sync_bitmap) { + backup_cleanup_sync_bitmap(s, 0); + } + } + +-static void backup_abort(BlockJob *job) ++static void backup_abort(Job *job) + { +- BackupBlockJob *s = container_of(job, BackupBlockJob, common); ++ BackupBlockJob *s = container_of(job, BackupBlockJob, common.job); + if (s->sync_bitmap) { + backup_cleanup_sync_bitmap(s, -1); + } + } + +-static void backup_clean(BlockJob *job) ++static void backup_clean(Job *job) + { +- BackupBlockJob *s = container_of(job, BackupBlockJob, common); ++ BackupBlockJob *s = container_of(job, BackupBlockJob, common.job); + assert(s->target); + blk_unref(s->target); + s->target = NULL; +@@ -530,10 +530,10 @@ static const BlockJobDriver backup_job_driver = { + .free = block_job_free, + .user_resume = block_job_user_resume, + .start = backup_run, ++ .commit = backup_commit, ++ .abort = backup_abort, ++ .clean = backup_clean, + }, +- .commit = backup_commit, +- .abort = backup_abort, +- .clean = backup_clean, + .attached_aio_context = backup_attached_aio_context, + .drain = backup_drain, + }; +@@ -678,8 +678,8 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, + bdrv_reclaim_dirty_bitmap(bs, sync_bitmap, NULL); + } + if (job) { +- backup_clean(&job->common); +- block_job_early_fail(&job->common); ++ backup_clean(&job->common.job); ++ job_early_fail(&job->common.job); + } + + return NULL; +diff --git a/block/commit.c b/block/commit.c +index 7a6ae59..e53b2d7 100644 +--- a/block/commit.c ++++ b/block/commit.c +@@ -385,7 +385,7 @@ fail: + if (commit_top_bs) { + bdrv_replace_node(commit_top_bs, top, &error_abort); + } +- block_job_early_fail(&s->common); ++ job_early_fail(&s->common.job); + } + + +diff --git a/block/mirror.c b/block/mirror.c +index 5091e72..e9a90ea 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -1257,7 +1257,7 @@ fail: + + g_free(s->replaces); + blk_unref(s->target); +- block_job_early_fail(&s->common); ++ job_early_fail(&s->common.job); + } + + bdrv_child_try_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL, +diff --git a/blockjob.c b/blockjob.c +index 05d7921..34c57da 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -127,7 +127,7 @@ void block_job_txn_add_job(BlockJobTxn *txn, BlockJob *job) + block_job_txn_ref(txn); + } + +-static void block_job_txn_del_job(BlockJob *job) ++void block_job_txn_del_job(BlockJob *job) + { + if (job->txn) { + QLIST_REMOVE(job, txn_list); +@@ -262,101 +262,12 @@ const BlockJobDriver *block_job_driver(BlockJob *job) + return job->driver; + } + +-static void block_job_decommission(BlockJob *job) +-{ +- assert(job); +- job->job.busy = false; +- job->job.paused = false; +- job->job.deferred_to_main_loop = true; +- block_job_txn_del_job(job); +- job_state_transition(&job->job, JOB_STATUS_NULL); +- job_unref(&job->job); +-} +- +-static void block_job_do_dismiss(BlockJob *job) +-{ +- block_job_decommission(job); +-} +- +-static void block_job_conclude(BlockJob *job) +-{ +- job_state_transition(&job->job, JOB_STATUS_CONCLUDED); +- if (job->job.auto_dismiss || !job_started(&job->job)) { +- block_job_do_dismiss(job); +- } +-} +- +-static void block_job_update_rc(BlockJob *job) +-{ +- if (!job->ret && job_is_cancelled(&job->job)) { +- job->ret = -ECANCELED; +- } +- if (job->ret) { +- job_state_transition(&job->job, JOB_STATUS_ABORTING); +- } +-} +- + static int block_job_prepare(BlockJob *job) + { +- if (job->ret == 0 && job->driver->prepare) { +- job->ret = job->driver->prepare(job); +- } +- return job->ret; +-} +- +-static void block_job_commit(BlockJob *job) +-{ +- assert(!job->ret); +- if (job->driver->commit) { +- job->driver->commit(job); +- } +-} +- +-static void block_job_abort(BlockJob *job) +-{ +- assert(job->ret); +- if (job->driver->abort) { +- job->driver->abort(job); +- } +-} +- +-static void block_job_clean(BlockJob *job) +-{ +- if (job->driver->clean) { +- job->driver->clean(job); ++ if (job->job.ret == 0 && job->driver->prepare) { ++ job->job.ret = job->driver->prepare(job); + } +-} +- +-static int block_job_finalize_single(BlockJob *job) +-{ +- assert(job_is_completed(&job->job)); +- +- /* Ensure abort is called for late-transactional failures */ +- block_job_update_rc(job); +- +- if (!job->ret) { +- block_job_commit(job); +- } else { +- block_job_abort(job); +- } +- block_job_clean(job); +- +- if (job->cb) { +- job->cb(job->opaque, job->ret); +- } +- +- /* Emit events only if we actually started */ +- if (job_started(&job->job)) { +- if (job_is_cancelled(&job->job)) { +- job_event_cancelled(&job->job); +- } else { +- job_event_completed(&job->job); +- } +- } +- +- block_job_txn_del_job(job); +- block_job_conclude(job); +- return 0; ++ return job->job.ret; + } + + static void block_job_cancel_async(BlockJob *job, bool force) +@@ -424,8 +335,8 @@ static int block_job_finish_sync(BlockJob *job, + while (!job_is_completed(&job->job)) { + aio_poll(qemu_get_aio_context(), true); + } +- ret = (job_is_cancelled(&job->job) && job->ret == 0) +- ? -ECANCELED : job->ret; ++ ret = (job_is_cancelled(&job->job) && job->job.ret == 0) ++ ? -ECANCELED : job->job.ret; + job_unref(&job->job); + return ret; + } +@@ -466,7 +377,7 @@ static void block_job_completed_txn_abort(BlockJob *job) + assert(job_is_cancelled(&other_job->job)); + block_job_finish_sync(other_job, NULL, NULL); + } +- block_job_finalize_single(other_job); ++ job_finalize_single(&other_job->job); + aio_context_release(ctx); + } + +@@ -478,6 +389,11 @@ static int block_job_needs_finalize(BlockJob *job) + return !job->job.auto_finalize; + } + ++static int block_job_finalize_single(BlockJob *job) ++{ ++ return job_finalize_single(&job->job); ++} ++ + static void block_job_do_finalize(BlockJob *job) + { + int rc; +@@ -516,7 +432,7 @@ static void block_job_completed_txn_success(BlockJob *job) + if (!job_is_completed(&other_job->job)) { + return; + } +- assert(other_job->ret == 0); ++ assert(other_job->job.ret == 0); + } + + block_job_txn_apply(txn, block_job_transition_to_pending, false); +@@ -601,14 +517,14 @@ void block_job_dismiss(BlockJob **jobptr, Error **errp) + return; + } + +- block_job_do_dismiss(job); ++ job_do_dismiss(&job->job); + *jobptr = NULL; + } + + void block_job_cancel(BlockJob *job, bool force) + { + if (job->job.status == JOB_STATUS_CONCLUDED) { +- block_job_do_dismiss(job); ++ job_do_dismiss(&job->job); + return; + } + block_job_cancel_async(job, force); +@@ -691,8 +607,8 @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp) + info->status = job->job.status; + info->auto_finalize = job->job.auto_finalize; + info->auto_dismiss = job->job.auto_dismiss; +- info->has_error = job->ret != 0; +- info->error = job->ret ? g_strdup(strerror(-job->ret)) : NULL; ++ info->has_error = job->job.ret != 0; ++ info->error = job->job.ret ? g_strdup(strerror(-job->job.ret)) : NULL; + return info; + } + +@@ -729,8 +645,8 @@ static void block_job_event_completed(Notifier *n, void *opaque) + return; + } + +- if (job->ret < 0) { +- msg = strerror(-job->ret); ++ if (job->job.ret < 0) { ++ msg = strerror(-job->job.ret); + } + + qapi_event_send_block_job_completed(job_type(&job->job), +@@ -787,7 +703,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + } + + job = job_create(job_id, &driver->job_driver, blk_get_aio_context(blk), +- flags, errp); ++ flags, cb, opaque, errp); + if (job == NULL) { + blk_unref(blk); + return NULL; +@@ -799,8 +715,6 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + + job->driver = driver; + job->blk = blk; +- job->cb = cb; +- job->opaque = opaque; + + job->finalize_cancelled_notifier.notify = block_job_event_cancelled; + job->finalize_completed_notifier.notify = block_job_event_completed; +@@ -828,7 +742,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + + block_job_set_speed(job, speed, &local_err); + if (local_err) { +- block_job_early_fail(job); ++ job_early_fail(&job->job); + error_propagate(errp, local_err); + return NULL; + } +@@ -847,20 +761,14 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + return job; + } + +-void block_job_early_fail(BlockJob *job) +-{ +- assert(job->job.status == JOB_STATUS_CREATED); +- block_job_decommission(job); +-} +- + void block_job_completed(BlockJob *job, int ret) + { + assert(job && job->txn && !job_is_completed(&job->job)); + assert(blk_bs(job->blk)->job == job); +- job->ret = ret; +- block_job_update_rc(job); +- trace_block_job_completed(job, ret, job->ret); +- if (job->ret) { ++ job->job.ret = ret; ++ job_update_rc(&job->job); ++ trace_block_job_completed(job, ret, job->job.ret); ++ if (job->job.ret) { + block_job_completed_txn_abort(job); + } else { + block_job_completed_txn_success(job); +diff --git a/include/block/blockjob.h b/include/block/blockjob.h +index aef0629..3f405d1 100644 +--- a/include/block/blockjob.h ++++ b/include/block/blockjob.h +@@ -76,9 +76,6 @@ typedef struct BlockJob { + /** Rate limiting data structure for implementing @speed. */ + RateLimit limit; + +- /** The completion function that will be called when the job completes. */ +- BlockCompletionFunc *cb; +- + /** Block other operations when block job is running */ + Error *blocker; + +@@ -94,12 +91,6 @@ typedef struct BlockJob { + /** BlockDriverStates that are involved in this block job */ + GSList *nodes; + +- /** The opaque value that is passed to the completion function. */ +- void *opaque; +- +- /** ret code passed to block_job_completed. */ +- int ret; +- + BlockJobTxn *txn; + QLIST_ENTRY(BlockJob) txn_list; + } BlockJob; +diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h +index 88639f7..bf2b762 100644 +--- a/include/block/blockjob_int.h ++++ b/include/block/blockjob_int.h +@@ -54,34 +54,6 @@ struct BlockJobDriver { + */ + int (*prepare)(BlockJob *job); + +- /** +- * If the callback is not NULL, it will be invoked when all the jobs +- * belonging to the same transaction complete; or upon this job's +- * completion if it is not in a transaction. Skipped if NULL. +- * +- * All jobs will complete with a call to either .commit() or .abort() but +- * never both. +- */ +- void (*commit)(BlockJob *job); +- +- /** +- * If the callback is not NULL, it will be invoked when any job in the +- * same transaction fails; or upon this job's failure (due to error or +- * cancellation) if it is not in a transaction. Skipped if NULL. +- * +- * All jobs will complete with a call to either .commit() or .abort() but +- * never both. +- */ +- void (*abort)(BlockJob *job); +- +- /** +- * If the callback is not NULL, it will be invoked after a call to either +- * .commit() or .abort(). Regardless of which callback is invoked after +- * completion, .clean() will always be called, even if the job does not +- * belong to a transaction group. +- */ +- void (*clean)(BlockJob *job); +- + /* + * If the callback is not NULL, it will be invoked before the job is + * resumed in a new AioContext. This is the place to move any resources +@@ -156,14 +128,6 @@ void block_job_yield(BlockJob *job); + int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n); + + /** +- * block_job_early_fail: +- * @bs: The block device. +- * +- * The block job could not be started, free it. +- */ +-void block_job_early_fail(BlockJob *job); +- +-/** + * block_job_completed: + * @job: The job being completed. + * @ret: The status code. +diff --git a/include/qemu/job.h b/include/qemu/job.h +index 14d9377..3e817be 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -29,6 +29,7 @@ + #include "qapi/qapi-types-block-core.h" + #include "qemu/queue.h" + #include "qemu/coroutine.h" ++#include "block/aio.h" + + typedef struct JobDriver JobDriver; + +@@ -105,6 +106,15 @@ typedef struct Job { + /** True if this job should automatically dismiss itself */ + bool auto_dismiss; + ++ /** ret code passed to block_job_completed. */ ++ int ret; ++ ++ /** The completion function that will be called when the job completes. */ ++ BlockCompletionFunc *cb; ++ ++ /** The opaque value that is passed to the completion function. */ ++ void *opaque; ++ + /** Notifiers called when a cancelled job is finalised */ + NotifierList on_finalize_cancelled; + +@@ -151,6 +161,35 @@ struct JobDriver { + */ + void (*user_resume)(Job *job); + ++ /** ++ * If the callback is not NULL, it will be invoked when all the jobs ++ * belonging to the same transaction complete; or upon this job's ++ * completion if it is not in a transaction. Skipped if NULL. ++ * ++ * All jobs will complete with a call to either .commit() or .abort() but ++ * never both. ++ */ ++ void (*commit)(Job *job); ++ ++ /** ++ * If the callback is not NULL, it will be invoked when any job in the ++ * same transaction fails; or upon this job's failure (due to error or ++ * cancellation) if it is not in a transaction. Skipped if NULL. ++ * ++ * All jobs will complete with a call to either .commit() or .abort() but ++ * never both. ++ */ ++ void (*abort)(Job *job); ++ ++ /** ++ * If the callback is not NULL, it will be invoked after a call to either ++ * .commit() or .abort(). Regardless of which callback is invoked after ++ * completion, .clean() will always be called, even if the job does not ++ * belong to a transaction group. ++ */ ++ void (*clean)(Job *job); ++ ++ + /** Called when the job is freed */ + void (*free)(Job *job); + }; +@@ -174,10 +213,12 @@ typedef enum JobCreateFlags { + * @driver: The class object for the newly-created job. + * @ctx: The AioContext to run the job coroutine in. + * @flags: Creation flags for the job. See @JobCreateFlags. ++ * @cb: Completion function for the job. ++ * @opaque: Opaque pointer value passed to @cb. + * @errp: Error object. + */ + void *job_create(const char *job_id, const JobDriver *driver, AioContext *ctx, +- int flags, Error **errp); ++ int flags, BlockCompletionFunc *cb, void *opaque, Error **errp); + + /** + * Add a reference to Job refcnt, it will be decreased with job_unref, and then +@@ -300,6 +341,10 @@ Job *job_get(const char *id); + */ + int job_apply_verb(Job *job, JobVerb verb, Error **errp); + ++/** The @job could not be started, free it. */ ++void job_early_fail(Job *job); ++ ++ + typedef void JobDeferToMainLoopFn(Job *job, void *opaque); + + /** +@@ -322,5 +367,11 @@ void job_state_transition(Job *job, JobStatus s1); + void coroutine_fn job_do_yield(Job *job, uint64_t ns); + bool job_should_pause(Job *job); + bool job_started(Job *job); ++void job_do_dismiss(Job *job); ++int job_finalize_single(Job *job); ++void job_update_rc(Job *job); ++ ++typedef struct BlockJob BlockJob; ++void block_job_txn_del_job(BlockJob *job); + + #endif +diff --git a/job.c b/job.c +index 817c3b4..64b64da 100644 +--- a/job.c ++++ b/job.c +@@ -85,7 +85,7 @@ void job_state_transition(Job *job, JobStatus s1) + { + JobStatus s0 = job->status; + assert(s1 >= 0 && s1 <= JOB_STATUS__MAX); +- trace_job_state_transition(job, /* TODO re-enable: job->ret */ 0, ++ trace_job_state_transition(job, job->ret, + JobSTT[s0][s1] ? "allowed" : "disallowed", + JobStatus_str(s0), JobStatus_str(s1)); + assert(JobSTT[s0][s1]); +@@ -182,7 +182,7 @@ static void job_sleep_timer_cb(void *opaque) + } + + void *job_create(const char *job_id, const JobDriver *driver, AioContext *ctx, +- int flags, Error **errp) ++ int flags, BlockCompletionFunc *cb, void *opaque, Error **errp) + { + Job *job; + +@@ -214,6 +214,8 @@ void *job_create(const char *job_id, const JobDriver *driver, AioContext *ctx, + job->pause_count = 1; + job->auto_finalize = !(flags & JOB_MANUAL_FINALIZE); + job->auto_dismiss = !(flags & JOB_MANUAL_DISMISS); ++ job->cb = cb; ++ job->opaque = opaque; + + notifier_list_init(&job->on_finalize_cancelled); + notifier_list_init(&job->on_finalize_completed); +@@ -449,6 +451,100 @@ void job_user_resume(Job *job, Error **errp) + job_resume(job); + } + ++void job_do_dismiss(Job *job) ++{ ++ assert(job); ++ job->busy = false; ++ job->paused = false; ++ job->deferred_to_main_loop = true; ++ ++ /* TODO Don't assume it's a BlockJob */ ++ block_job_txn_del_job((BlockJob*) job); ++ ++ job_state_transition(job, JOB_STATUS_NULL); ++ job_unref(job); ++} ++ ++void job_early_fail(Job *job) ++{ ++ assert(job->status == JOB_STATUS_CREATED); ++ job_do_dismiss(job); ++} ++ ++static void job_conclude(Job *job) ++{ ++ job_state_transition(job, JOB_STATUS_CONCLUDED); ++ if (job->auto_dismiss || !job_started(job)) { ++ job_do_dismiss(job); ++ } ++} ++ ++void job_update_rc(Job *job) ++{ ++ if (!job->ret && job_is_cancelled(job)) { ++ job->ret = -ECANCELED; ++ } ++ if (job->ret) { ++ job_state_transition(job, JOB_STATUS_ABORTING); ++ } ++} ++ ++static void job_commit(Job *job) ++{ ++ assert(!job->ret); ++ if (job->driver->commit) { ++ job->driver->commit(job); ++ } ++} ++ ++static void job_abort(Job *job) ++{ ++ assert(job->ret); ++ if (job->driver->abort) { ++ job->driver->abort(job); ++ } ++} ++ ++static void job_clean(Job *job) ++{ ++ if (job->driver->clean) { ++ job->driver->clean(job); ++ } ++} ++ ++int job_finalize_single(Job *job) ++{ ++ assert(job_is_completed(job)); ++ ++ /* Ensure abort is called for late-transactional failures */ ++ job_update_rc(job); ++ ++ if (!job->ret) { ++ job_commit(job); ++ } else { ++ job_abort(job); ++ } ++ job_clean(job); ++ ++ if (job->cb) { ++ job->cb(job->opaque, job->ret); ++ } ++ ++ /* Emit events only if we actually started */ ++ if (job_started(job)) { ++ if (job_is_cancelled(job)) { ++ job_event_cancelled(job); ++ } else { ++ job_event_completed(job); ++ } ++ } ++ ++ /* TODO Don't assume it's a BlockJob */ ++ block_job_txn_del_job((BlockJob*) job); ++ job_conclude(job); ++ return 0; ++} ++ + + typedef struct { + Job *job; +diff --git a/qemu-img.c b/qemu-img.c +index 843dc6a..91b3151 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -883,7 +883,7 @@ static void run_block_job(BlockJob *job, Error **errp) + if (!job_is_completed(&job->job)) { + ret = block_job_complete_sync(job, errp); + } else { +- ret = job->ret; ++ ret = job->job.ret; + } + job_unref(&job->job); + aio_context_release(aio_context); +diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c +index 8bb0aa8..1fe6803 100644 +--- a/tests/test-blockjob.c ++++ b/tests/test-blockjob.c +@@ -128,11 +128,11 @@ static void test_job_ids(void) + job[1] = do_test_id(blk[1], "id0", false); + + /* But once job[0] finishes we can reuse its ID */ +- block_job_early_fail(job[0]); ++ job_early_fail(&job[0]->job); + job[1] = do_test_id(blk[1], "id0", true); + + /* No job ID specified, defaults to the backend name ('drive1') */ +- block_job_early_fail(job[1]); ++ job_early_fail(&job[1]->job); + job[1] = do_test_id(blk[1], NULL, true); + + /* Duplicate job ID */ +@@ -145,9 +145,9 @@ static void test_job_ids(void) + /* This one is valid */ + job[2] = do_test_id(blk[2], "id_2", true); + +- block_job_early_fail(job[0]); +- block_job_early_fail(job[1]); +- block_job_early_fail(job[2]); ++ job_early_fail(&job[0]->job); ++ job_early_fail(&job[1]->job); ++ job_early_fail(&job[2]->job); + + destroy_blk(blk[0]); + destroy_blk(blk[1]); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Move-state-transitions-to-Job.patch b/SOURCES/kvm-job-Move-state-transitions-to-Job.patch new file mode 100644 index 0000000..880a1f7 --- /dev/null +++ b/SOURCES/kvm-job-Move-state-transitions-to-Job.patch @@ -0,0 +1,640 @@ +From bb250647bab72a20db342030756d1837b91bc91a Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:04 +0200 +Subject: [PATCH 35/89] job: Move state transitions to Job + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-22-kwolf@redhat.com> +Patchwork-id: 81093 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 21/73] job: Move state transitions to Job +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This moves BlockJob.status and the closely related functions +(block_)job_state_transition() and (block_)job_apply_verb to Job. The +two QAPI enums are renamed to JobStatus and JobVerb. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +Reviewed-by: John Snow +Reviewed-by: Eric Blake +(cherry picked from commit a50c2ab858fe613fb805e53b4f6b970ab936706d) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/trace-events | 2 - + blockjob.c | 102 +++++++++++------------------------------------ + include/block/blockjob.h | 3 -- + include/qemu/job.h | 13 ++++++ + job.c | 56 ++++++++++++++++++++++++++ + qapi/block-core.json | 16 ++++---- + tests/test-blockjob.c | 39 +++++++++--------- + trace-events | 4 ++ + 8 files changed, 123 insertions(+), 112 deletions(-) + +diff --git a/block/trace-events b/block/trace-events +index f8c50b4..93b9279 100644 +--- a/block/trace-events ++++ b/block/trace-events +@@ -6,8 +6,6 @@ bdrv_lock_medium(void *bs, bool locked) "bs %p locked %d" + + # blockjob.c + block_job_completed(void *job, int ret, int jret) "job %p ret %d corrected ret %d" +-block_job_state_transition(void *job, int ret, const char *legal, const char *s0, const char *s1) "job %p (ret: %d) attempting %s transition (%s-->%s)" +-block_job_apply_verb(void *job, const char *state, const char *verb, const char *legal) "job %p in state %s; applying verb %s (%s)" + + # block/block-backend.c + blk_co_preadv(void *blk, void *bs, int64_t offset, unsigned int bytes, int flags) "blk %p bs %p offset %"PRId64" bytes %u flags 0x%x" +diff --git a/blockjob.c b/blockjob.c +index c69b2e7..0fba01e 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -41,61 +41,6 @@ + * block_job_enter. */ + static QemuMutex block_job_mutex; + +-/* BlockJob State Transition Table */ +-bool BlockJobSTT[BLOCK_JOB_STATUS__MAX][BLOCK_JOB_STATUS__MAX] = { +- /* U, C, R, P, Y, S, W, D, X, E, N */ +- /* U: */ [BLOCK_JOB_STATUS_UNDEFINED] = {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- /* C: */ [BLOCK_JOB_STATUS_CREATED] = {0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1}, +- /* R: */ [BLOCK_JOB_STATUS_RUNNING] = {0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0}, +- /* P: */ [BLOCK_JOB_STATUS_PAUSED] = {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, +- /* Y: */ [BLOCK_JOB_STATUS_READY] = {0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0}, +- /* S: */ [BLOCK_JOB_STATUS_STANDBY] = {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, +- /* W: */ [BLOCK_JOB_STATUS_WAITING] = {0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, +- /* D: */ [BLOCK_JOB_STATUS_PENDING] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0}, +- /* X: */ [BLOCK_JOB_STATUS_ABORTING] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0}, +- /* E: */ [BLOCK_JOB_STATUS_CONCLUDED] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, +- /* N: */ [BLOCK_JOB_STATUS_NULL] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +-}; +- +-bool BlockJobVerbTable[BLOCK_JOB_VERB__MAX][BLOCK_JOB_STATUS__MAX] = { +- /* U, C, R, P, Y, S, W, D, X, E, N */ +- [BLOCK_JOB_VERB_CANCEL] = {0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0}, +- [BLOCK_JOB_VERB_PAUSE] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}, +- [BLOCK_JOB_VERB_RESUME] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}, +- [BLOCK_JOB_VERB_SET_SPEED] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}, +- [BLOCK_JOB_VERB_COMPLETE] = {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, +- [BLOCK_JOB_VERB_FINALIZE] = {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, +- [BLOCK_JOB_VERB_DISMISS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, +-}; +- +-static void block_job_state_transition(BlockJob *job, BlockJobStatus s1) +-{ +- BlockJobStatus s0 = job->status; +- assert(s1 >= 0 && s1 <= BLOCK_JOB_STATUS__MAX); +- trace_block_job_state_transition(job, job->ret, BlockJobSTT[s0][s1] ? +- "allowed" : "disallowed", +- BlockJobStatus_str(s0), +- BlockJobStatus_str(s1)); +- assert(BlockJobSTT[s0][s1]); +- job->status = s1; +-} +- +-static int block_job_apply_verb(BlockJob *job, BlockJobVerb bv, Error **errp) +-{ +- assert(bv >= 0 && bv <= BLOCK_JOB_VERB__MAX); +- trace_block_job_apply_verb(job, BlockJobStatus_str(job->status), +- BlockJobVerb_str(bv), +- BlockJobVerbTable[bv][job->status] ? +- "allowed" : "prohibited"); +- if (BlockJobVerbTable[bv][job->status]) { +- return 0; +- } +- error_setg(errp, "Job '%s' in state '%s' cannot accept command verb '%s'", +- job->job.id, BlockJobStatus_str(job->status), +- BlockJobVerb_str(bv)); +- return -EPERM; +-} +- + static void block_job_lock(void) + { + qemu_mutex_lock(&block_job_mutex); +@@ -257,7 +202,7 @@ static void block_job_detach_aio_context(void *opaque); + void block_job_unref(BlockJob *job) + { + if (--job->refcnt == 0) { +- assert(job->status == BLOCK_JOB_STATUS_NULL); ++ assert(job->job.status == JOB_STATUS_NULL); + assert(!job->txn); + BlockDriverState *bs = blk_bs(job->blk); + bs->job = NULL; +@@ -409,7 +354,7 @@ void block_job_start(BlockJob *job) + job->pause_count--; + job->busy = true; + job->paused = false; +- block_job_state_transition(job, BLOCK_JOB_STATUS_RUNNING); ++ job_state_transition(&job->job, JOB_STATUS_RUNNING); + bdrv_coroutine_enter(blk_bs(job->blk), job->co); + } + +@@ -421,7 +366,7 @@ static void block_job_decommission(BlockJob *job) + job->paused = false; + job->deferred_to_main_loop = true; + block_job_txn_del_job(job); +- block_job_state_transition(job, BLOCK_JOB_STATUS_NULL); ++ job_state_transition(&job->job, JOB_STATUS_NULL); + block_job_unref(job); + } + +@@ -432,7 +377,7 @@ static void block_job_do_dismiss(BlockJob *job) + + static void block_job_conclude(BlockJob *job) + { +- block_job_state_transition(job, BLOCK_JOB_STATUS_CONCLUDED); ++ job_state_transition(&job->job, JOB_STATUS_CONCLUDED); + if (job->auto_dismiss || !block_job_started(job)) { + block_job_do_dismiss(job); + } +@@ -444,7 +389,7 @@ static void block_job_update_rc(BlockJob *job) + job->ret = -ECANCELED; + } + if (job->ret) { +- block_job_state_transition(job, BLOCK_JOB_STATUS_ABORTING); ++ job_state_transition(&job->job, JOB_STATUS_ABORTING); + } + } + +@@ -652,7 +597,7 @@ static void block_job_completed_txn_success(BlockJob *job) + BlockJobTxn *txn = job->txn; + BlockJob *other_job; + +- block_job_state_transition(job, BLOCK_JOB_STATUS_WAITING); ++ job_state_transition(&job->job, JOB_STATUS_WAITING); + + /* + * Successful completion, see if there are other running jobs in this +@@ -677,7 +622,7 @@ void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) + { + int64_t old_speed = job->speed; + +- if (block_job_apply_verb(job, BLOCK_JOB_VERB_SET_SPEED, errp)) { ++ if (job_apply_verb(&job->job, JOB_VERB_SET_SPEED, errp)) { + return; + } + if (speed < 0) { +@@ -709,7 +654,7 @@ void block_job_complete(BlockJob *job, Error **errp) + { + /* Should not be reachable via external interface for internal jobs */ + assert(job->job.id); +- if (block_job_apply_verb(job, BLOCK_JOB_VERB_COMPLETE, errp)) { ++ if (job_apply_verb(&job->job, JOB_VERB_COMPLETE, errp)) { + return; + } + if (job->pause_count || job->cancelled || !job->driver->complete) { +@@ -724,7 +669,7 @@ void block_job_complete(BlockJob *job, Error **errp) + void block_job_finalize(BlockJob *job, Error **errp) + { + assert(job && job->job.id); +- if (block_job_apply_verb(job, BLOCK_JOB_VERB_FINALIZE, errp)) { ++ if (job_apply_verb(&job->job, JOB_VERB_FINALIZE, errp)) { + return; + } + block_job_do_finalize(job); +@@ -735,7 +680,7 @@ void block_job_dismiss(BlockJob **jobptr, Error **errp) + BlockJob *job = *jobptr; + /* similarly to _complete, this is QMP-interface only. */ + assert(job->job.id); +- if (block_job_apply_verb(job, BLOCK_JOB_VERB_DISMISS, errp)) { ++ if (job_apply_verb(&job->job, JOB_VERB_DISMISS, errp)) { + return; + } + +@@ -745,7 +690,7 @@ void block_job_dismiss(BlockJob **jobptr, Error **errp) + + void block_job_user_pause(BlockJob *job, Error **errp) + { +- if (block_job_apply_verb(job, BLOCK_JOB_VERB_PAUSE, errp)) { ++ if (job_apply_verb(&job->job, JOB_VERB_PAUSE, errp)) { + return; + } + if (job->user_paused) { +@@ -768,7 +713,7 @@ void block_job_user_resume(BlockJob *job, Error **errp) + error_setg(errp, "Can't resume a job that was not paused"); + return; + } +- if (block_job_apply_verb(job, BLOCK_JOB_VERB_RESUME, errp)) { ++ if (job_apply_verb(&job->job, JOB_VERB_RESUME, errp)) { + return; + } + block_job_iostatus_reset(job); +@@ -778,7 +723,7 @@ void block_job_user_resume(BlockJob *job, Error **errp) + + void block_job_cancel(BlockJob *job, bool force) + { +- if (job->status == BLOCK_JOB_STATUS_CONCLUDED) { ++ if (job->job.status == JOB_STATUS_CONCLUDED) { + block_job_do_dismiss(job); + return; + } +@@ -794,7 +739,7 @@ void block_job_cancel(BlockJob *job, bool force) + + void block_job_user_cancel(BlockJob *job, bool force, Error **errp) + { +- if (block_job_apply_verb(job, BLOCK_JOB_VERB_CANCEL, errp)) { ++ if (job_apply_verb(&job->job, JOB_VERB_CANCEL, errp)) { + return; + } + block_job_cancel(job, force); +@@ -859,7 +804,7 @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp) + info->speed = job->speed; + info->io_status = job->iostatus; + info->ready = job->ready; +- info->status = job->status; ++ info->status = job->job.status; + info->auto_finalize = job->auto_finalize; + info->auto_dismiss = job->auto_dismiss; + info->has_error = job->ret != 0; +@@ -907,7 +852,7 @@ static void block_job_event_completed(BlockJob *job, const char *msg) + + static int block_job_event_pending(BlockJob *job) + { +- block_job_state_transition(job, BLOCK_JOB_STATUS_PENDING); ++ job_state_transition(&job->job, JOB_STATUS_PENDING); + if (!job->auto_finalize && !block_job_is_internal(job)) { + qapi_event_send_block_job_pending(job_type(&job->job), + job->job.id, +@@ -975,7 +920,6 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + job->refcnt = 1; + job->auto_finalize = !(flags & BLOCK_JOB_MANUAL_FINALIZE); + job->auto_dismiss = !(flags & BLOCK_JOB_MANUAL_DISMISS); +- block_job_state_transition(job, BLOCK_JOB_STATUS_CREATED); + aio_timer_init(qemu_get_aio_context(), &job->sleep_timer, + QEMU_CLOCK_REALTIME, SCALE_NS, + block_job_sleep_timer_cb, job); +@@ -1017,7 +961,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + + void block_job_early_fail(BlockJob *job) + { +- assert(job->status == BLOCK_JOB_STATUS_CREATED); ++ assert(job->job.status == JOB_STATUS_CREATED); + block_job_decommission(job); + } + +@@ -1077,14 +1021,14 @@ void coroutine_fn block_job_pause_point(BlockJob *job) + } + + if (block_job_should_pause(job) && !block_job_is_cancelled(job)) { +- BlockJobStatus status = job->status; +- block_job_state_transition(job, status == BLOCK_JOB_STATUS_READY ? \ +- BLOCK_JOB_STATUS_STANDBY : \ +- BLOCK_JOB_STATUS_PAUSED); ++ JobStatus status = job->job.status; ++ job_state_transition(&job->job, status == JOB_STATUS_READY ++ ? JOB_STATUS_STANDBY ++ : JOB_STATUS_PAUSED); + job->paused = true; + block_job_do_yield(job, -1); + job->paused = false; +- block_job_state_transition(job, status); ++ job_state_transition(&job->job, status); + } + + if (job->driver->resume) { +@@ -1176,7 +1120,7 @@ void block_job_iostatus_reset(BlockJob *job) + + void block_job_event_ready(BlockJob *job) + { +- block_job_state_transition(job, BLOCK_JOB_STATUS_READY); ++ job_state_transition(&job->job, JOB_STATUS_READY); + job->ready = true; + + if (block_job_is_internal(job)) { +diff --git a/include/block/blockjob.h b/include/block/blockjob.h +index 10bd9f7..01cdee6 100644 +--- a/include/block/blockjob.h ++++ b/include/block/blockjob.h +@@ -147,9 +147,6 @@ typedef struct BlockJob { + */ + QEMUTimer sleep_timer; + +- /** Current state; See @BlockJobStatus for details. */ +- BlockJobStatus status; +- + /** True if this job should automatically finalize itself */ + bool auto_finalize; + +diff --git a/include/qemu/job.h b/include/qemu/job.h +index bae2b09..0b78778 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -41,6 +41,9 @@ typedef struct Job { + /** The type of this job. */ + const JobDriver *driver; + ++ /** Current state; See @JobStatus for details. */ ++ JobStatus status; ++ + /** Element of the list of jobs */ + QLIST_ENTRY(Job) job_list; + } Job; +@@ -90,4 +93,14 @@ Job *job_next(Job *job); + */ + Job *job_get(const char *id); + ++/** ++ * Check whether the verb @verb can be applied to @job in its current state. ++ * Returns 0 if the verb can be applied; otherwise errp is set and -EPERM ++ * returned. ++ */ ++int job_apply_verb(Job *job, JobVerb verb, Error **errp); ++ ++/* TODO To be removed from the public interface */ ++void job_state_transition(Job *job, JobStatus s1); ++ + #endif +diff --git a/job.c b/job.c +index e57303c..b049a32 100644 +--- a/job.c ++++ b/job.c +@@ -28,9 +28,63 @@ + #include "qapi/error.h" + #include "qemu/job.h" + #include "qemu/id.h" ++#include "trace-root.h" + + static QLIST_HEAD(, Job) jobs = QLIST_HEAD_INITIALIZER(jobs); + ++/* Job State Transition Table */ ++bool JobSTT[JOB_STATUS__MAX][JOB_STATUS__MAX] = { ++ /* U, C, R, P, Y, S, W, D, X, E, N */ ++ /* U: */ [JOB_STATUS_UNDEFINED] = {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ /* C: */ [JOB_STATUS_CREATED] = {0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1}, ++ /* R: */ [JOB_STATUS_RUNNING] = {0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0}, ++ /* P: */ [JOB_STATUS_PAUSED] = {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, ++ /* Y: */ [JOB_STATUS_READY] = {0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0}, ++ /* S: */ [JOB_STATUS_STANDBY] = {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, ++ /* W: */ [JOB_STATUS_WAITING] = {0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, ++ /* D: */ [JOB_STATUS_PENDING] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0}, ++ /* X: */ [JOB_STATUS_ABORTING] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0}, ++ /* E: */ [JOB_STATUS_CONCLUDED] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, ++ /* N: */ [JOB_STATUS_NULL] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++}; ++ ++bool JobVerbTable[JOB_VERB__MAX][JOB_STATUS__MAX] = { ++ /* U, C, R, P, Y, S, W, D, X, E, N */ ++ [JOB_VERB_CANCEL] = {0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0}, ++ [JOB_VERB_PAUSE] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}, ++ [JOB_VERB_RESUME] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}, ++ [JOB_VERB_SET_SPEED] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}, ++ [JOB_VERB_COMPLETE] = {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, ++ [JOB_VERB_FINALIZE] = {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, ++ [JOB_VERB_DISMISS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, ++}; ++ ++/* TODO Make static once the whole state machine is in job.c */ ++void job_state_transition(Job *job, JobStatus s1) ++{ ++ JobStatus s0 = job->status; ++ assert(s1 >= 0 && s1 <= JOB_STATUS__MAX); ++ trace_job_state_transition(job, /* TODO re-enable: job->ret */ 0, ++ JobSTT[s0][s1] ? "allowed" : "disallowed", ++ JobStatus_str(s0), JobStatus_str(s1)); ++ assert(JobSTT[s0][s1]); ++ job->status = s1; ++} ++ ++int job_apply_verb(Job *job, JobVerb verb, Error **errp) ++{ ++ JobStatus s0 = job->status; ++ assert(verb >= 0 && verb <= JOB_VERB__MAX); ++ trace_job_apply_verb(job, JobStatus_str(s0), JobVerb_str(verb), ++ JobVerbTable[verb][s0] ? "allowed" : "prohibited"); ++ if (JobVerbTable[verb][s0]) { ++ return 0; ++ } ++ error_setg(errp, "Job '%s' in state '%s' cannot accept command verb '%s'", ++ job->id, JobStatus_str(s0), JobVerb_str(verb)); ++ return -EPERM; ++} ++ + JobType job_type(const Job *job) + { + return job->driver->job_type; +@@ -81,6 +135,8 @@ void *job_create(const char *job_id, const JobDriver *driver, Error **errp) + job->driver = driver; + job->id = g_strdup(job_id); + ++ job_state_transition(job, JOB_STATUS_CREATED); ++ + QLIST_INSERT_HEAD(&jobs, job, job_list); + + return job; +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 607e5c5..85bf353 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -1068,9 +1068,9 @@ + 'data': ['commit', 'stream', 'mirror', 'backup'] } + + ## +-# @BlockJobVerb: ++# @JobVerb: + # +-# Represents command verbs that can be applied to a blockjob. ++# Represents command verbs that can be applied to a job. + # + # @cancel: see @block-job-cancel + # +@@ -1088,14 +1088,14 @@ + # + # Since: 2.12 + ## +-{ 'enum': 'BlockJobVerb', ++{ 'enum': 'JobVerb', + 'data': ['cancel', 'pause', 'resume', 'set-speed', 'complete', 'dismiss', + 'finalize' ] } + + ## +-# @BlockJobStatus: ++# @JobStatus: + # +-# Indicates the present state of a given blockjob in its lifetime. ++# Indicates the present state of a given job in its lifetime. + # + # @undefined: Erroneous, default state. Should not ever be visible. + # +@@ -1134,7 +1134,7 @@ + # + # Since: 2.12 + ## +-{ 'enum': 'BlockJobStatus', ++{ 'enum': 'JobStatus', + 'data': ['undefined', 'created', 'running', 'paused', 'ready', 'standby', + 'waiting', 'pending', 'aborting', 'concluded', 'null' ] } + +@@ -1184,7 +1184,7 @@ + 'data': {'type': 'str', 'device': 'str', 'len': 'int', + 'offset': 'int', 'busy': 'bool', 'paused': 'bool', 'speed': 'int', + 'io-status': 'BlockDeviceIoStatus', 'ready': 'bool', +- 'status': 'BlockJobStatus', ++ 'status': 'JobStatus', + 'auto-finalize': 'bool', 'auto-dismiss': 'bool', + '*error': 'str' } } + +@@ -2416,7 +2416,7 @@ + # QEMU 2.12+ job lifetime management semantics. + # + # This command will refuse to operate on any job that has not yet reached +-# its terminal state, BLOCK_JOB_STATUS_CONCLUDED. For jobs that make use of ++# its terminal state, JOB_STATUS_CONCLUDED. For jobs that make use of the + # BLOCK_JOB_READY event, block-job-cancel or block-job-complete will still need + # to be used as appropriate. + # +diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c +index b820261..6ccd585 100644 +--- a/tests/test-blockjob.c ++++ b/tests/test-blockjob.c +@@ -211,7 +211,7 @@ static CancelJob *create_common(BlockJob **pjob) + job = mk_job(blk, "Steve", &test_cancel_driver, true, + BLOCK_JOB_MANUAL_FINALIZE | BLOCK_JOB_MANUAL_DISMISS); + block_job_ref(job); +- assert(job->status == BLOCK_JOB_STATUS_CREATED); ++ assert(job->job.status == JOB_STATUS_CREATED); + s = container_of(job, CancelJob, common); + s->blk = blk; + +@@ -223,15 +223,14 @@ static void cancel_common(CancelJob *s) + { + BlockJob *job = &s->common; + BlockBackend *blk = s->blk; +- BlockJobStatus sts = job->status; ++ JobStatus sts = job->job.status; + + block_job_cancel_sync(job); +- if ((sts != BLOCK_JOB_STATUS_CREATED) && +- (sts != BLOCK_JOB_STATUS_CONCLUDED)) { ++ if (sts != JOB_STATUS_CREATED && sts != JOB_STATUS_CONCLUDED) { + BlockJob *dummy = job; + block_job_dismiss(&dummy, &error_abort); + } +- assert(job->status == BLOCK_JOB_STATUS_NULL); ++ assert(job->job.status == JOB_STATUS_NULL); + block_job_unref(job); + destroy_blk(blk); + } +@@ -253,7 +252,7 @@ static void test_cancel_running(void) + s = create_common(&job); + + block_job_start(job); +- assert(job->status == BLOCK_JOB_STATUS_RUNNING); ++ assert(job->job.status == JOB_STATUS_RUNNING); + + cancel_common(s); + } +@@ -266,11 +265,11 @@ static void test_cancel_paused(void) + s = create_common(&job); + + block_job_start(job); +- assert(job->status == BLOCK_JOB_STATUS_RUNNING); ++ assert(job->job.status == JOB_STATUS_RUNNING); + + block_job_user_pause(job, &error_abort); + block_job_enter(job); +- assert(job->status == BLOCK_JOB_STATUS_PAUSED); ++ assert(job->job.status == JOB_STATUS_PAUSED); + + cancel_common(s); + } +@@ -283,11 +282,11 @@ static void test_cancel_ready(void) + s = create_common(&job); + + block_job_start(job); +- assert(job->status == BLOCK_JOB_STATUS_RUNNING); ++ assert(job->job.status == JOB_STATUS_RUNNING); + + s->should_converge = true; + block_job_enter(job); +- assert(job->status == BLOCK_JOB_STATUS_READY); ++ assert(job->job.status == JOB_STATUS_READY); + + cancel_common(s); + } +@@ -300,15 +299,15 @@ static void test_cancel_standby(void) + s = create_common(&job); + + block_job_start(job); +- assert(job->status == BLOCK_JOB_STATUS_RUNNING); ++ assert(job->job.status == JOB_STATUS_RUNNING); + + s->should_converge = true; + block_job_enter(job); +- assert(job->status == BLOCK_JOB_STATUS_READY); ++ assert(job->job.status == JOB_STATUS_READY); + + block_job_user_pause(job, &error_abort); + block_job_enter(job); +- assert(job->status == BLOCK_JOB_STATUS_STANDBY); ++ assert(job->job.status == JOB_STATUS_STANDBY); + + cancel_common(s); + } +@@ -321,18 +320,18 @@ static void test_cancel_pending(void) + s = create_common(&job); + + block_job_start(job); +- assert(job->status == BLOCK_JOB_STATUS_RUNNING); ++ assert(job->job.status == JOB_STATUS_RUNNING); + + s->should_converge = true; + block_job_enter(job); +- assert(job->status == BLOCK_JOB_STATUS_READY); ++ assert(job->job.status == JOB_STATUS_READY); + + block_job_complete(job, &error_abort); + block_job_enter(job); + while (!s->completed) { + aio_poll(qemu_get_aio_context(), true); + } +- assert(job->status == BLOCK_JOB_STATUS_PENDING); ++ assert(job->job.status == JOB_STATUS_PENDING); + + cancel_common(s); + } +@@ -345,21 +344,21 @@ static void test_cancel_concluded(void) + s = create_common(&job); + + block_job_start(job); +- assert(job->status == BLOCK_JOB_STATUS_RUNNING); ++ assert(job->job.status == JOB_STATUS_RUNNING); + + s->should_converge = true; + block_job_enter(job); +- assert(job->status == BLOCK_JOB_STATUS_READY); ++ assert(job->job.status == JOB_STATUS_READY); + + block_job_complete(job, &error_abort); + block_job_enter(job); + while (!s->completed) { + aio_poll(qemu_get_aio_context(), true); + } +- assert(job->status == BLOCK_JOB_STATUS_PENDING); ++ assert(job->job.status == JOB_STATUS_PENDING); + + block_job_finalize(job, &error_abort); +- assert(job->status == BLOCK_JOB_STATUS_CONCLUDED); ++ assert(job->job.status == JOB_STATUS_CONCLUDED); + + cancel_common(s); + } +diff --git a/trace-events b/trace-events +index ed71f44..2507e13 100644 +--- a/trace-events ++++ b/trace-events +@@ -104,6 +104,10 @@ gdbstub_err_invalid_rle(void) "got invalid RLE sequence" + gdbstub_err_checksum_invalid(uint8_t ch) "got invalid command checksum digit: 0x%02x" + gdbstub_err_checksum_incorrect(uint8_t expected, uint8_t got) "got command packet with incorrect checksum, expected=0x%02x, received=0x%02x" + ++# job.c ++job_state_transition(void *job, int ret, const char *legal, const char *s0, const char *s1) "job %p (ret: %d) attempting %s transition (%s-->%s)" ++job_apply_verb(void *job, const char *state, const char *verb, const char *legal) "job %p in state %s; applying verb %s (%s)" ++ + ### Guest events, keep at bottom + + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Move-transactions-to-Job.patch b/SOURCES/kvm-job-Move-transactions-to-Job.patch new file mode 100644 index 0000000..0745c01 --- /dev/null +++ b/SOURCES/kvm-job-Move-transactions-to-Job.patch @@ -0,0 +1,995 @@ +From 870c205da77467ee664de7f74ba9c47b6b8e528b Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:22 +0200 +Subject: [PATCH 53/89] job: Move transactions to Job + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-40-kwolf@redhat.com> +Patchwork-id: 81097 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 39/73] job: Move transactions to Job +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This moves the logic that implements job transactions from BlockJob to +Job. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +(cherry picked from commit 7eaa8fb57da96301f4a8ce176ad503f80efc7cc0) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + blockdev.c | 6 +- + blockjob.c | 238 +------------------------------------------ + include/block/blockjob.h | 54 ---------- + include/block/blockjob_int.h | 10 -- + include/qemu/job.h | 71 +++++++++++-- + job.c | 234 ++++++++++++++++++++++++++++++++++++++++-- + tests/test-blockjob-txn.c | 12 +-- + tests/test-blockjob.c | 2 +- + 8 files changed, 303 insertions(+), 324 deletions(-) + +diff --git a/blockdev.c b/blockdev.c +index b6f3e92..422b5ac 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -2297,7 +2297,7 @@ void qmp_transaction(TransactionActionList *dev_list, + */ + props = get_transaction_properties(props); + if (props->completion_mode != ACTION_COMPLETION_MODE_INDIVIDUAL) { +- block_job_txn = block_job_txn_new(); ++ block_job_txn = job_txn_new(); + } + + /* drain all i/o before any operations */ +@@ -2356,7 +2356,7 @@ exit: + if (!has_props) { + qapi_free_TransactionProperties(props); + } +- block_job_txn_unref(block_job_txn); ++ job_txn_unref(block_job_txn); + } + + void qmp_eject(bool has_device, const char *device, +@@ -3955,7 +3955,7 @@ void qmp_block_job_finalize(const char *id, Error **errp) + } + + trace_qmp_block_job_finalize(job); +- block_job_finalize(job, errp); ++ job_finalize(&job->job, errp); + aio_context_release(aio_context); + } + +diff --git a/blockjob.c b/blockjob.c +index bd35c4f..14b21c8 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -36,19 +36,6 @@ + #include "qemu/coroutine.h" + #include "qemu/timer.h" + +-/* Transactional group of block jobs */ +-struct JobTxn { +- +- /* Is this txn being cancelled? */ +- bool aborting; +- +- /* List of jobs */ +- QLIST_HEAD(, Job) jobs; +- +- /* Reference count */ +- int refcnt; +-}; +- + /* + * The block job API is composed of two categories of functions. + * +@@ -94,48 +81,6 @@ BlockJob *block_job_get(const char *id) + } + } + +-JobTxn *block_job_txn_new(void) +-{ +- JobTxn *txn = g_new0(JobTxn, 1); +- QLIST_INIT(&txn->jobs); +- txn->refcnt = 1; +- return txn; +-} +- +-static void block_job_txn_ref(JobTxn *txn) +-{ +- txn->refcnt++; +-} +- +-void block_job_txn_unref(JobTxn *txn) +-{ +- if (txn && --txn->refcnt == 0) { +- g_free(txn); +- } +-} +- +-void block_job_txn_add_job(JobTxn *txn, BlockJob *job) +-{ +- if (!txn) { +- return; +- } +- +- assert(!job->txn); +- job->txn = txn; +- +- QLIST_INSERT_HEAD(&txn->jobs, &job->job, txn_list); +- block_job_txn_ref(txn); +-} +- +-void block_job_txn_del_job(BlockJob *job) +-{ +- if (job->txn) { +- QLIST_REMOVE(&job->job, txn_list); +- block_job_txn_unref(job->txn); +- job->txn = NULL; +- } +-} +- + static void block_job_attached_aio_context(AioContext *new_context, + void *opaque); + static void block_job_detach_aio_context(void *opaque); +@@ -145,8 +90,6 @@ void block_job_free(Job *job) + BlockJob *bjob = container_of(job, BlockJob, job); + BlockDriverState *bs = blk_bs(bjob->blk); + +- assert(!bjob->txn); +- + bs->job = NULL; + block_job_remove_all_bdrv(bjob); + blk_remove_aio_context_notifier(bjob->blk, +@@ -261,158 +204,6 @@ const BlockJobDriver *block_job_driver(BlockJob *job) + return job->driver; + } + +-static int block_job_prepare(BlockJob *job) +-{ +- if (job->job.ret == 0 && job->driver->prepare) { +- job->job.ret = job->driver->prepare(job); +- } +- return job->job.ret; +-} +- +-static void job_cancel_async(Job *job, bool force) +-{ +- if (job->user_paused) { +- /* Do not call job_enter here, the caller will handle it. */ +- job->user_paused = false; +- if (job->driver->user_resume) { +- job->driver->user_resume(job); +- } +- assert(job->pause_count > 0); +- job->pause_count--; +- } +- job->cancelled = true; +- /* To prevent 'force == false' overriding a previous 'force == true' */ +- job->force_cancel |= force; +-} +- +-static int block_job_txn_apply(JobTxn *txn, int fn(BlockJob *), bool lock) +-{ +- AioContext *ctx; +- Job *job, *next; +- BlockJob *bjob; +- int rc = 0; +- +- QLIST_FOREACH_SAFE(job, &txn->jobs, txn_list, next) { +- assert(is_block_job(job)); +- bjob = container_of(job, BlockJob, job); +- +- if (lock) { +- ctx = job->aio_context; +- aio_context_acquire(ctx); +- } +- rc = fn(bjob); +- if (lock) { +- aio_context_release(ctx); +- } +- if (rc) { +- break; +- } +- } +- return rc; +-} +- +-static void block_job_completed_txn_abort(BlockJob *job) +-{ +- AioContext *ctx; +- JobTxn *txn = job->txn; +- Job *other_job; +- +- if (txn->aborting) { +- /* +- * We are cancelled by another job, which will handle everything. +- */ +- return; +- } +- txn->aborting = true; +- block_job_txn_ref(txn); +- +- /* We are the first failed job. Cancel other jobs. */ +- QLIST_FOREACH(other_job, &txn->jobs, txn_list) { +- ctx = other_job->aio_context; +- aio_context_acquire(ctx); +- } +- +- /* Other jobs are effectively cancelled by us, set the status for +- * them; this job, however, may or may not be cancelled, depending +- * on the caller, so leave it. */ +- QLIST_FOREACH(other_job, &txn->jobs, txn_list) { +- if (other_job != &job->job) { +- job_cancel_async(other_job, false); +- } +- } +- while (!QLIST_EMPTY(&txn->jobs)) { +- other_job = QLIST_FIRST(&txn->jobs); +- ctx = other_job->aio_context; +- if (!job_is_completed(other_job)) { +- assert(job_is_cancelled(other_job)); +- job_finish_sync(other_job, NULL, NULL); +- } +- job_finalize_single(other_job); +- aio_context_release(ctx); +- } +- +- block_job_txn_unref(txn); +-} +- +-static int block_job_needs_finalize(BlockJob *job) +-{ +- return !job->job.auto_finalize; +-} +- +-static int block_job_finalize_single(BlockJob *job) +-{ +- return job_finalize_single(&job->job); +-} +- +-static void block_job_do_finalize(BlockJob *job) +-{ +- int rc; +- assert(job && job->txn); +- +- /* prepare the transaction to complete */ +- rc = block_job_txn_apply(job->txn, block_job_prepare, true); +- if (rc) { +- block_job_completed_txn_abort(job); +- } else { +- block_job_txn_apply(job->txn, block_job_finalize_single, true); +- } +-} +- +-static int block_job_transition_to_pending(BlockJob *job) +-{ +- job_state_transition(&job->job, JOB_STATUS_PENDING); +- if (!job->job.auto_finalize) { +- job_event_pending(&job->job); +- } +- return 0; +-} +- +-static void block_job_completed_txn_success(BlockJob *job) +-{ +- JobTxn *txn = job->txn; +- Job *other_job; +- +- job_state_transition(&job->job, JOB_STATUS_WAITING); +- +- /* +- * Successful completion, see if there are other running jobs in this +- * txn. +- */ +- QLIST_FOREACH(other_job, &txn->jobs, txn_list) { +- if (!job_is_completed(other_job)) { +- return; +- } +- assert(other_job->ret == 0); +- } +- +- block_job_txn_apply(txn, block_job_transition_to_pending, false); +- +- /* If no jobs need manual finalization, automatically do so */ +- if (block_job_txn_apply(txn, block_job_needs_finalize, false) == 0) { +- block_job_do_finalize(job); +- } +-} +- + /* Assumes the job_mutex is held */ + static bool job_timer_pending(Job *job) + { +@@ -451,15 +242,6 @@ int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n) + return ratelimit_calculate_delay(&job->limit, n); + } + +-void block_job_finalize(BlockJob *job, Error **errp) +-{ +- assert(job && job->job.id); +- if (job_apply_verb(&job->job, JOB_VERB_FINALIZE, errp)) { +- return; +- } +- block_job_do_finalize(job); +-} +- + void block_job_dismiss(BlockJob **jobptr, Error **errp) + { + BlockJob *job = *jobptr; +@@ -483,7 +265,7 @@ void block_job_cancel(BlockJob *job, bool force) + if (!job_started(&job->job)) { + block_job_completed(job, -ECANCELED); + } else if (job->job.deferred_to_main_loop) { +- block_job_completed_txn_abort(job); ++ job_completed_txn_abort(&job->job); + } else { + block_job_enter(job); + } +@@ -656,7 +438,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + return NULL; + } + +- job = job_create(job_id, &driver->job_driver, blk_get_aio_context(blk), ++ job = job_create(job_id, &driver->job_driver, txn, blk_get_aio_context(blk), + flags, cb, opaque, errp); + if (job == NULL) { + blk_unref(blk); +@@ -703,30 +485,20 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + } + } + +- /* Single jobs are modeled as single-job transactions for sake of +- * consolidating the job management logic */ +- if (!txn) { +- txn = block_job_txn_new(); +- block_job_txn_add_job(txn, job); +- block_job_txn_unref(txn); +- } else { +- block_job_txn_add_job(txn, job); +- } +- + return job; + } + + void block_job_completed(BlockJob *job, int ret) + { +- assert(job && job->txn && !job_is_completed(&job->job)); ++ assert(job && job->job.txn && !job_is_completed(&job->job)); + assert(blk_bs(job->blk)->job == job); + job->job.ret = ret; + job_update_rc(&job->job); + trace_block_job_completed(job, ret, job->job.ret); + if (job->job.ret) { +- block_job_completed_txn_abort(job); ++ job_completed_txn_abort(&job->job); + } else { +- block_job_completed_txn_success(job); ++ job_completed_txn_success(&job->job); + } + } + +diff --git a/include/block/blockjob.h b/include/block/blockjob.h +index 44df025..09e6bb4 100644 +--- a/include/block/blockjob.h ++++ b/include/block/blockjob.h +@@ -33,7 +33,6 @@ + #define BLOCK_JOB_SLICE_TIME 100000000ULL /* ns */ + + typedef struct BlockJobDriver BlockJobDriver; +-typedef struct JobTxn JobTxn; + + /** + * BlockJob: +@@ -84,8 +83,6 @@ typedef struct BlockJob { + + /** BlockDriverStates that are involved in this block job */ + GSList *nodes; +- +- JobTxn *txn; + } BlockJob; + + /** +@@ -153,22 +150,6 @@ void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp); + void block_job_cancel(BlockJob *job, bool force); + + /** +- * block_job_finalize: +- * @job: The job to fully commit and finish. +- * @errp: Error object. +- * +- * For jobs that have finished their work and are pending +- * awaiting explicit acknowledgement to commit their work, +- * This will commit that work. +- * +- * FIXME: Make the below statement universally true: +- * For jobs that support the manual workflow mode, all graph +- * changes that occur as a result will occur after this command +- * and before a successful reply. +- */ +-void block_job_finalize(BlockJob *job, Error **errp); +- +-/** + * block_job_dismiss: + * @job: The job to be dismissed. + * @errp: Error object. +@@ -260,41 +241,6 @@ int block_job_complete_sync(BlockJob *job, Error **errp); + void block_job_iostatus_reset(BlockJob *job); + + /** +- * block_job_txn_new: +- * +- * Allocate and return a new block job transaction. Jobs can be added to the +- * transaction using block_job_txn_add_job(). +- * +- * The transaction is automatically freed when the last job completes or is +- * cancelled. +- * +- * All jobs in the transaction either complete successfully or fail/cancel as a +- * group. Jobs wait for each other before completing. Cancelling one job +- * cancels all jobs in the transaction. +- */ +-JobTxn *block_job_txn_new(void); +- +-/** +- * block_job_txn_unref: +- * +- * Release a reference that was previously acquired with block_job_txn_add_job +- * or block_job_txn_new. If it's the last reference to the object, it will be +- * freed. +- */ +-void block_job_txn_unref(JobTxn *txn); +- +-/** +- * block_job_txn_add_job: +- * @txn: The transaction (may be NULL) +- * @job: Job to add to the transaction +- * +- * Add @job to the transaction. The @job must not already be in a transaction. +- * The caller must call either block_job_txn_unref() or block_job_completed() +- * to release the reference that is automatically grabbed here. +- */ +-void block_job_txn_add_job(JobTxn *txn, BlockJob *job); +- +-/** + * block_job_is_internal: + * @job: The job to determine if it is user-visible or not. + * +diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h +index ce66a9b..29a2802 100644 +--- a/include/block/blockjob_int.h ++++ b/include/block/blockjob_int.h +@@ -38,16 +38,6 @@ struct BlockJobDriver { + /** Generic JobDriver callbacks and settings */ + JobDriver job_driver; + +- /** +- * If the callback is not NULL, prepare will be invoked when all the jobs +- * belonging to the same transaction complete; or upon this job's completion +- * if it is not in a transaction. +- * +- * This callback will not be invoked if the job has already failed. +- * If it fails, abort and then clean will be called. +- */ +- int (*prepare)(BlockJob *job); +- + /* + * If the callback is not NULL, it will be invoked before the job is + * resumed in a new AioContext. This is the place to move any resources +diff --git a/include/qemu/job.h b/include/qemu/job.h +index d4aa7fa..39d74ab 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -32,6 +32,8 @@ + #include "block/aio.h" + + typedef struct JobDriver JobDriver; ++typedef struct JobTxn JobTxn; ++ + + /** + * Long-running operation. +@@ -133,6 +135,9 @@ typedef struct Job { + /** Element of the list of jobs */ + QLIST_ENTRY(Job) job_list; + ++ /** Transaction this job is part of */ ++ JobTxn *txn; ++ + /** Element of the list of jobs in a job transaction */ + QLIST_ENTRY(Job) txn_list; + } Job; +@@ -184,6 +189,16 @@ struct JobDriver { + void (*drain)(Job *job); + + /** ++ * If the callback is not NULL, prepare will be invoked when all the jobs ++ * belonging to the same transaction complete; or upon this job's completion ++ * if it is not in a transaction. ++ * ++ * This callback will not be invoked if the job has already failed. ++ * If it fails, abort and then clean will be called. ++ */ ++ int (*prepare)(Job *job); ++ ++ /** + * If the callback is not NULL, it will be invoked when all the jobs + * belonging to the same transaction complete; or upon this job's + * completion if it is not in a transaction. Skipped if NULL. +@@ -227,20 +242,52 @@ typedef enum JobCreateFlags { + JOB_MANUAL_DISMISS = 0x04, + } JobCreateFlags; + ++/** ++ * Allocate and return a new job transaction. Jobs can be added to the ++ * transaction using job_txn_add_job(). ++ * ++ * The transaction is automatically freed when the last job completes or is ++ * cancelled. ++ * ++ * All jobs in the transaction either complete successfully or fail/cancel as a ++ * group. Jobs wait for each other before completing. Cancelling one job ++ * cancels all jobs in the transaction. ++ */ ++JobTxn *job_txn_new(void); ++ ++/** ++ * Release a reference that was previously acquired with job_txn_add_job or ++ * job_txn_new. If it's the last reference to the object, it will be freed. ++ */ ++void job_txn_unref(JobTxn *txn); ++ ++/** ++ * @txn: The transaction (may be NULL) ++ * @job: Job to add to the transaction ++ * ++ * Add @job to the transaction. The @job must not already be in a transaction. ++ * The caller must call either job_txn_unref() or block_job_completed() to ++ * release the reference that is automatically grabbed here. ++ * ++ * If @txn is NULL, the function does nothing. ++ */ ++void job_txn_add_job(JobTxn *txn, Job *job); + + /** + * Create a new long-running job and return it. + * + * @job_id: The id of the newly-created job, or %NULL for internal jobs + * @driver: The class object for the newly-created job. ++ * @txn: The transaction this job belongs to, if any. %NULL otherwise. + * @ctx: The AioContext to run the job coroutine in. + * @flags: Creation flags for the job. See @JobCreateFlags. + * @cb: Completion function for the job. + * @opaque: Opaque pointer value passed to @cb. + * @errp: Error object. + */ +-void *job_create(const char *job_id, const JobDriver *driver, AioContext *ctx, +- int flags, BlockCompletionFunc *cb, void *opaque, Error **errp); ++void *job_create(const char *job_id, const JobDriver *driver, JobTxn *txn, ++ AioContext *ctx, int flags, BlockCompletionFunc *cb, ++ void *opaque, Error **errp); + + /** + * Add a reference to Job refcnt, it will be decreased with job_unref, and then +@@ -260,9 +307,6 @@ void job_event_cancelled(Job *job); + /** To be called when a successfully completed job is finalised. */ + void job_event_completed(Job *job); + +-/** To be called when the job transitions to PENDING */ +-void job_event_pending(Job *job); +- + /** + * Conditionally enter the job coroutine if the job is ready to run, not + * already busy and fn() returns true. fn() is called while under the job_lock +@@ -375,6 +419,16 @@ void job_early_fail(Job *job); + /** Asynchronously complete the specified @job. */ + void job_complete(Job *job, Error **errp);; + ++/** ++ * For a @job that has finished its work and is pending awaiting explicit ++ * acknowledgement to commit its work, this will commit that work. ++ * ++ * FIXME: Make the below statement universally true: ++ * For jobs that support the manual workflow mode, all graph changes that occur ++ * as a result will occur after this command and before a successful reply. ++ */ ++void job_finalize(Job *job, Error **errp); ++ + typedef void JobDeferToMainLoopFn(Job *job, void *opaque); + + /** +@@ -407,10 +461,9 @@ void coroutine_fn job_do_yield(Job *job, uint64_t ns); + bool job_should_pause(Job *job); + bool job_started(Job *job); + void job_do_dismiss(Job *job); +-int job_finalize_single(Job *job); + void job_update_rc(Job *job); +- +-typedef struct BlockJob BlockJob; +-void block_job_txn_del_job(BlockJob *job); ++void job_cancel_async(Job *job, bool force); ++void job_completed_txn_abort(Job *job); ++void job_completed_txn_success(Job *job); + + #endif +diff --git a/job.c b/job.c +index aa74b4c..4f6fd73 100644 +--- a/job.c ++++ b/job.c +@@ -60,6 +60,19 @@ bool JobVerbTable[JOB_VERB__MAX][JOB_STATUS__MAX] = { + [JOB_VERB_DISMISS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, + }; + ++/* Transactional group of jobs */ ++struct JobTxn { ++ ++ /* Is this txn being cancelled? */ ++ bool aborting; ++ ++ /* List of jobs */ ++ QLIST_HEAD(, Job) jobs; ++ ++ /* Reference count */ ++ int refcnt; ++}; ++ + /* Right now, this mutex is only needed to synchronize accesses to job->busy + * and job->sleep_timer, such as concurrent calls to job_do_yield and + * job_enter. */ +@@ -80,6 +93,71 @@ static void __attribute__((__constructor__)) job_init(void) + qemu_mutex_init(&job_mutex); + } + ++JobTxn *job_txn_new(void) ++{ ++ JobTxn *txn = g_new0(JobTxn, 1); ++ QLIST_INIT(&txn->jobs); ++ txn->refcnt = 1; ++ return txn; ++} ++ ++static void job_txn_ref(JobTxn *txn) ++{ ++ txn->refcnt++; ++} ++ ++void job_txn_unref(JobTxn *txn) ++{ ++ if (txn && --txn->refcnt == 0) { ++ g_free(txn); ++ } ++} ++ ++void job_txn_add_job(JobTxn *txn, Job *job) ++{ ++ if (!txn) { ++ return; ++ } ++ ++ assert(!job->txn); ++ job->txn = txn; ++ ++ QLIST_INSERT_HEAD(&txn->jobs, job, txn_list); ++ job_txn_ref(txn); ++} ++ ++static void job_txn_del_job(Job *job) ++{ ++ if (job->txn) { ++ QLIST_REMOVE(job, txn_list); ++ job_txn_unref(job->txn); ++ job->txn = NULL; ++ } ++} ++ ++static int job_txn_apply(JobTxn *txn, int fn(Job *), bool lock) ++{ ++ AioContext *ctx; ++ Job *job, *next; ++ int rc = 0; ++ ++ QLIST_FOREACH_SAFE(job, &txn->jobs, txn_list, next) { ++ if (lock) { ++ ctx = job->aio_context; ++ aio_context_acquire(ctx); ++ } ++ rc = fn(job); ++ if (lock) { ++ aio_context_release(ctx); ++ } ++ if (rc) { ++ break; ++ } ++ } ++ return rc; ++} ++ ++ + /* TODO Make static once the whole state machine is in job.c */ + void job_state_transition(Job *job, JobStatus s1) + { +@@ -181,8 +259,9 @@ static void job_sleep_timer_cb(void *opaque) + job_enter(job); + } + +-void *job_create(const char *job_id, const JobDriver *driver, AioContext *ctx, +- int flags, BlockCompletionFunc *cb, void *opaque, Error **errp) ++void *job_create(const char *job_id, const JobDriver *driver, JobTxn *txn, ++ AioContext *ctx, int flags, BlockCompletionFunc *cb, ++ void *opaque, Error **errp) + { + Job *job; + +@@ -228,6 +307,16 @@ void *job_create(const char *job_id, const JobDriver *driver, AioContext *ctx, + + QLIST_INSERT_HEAD(&jobs, job, job_list); + ++ /* Single jobs are modeled as single-job transactions for sake of ++ * consolidating the job management logic */ ++ if (!txn) { ++ txn = job_txn_new(); ++ job_txn_add_job(txn, job); ++ job_txn_unref(txn); ++ } else { ++ job_txn_add_job(txn, job); ++ } ++ + return job; + } + +@@ -241,6 +330,7 @@ void job_unref(Job *job) + if (--job->refcnt == 0) { + assert(job->status == JOB_STATUS_NULL); + assert(!timer_pending(&job->sleep_timer)); ++ assert(!job->txn); + + if (job->driver->free) { + job->driver->free(job); +@@ -263,7 +353,7 @@ void job_event_completed(Job *job) + notifier_list_notify(&job->on_finalize_completed, job); + } + +-void job_event_pending(Job *job) ++static void job_event_pending(Job *job) + { + notifier_list_notify(&job->on_pending, job); + } +@@ -469,8 +559,7 @@ void job_do_dismiss(Job *job) + job->paused = false; + job->deferred_to_main_loop = true; + +- /* TODO Don't assume it's a BlockJob */ +- block_job_txn_del_job((BlockJob*) job); ++ job_txn_del_job(job); + + job_state_transition(job, JOB_STATUS_NULL); + job_unref(job); +@@ -523,7 +612,7 @@ static void job_clean(Job *job) + } + } + +-int job_finalize_single(Job *job) ++static int job_finalize_single(Job *job) + { + assert(job_is_completed(job)); + +@@ -550,12 +639,141 @@ int job_finalize_single(Job *job) + } + } + +- /* TODO Don't assume it's a BlockJob */ +- block_job_txn_del_job((BlockJob*) job); ++ job_txn_del_job(job); + job_conclude(job); + return 0; + } + ++void job_cancel_async(Job *job, bool force) ++{ ++ if (job->user_paused) { ++ /* Do not call job_enter here, the caller will handle it. */ ++ job->user_paused = false; ++ if (job->driver->user_resume) { ++ job->driver->user_resume(job); ++ } ++ assert(job->pause_count > 0); ++ job->pause_count--; ++ } ++ job->cancelled = true; ++ /* To prevent 'force == false' overriding a previous 'force == true' */ ++ job->force_cancel |= force; ++} ++ ++void job_completed_txn_abort(Job *job) ++{ ++ AioContext *ctx; ++ JobTxn *txn = job->txn; ++ Job *other_job; ++ ++ if (txn->aborting) { ++ /* ++ * We are cancelled by another job, which will handle everything. ++ */ ++ return; ++ } ++ txn->aborting = true; ++ job_txn_ref(txn); ++ ++ /* We are the first failed job. Cancel other jobs. */ ++ QLIST_FOREACH(other_job, &txn->jobs, txn_list) { ++ ctx = other_job->aio_context; ++ aio_context_acquire(ctx); ++ } ++ ++ /* Other jobs are effectively cancelled by us, set the status for ++ * them; this job, however, may or may not be cancelled, depending ++ * on the caller, so leave it. */ ++ QLIST_FOREACH(other_job, &txn->jobs, txn_list) { ++ if (other_job != job) { ++ job_cancel_async(other_job, false); ++ } ++ } ++ while (!QLIST_EMPTY(&txn->jobs)) { ++ other_job = QLIST_FIRST(&txn->jobs); ++ ctx = other_job->aio_context; ++ if (!job_is_completed(other_job)) { ++ assert(job_is_cancelled(other_job)); ++ job_finish_sync(other_job, NULL, NULL); ++ } ++ job_finalize_single(other_job); ++ aio_context_release(ctx); ++ } ++ ++ job_txn_unref(txn); ++} ++ ++static int job_prepare(Job *job) ++{ ++ if (job->ret == 0 && job->driver->prepare) { ++ job->ret = job->driver->prepare(job); ++ } ++ return job->ret; ++} ++ ++static int job_needs_finalize(Job *job) ++{ ++ return !job->auto_finalize; ++} ++ ++static void job_do_finalize(Job *job) ++{ ++ int rc; ++ assert(job && job->txn); ++ ++ /* prepare the transaction to complete */ ++ rc = job_txn_apply(job->txn, job_prepare, true); ++ if (rc) { ++ job_completed_txn_abort(job); ++ } else { ++ job_txn_apply(job->txn, job_finalize_single, true); ++ } ++} ++ ++void job_finalize(Job *job, Error **errp) ++{ ++ assert(job && job->id); ++ if (job_apply_verb(job, JOB_VERB_FINALIZE, errp)) { ++ return; ++ } ++ job_do_finalize(job); ++} ++ ++static int job_transition_to_pending(Job *job) ++{ ++ job_state_transition(job, JOB_STATUS_PENDING); ++ if (!job->auto_finalize) { ++ job_event_pending(job); ++ } ++ return 0; ++} ++ ++void job_completed_txn_success(Job *job) ++{ ++ JobTxn *txn = job->txn; ++ Job *other_job; ++ ++ job_state_transition(job, JOB_STATUS_WAITING); ++ ++ /* ++ * Successful completion, see if there are other running jobs in this ++ * txn. ++ */ ++ QLIST_FOREACH(other_job, &txn->jobs, txn_list) { ++ if (!job_is_completed(other_job)) { ++ return; ++ } ++ assert(other_job->ret == 0); ++ } ++ ++ job_txn_apply(txn, job_transition_to_pending, false); ++ ++ /* If no jobs need manual finalization, automatically do so */ ++ if (job_txn_apply(txn, job_needs_finalize, false) == 0) { ++ job_do_finalize(job); ++ } ++} ++ + void job_complete(Job *job, Error **errp) + { + /* Should not be reachable via external interface for internal jobs */ +diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c +index ec5d592..6ee31d5 100644 +--- a/tests/test-blockjob-txn.c ++++ b/tests/test-blockjob-txn.c +@@ -125,7 +125,7 @@ static void test_single_job(int expected) + JobTxn *txn; + int result = -EINPROGRESS; + +- txn = block_job_txn_new(); ++ txn = job_txn_new(); + job = test_block_job_start(1, true, expected, &result, txn); + job_start(&job->job); + +@@ -138,7 +138,7 @@ static void test_single_job(int expected) + } + g_assert_cmpint(result, ==, expected); + +- block_job_txn_unref(txn); ++ job_txn_unref(txn); + } + + static void test_single_job_success(void) +@@ -164,7 +164,7 @@ static void test_pair_jobs(int expected1, int expected2) + int result1 = -EINPROGRESS; + int result2 = -EINPROGRESS; + +- txn = block_job_txn_new(); ++ txn = job_txn_new(); + job1 = test_block_job_start(1, true, expected1, &result1, txn); + job2 = test_block_job_start(2, true, expected2, &result2, txn); + job_start(&job1->job); +@@ -173,7 +173,7 @@ static void test_pair_jobs(int expected1, int expected2) + /* Release our reference now to trigger as many nice + * use-after-free bugs as possible. + */ +- block_job_txn_unref(txn); ++ job_txn_unref(txn); + + if (expected1 == -ECANCELED) { + block_job_cancel(job1, false); +@@ -226,7 +226,7 @@ static void test_pair_jobs_fail_cancel_race(void) + int result1 = -EINPROGRESS; + int result2 = -EINPROGRESS; + +- txn = block_job_txn_new(); ++ txn = job_txn_new(); + job1 = test_block_job_start(1, true, -ECANCELED, &result1, txn); + job2 = test_block_job_start(2, false, 0, &result2, txn); + job_start(&job1->job); +@@ -247,7 +247,7 @@ static void test_pair_jobs_fail_cancel_race(void) + g_assert_cmpint(result1, ==, -ECANCELED); + g_assert_cmpint(result2, ==, -ECANCELED); + +- block_job_txn_unref(txn); ++ job_txn_unref(txn); + } + + int main(int argc, char **argv) +diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c +index e44c608..1e052c2 100644 +--- a/tests/test-blockjob.c ++++ b/tests/test-blockjob.c +@@ -364,7 +364,7 @@ static void test_cancel_concluded(void) + } + assert(job->job.status == JOB_STATUS_PENDING); + +- block_job_finalize(job, &error_abort); ++ job_finalize(&job->job, &error_abort); + assert(job->job.status == JOB_STATUS_CONCLUDED); + + cancel_common(s); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Rename-BlockJobType-into-JobType.patch b/SOURCES/kvm-job-Rename-BlockJobType-into-JobType.patch new file mode 100644 index 0000000..5085146 --- /dev/null +++ b/SOURCES/kvm-job-Rename-BlockJobType-into-JobType.patch @@ -0,0 +1,204 @@ +From 5ca59831fc7c51ec7f0c002bced4a41d088a0fb2 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:00 +0200 +Subject: [PATCH 31/89] job: Rename BlockJobType into JobType + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-18-kwolf@redhat.com> +Patchwork-id: 81112 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 17/73] job: Rename BlockJobType into JobType +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +QAPI types aren't externally visible, so we can rename them without +causing problems. Before we add a job type to Job, rename the enum +so it can be used for more than just block jobs. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +Reviewed-by: Max Reitz +Reviewed-by: John Snow +(cherry picked from commit 8e4c87000fc515f8f65f7c8f18afb1e9270b11d6) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/backup.c | 2 +- + block/commit.c | 2 +- + block/mirror.c | 4 ++-- + block/stream.c | 2 +- + blockjob.c | 6 +++--- + include/block/blockjob_int.h | 2 +- + qapi/block-core.json | 14 +++++++------- + 7 files changed, 16 insertions(+), 16 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index 9e672bb..c49ea92 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -526,7 +526,7 @@ static const BlockJobDriver backup_job_driver = { + .job_driver = { + .instance_size = sizeof(BackupBlockJob), + }, +- .job_type = BLOCK_JOB_TYPE_BACKUP, ++ .job_type = JOB_TYPE_BACKUP, + .start = backup_run, + .commit = backup_commit, + .abort = backup_abort, +diff --git a/block/commit.c b/block/commit.c +index 18cbb2f..afa2b2b 100644 +--- a/block/commit.c ++++ b/block/commit.c +@@ -218,7 +218,7 @@ static const BlockJobDriver commit_job_driver = { + .job_driver = { + .instance_size = sizeof(CommitBlockJob), + }, +- .job_type = BLOCK_JOB_TYPE_COMMIT, ++ .job_type = JOB_TYPE_COMMIT, + .start = commit_run, + }; + +diff --git a/block/mirror.c b/block/mirror.c +index aa1d6b7..ed72656 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -989,7 +989,7 @@ static const BlockJobDriver mirror_job_driver = { + .job_driver = { + .instance_size = sizeof(MirrorBlockJob), + }, +- .job_type = BLOCK_JOB_TYPE_MIRROR, ++ .job_type = JOB_TYPE_MIRROR, + .start = mirror_run, + .complete = mirror_complete, + .pause = mirror_pause, +@@ -1001,7 +1001,7 @@ static const BlockJobDriver commit_active_job_driver = { + .job_driver = { + .instance_size = sizeof(MirrorBlockJob), + }, +- .job_type = BLOCK_JOB_TYPE_COMMIT, ++ .job_type = JOB_TYPE_COMMIT, + .start = mirror_run, + .complete = mirror_complete, + .pause = mirror_pause, +diff --git a/block/stream.c b/block/stream.c +index f88fc75..048bceb 100644 +--- a/block/stream.c ++++ b/block/stream.c +@@ -212,7 +212,7 @@ static const BlockJobDriver stream_job_driver = { + .job_driver = { + .instance_size = sizeof(StreamBlockJob), + }, +- .job_type = BLOCK_JOB_TYPE_STREAM, ++ .job_type = JOB_TYPE_STREAM, + .start = stream_run, + }; + +diff --git a/blockjob.c b/blockjob.c +index 1464856..2a38447 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -310,7 +310,7 @@ static char *child_job_get_parent_desc(BdrvChild *c) + { + BlockJob *job = c->opaque; + return g_strdup_printf("%s job '%s'", +- BlockJobType_str(job->driver->job_type), ++ JobType_str(job->driver->job_type), + job->job.id); + } + +@@ -847,7 +847,7 @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp) + return NULL; + } + info = g_new0(BlockJobInfo, 1); +- info->type = g_strdup(BlockJobType_str(job->driver->job_type)); ++ info->type = g_strdup(JobType_str(job->driver->job_type)); + info->device = g_strdup(job->job.id); + info->len = job->len; + info->busy = atomic_read(&job->busy); +@@ -980,7 +980,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, + block_job_sleep_timer_cb, job); + + error_setg(&job->blocker, "block device is in use by block job: %s", +- BlockJobType_str(driver->job_type)); ++ JobType_str(driver->job_type)); + block_job_add_bdrv(job, "main node", bs, 0, BLK_PERM_ALL, &error_abort); + bs->job = job; + +diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h +index e8eca44..8e7e0a2 100644 +--- a/include/block/blockjob_int.h ++++ b/include/block/blockjob_int.h +@@ -39,7 +39,7 @@ struct BlockJobDriver { + JobDriver job_driver; + + /** String describing the operation, part of query-block-jobs QMP API */ +- BlockJobType job_type; ++ JobType job_type; + + /** Mandatory: Entrypoint for the Coroutine. */ + CoroutineEntry *start; +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 1f6d4bb..607e5c5 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -1050,9 +1050,9 @@ + 'data': ['top', 'full', 'none', 'incremental'] } + + ## +-# @BlockJobType: ++# @JobType: + # +-# Type of a block job. ++# Type of a background job. + # + # @commit: block commit job type, see "block-commit" + # +@@ -1064,7 +1064,7 @@ + # + # Since: 1.7 + ## +-{ 'enum': 'BlockJobType', ++{ 'enum': 'JobType', + 'data': ['commit', 'stream', 'mirror', 'backup'] } + + ## +@@ -4529,7 +4529,7 @@ + # + ## + { 'event': 'BLOCK_JOB_COMPLETED', +- 'data': { 'type' : 'BlockJobType', ++ 'data': { 'type' : 'JobType', + 'device': 'str', + 'len' : 'int', + 'offset': 'int', +@@ -4565,7 +4565,7 @@ + # + ## + { 'event': 'BLOCK_JOB_CANCELLED', +- 'data': { 'type' : 'BlockJobType', ++ 'data': { 'type' : 'JobType', + 'device': 'str', + 'len' : 'int', + 'offset': 'int', +@@ -4630,7 +4630,7 @@ + # + ## + { 'event': 'BLOCK_JOB_READY', +- 'data': { 'type' : 'BlockJobType', ++ 'data': { 'type' : 'JobType', + 'device': 'str', + 'len' : 'int', + 'offset': 'int', +@@ -4657,7 +4657,7 @@ + # + ## + { 'event': 'BLOCK_JOB_PENDING', +- 'data': { 'type' : 'BlockJobType', ++ 'data': { 'type' : 'JobType', + 'id' : 'str' } } + + ## +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Replace-BlockJob.completed-with-job_is_completed.patch b/SOURCES/kvm-job-Replace-BlockJob.completed-with-job_is_completed.patch new file mode 100644 index 0000000..6f78849 --- /dev/null +++ b/SOURCES/kvm-job-Replace-BlockJob.completed-with-job_is_completed.patch @@ -0,0 +1,185 @@ +From bafcb1e3ffe5b9af344a7891f6a62eb296687a43 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:12 +0200 +Subject: [PATCH 43/89] job: Replace BlockJob.completed with job_is_completed() + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-30-kwolf@redhat.com> +Patchwork-id: 81094 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 29/73] job: Replace BlockJob.completed with job_is_completed() +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +Since we introduced an explicit status to block job, BlockJob.completed +is redundant because it can be derived from the status. Remove the field +from BlockJob and add a function to derive it from the status at the Job +level. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +Reviewed-by: John Snow +(cherry picked from commit dbe5e6c1f73b41282624b78a2375a5c3ee59e905) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + blockjob.c | 16 +++++++--------- + include/block/blockjob.h | 3 --- + include/qemu/job.h | 3 +++ + job.c | 22 ++++++++++++++++++++++ + qemu-img.c | 4 ++-- + 5 files changed, 34 insertions(+), 14 deletions(-) + +diff --git a/blockjob.c b/blockjob.c +index 6334a54..a1d1f48 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -193,7 +193,7 @@ static void block_job_detach_aio_context(void *opaque) + + job_pause(&job->job); + +- while (!job->job.paused && !job->completed) { ++ while (!job->job.paused && !job_is_completed(&job->job)) { + block_job_drain(job); + } + +@@ -269,7 +269,6 @@ const BlockJobDriver *block_job_driver(BlockJob *job) + static void block_job_decommission(BlockJob *job) + { + assert(job); +- job->completed = true; + job->job.busy = false; + job->job.paused = false; + job->job.deferred_to_main_loop = true; +@@ -334,7 +333,7 @@ static void block_job_clean(BlockJob *job) + + static int block_job_finalize_single(BlockJob *job) + { +- assert(job->completed); ++ assert(job_is_completed(&job->job)); + + /* Ensure abort is called for late-transactional failures */ + block_job_update_rc(job); +@@ -427,10 +426,10 @@ static int block_job_finish_sync(BlockJob *job, + /* block_job_drain calls block_job_enter, and it should be enough to + * induce progress until the job completes or moves to the main thread. + */ +- while (!job->job.deferred_to_main_loop && !job->completed) { ++ while (!job->job.deferred_to_main_loop && !job_is_completed(&job->job)) { + block_job_drain(job); + } +- while (!job->completed) { ++ while (!job_is_completed(&job->job)) { + aio_poll(qemu_get_aio_context(), true); + } + ret = (job_is_cancelled(&job->job) && job->ret == 0) +@@ -471,7 +470,7 @@ static void block_job_completed_txn_abort(BlockJob *job) + while (!QLIST_EMPTY(&txn->jobs)) { + other_job = QLIST_FIRST(&txn->jobs); + ctx = blk_get_aio_context(other_job->blk); +- if (!other_job->completed) { ++ if (!job_is_completed(&other_job->job)) { + assert(job_is_cancelled(&other_job->job)); + block_job_finish_sync(other_job, NULL, NULL); + } +@@ -513,7 +512,7 @@ static void block_job_completed_txn_success(BlockJob *job) + * txn. + */ + QLIST_FOREACH(other_job, &txn->jobs, txn_list) { +- if (!other_job->completed) { ++ if (!job_is_completed(&other_job->job)) { + return; + } + assert(other_job->ret == 0); +@@ -847,9 +846,8 @@ void block_job_early_fail(BlockJob *job) + + void block_job_completed(BlockJob *job, int ret) + { +- assert(job && job->txn && !job->completed); ++ assert(job && job->txn && !job_is_completed(&job->job)); + assert(blk_bs(job->blk)->job == job); +- job->completed = true; + job->ret = ret; + block_job_update_rc(job); + trace_block_job_completed(job, ret, job->ret); +diff --git a/include/block/blockjob.h b/include/block/blockjob.h +index 556a8f6..3e94e18 100644 +--- a/include/block/blockjob.h ++++ b/include/block/blockjob.h +@@ -88,9 +88,6 @@ typedef struct BlockJob { + /** The opaque value that is passed to the completion function. */ + void *opaque; + +- /** True when job has reported completion by calling block_job_completed. */ +- bool completed; +- + /** ret code passed to block_job_completed. */ + int ret; + +diff --git a/include/qemu/job.h b/include/qemu/job.h +index bc63985..858f3be 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -214,6 +214,9 @@ const char *job_type_str(const Job *job); + /** Returns whether the job is scheduled for cancellation. */ + bool job_is_cancelled(Job *job); + ++/** Returns whether the job is in a completed state. */ ++bool job_is_completed(Job *job); ++ + /** + * Request @job to pause at the next pause point. Must be paired with + * job_resume(). If the job is supposed to be resumed by user action, call +diff --git a/job.c b/job.c +index fd10b1d..aaacfcc 100644 +--- a/job.c ++++ b/job.c +@@ -121,6 +121,28 @@ bool job_is_cancelled(Job *job) + return job->cancelled; + } + ++bool job_is_completed(Job *job) ++{ ++ switch (job->status) { ++ case JOB_STATUS_UNDEFINED: ++ case JOB_STATUS_CREATED: ++ case JOB_STATUS_RUNNING: ++ case JOB_STATUS_PAUSED: ++ case JOB_STATUS_READY: ++ case JOB_STATUS_STANDBY: ++ return false; ++ case JOB_STATUS_WAITING: ++ case JOB_STATUS_PENDING: ++ case JOB_STATUS_ABORTING: ++ case JOB_STATUS_CONCLUDED: ++ case JOB_STATUS_NULL: ++ return true; ++ default: ++ g_assert_not_reached(); ++ } ++ return false; ++} ++ + bool job_started(Job *job) + { + return job->co; +diff --git a/qemu-img.c b/qemu-img.c +index f745919..f5bb0ef 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -878,9 +878,9 @@ static void run_block_job(BlockJob *job, Error **errp) + aio_poll(aio_context, true); + qemu_progress_print(job->len ? + ((float)job->offset / job->len * 100.f) : 0.0f, 0); +- } while (!job->ready && !job->completed); ++ } while (!job->ready && !job_is_completed(&job->job)); + +- if (!job->completed) { ++ if (!job_is_completed(&job->job)) { + ret = block_job_complete_sync(job, errp); + } else { + ret = job->ret; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Switch-transactions-to-JobTxn.patch b/SOURCES/kvm-job-Switch-transactions-to-JobTxn.patch new file mode 100644 index 0000000..3f5ebdc --- /dev/null +++ b/SOURCES/kvm-job-Switch-transactions-to-JobTxn.patch @@ -0,0 +1,423 @@ +From cf8f50fd39b467c3f23f78e7bec351e07b826344 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:21 +0200 +Subject: [PATCH 52/89] job: Switch transactions to JobTxn + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-39-kwolf@redhat.com> +Patchwork-id: 81086 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 38/73] job: Switch transactions to JobTxn +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This doesn't actually move any transaction code to Job yet, but it +renames the type for transactions from BlockJobTxn to JobTxn and makes +them contain Jobs rather than BlockJobs + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +(cherry picked from commit 62c9e4162a7bc26a1389e50d17d3b2637028bbc3) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/backup.c | 2 +- + blockdev.c | 14 +++++------ + blockjob.c | 60 +++++++++++++++++++++++--------------------- + include/block/block_int.h | 2 +- + include/block/blockjob.h | 11 ++++---- + include/block/blockjob_int.h | 2 +- + include/qemu/job.h | 3 +++ + tests/test-blockjob-txn.c | 8 +++--- + 8 files changed, 54 insertions(+), 48 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index ca7d990..6172f90 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -547,7 +547,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, + BlockdevOnError on_target_error, + int creation_flags, + BlockCompletionFunc *cb, void *opaque, +- BlockJobTxn *txn, Error **errp) ++ JobTxn *txn, Error **errp) + { + int64_t len; + BlockDriverInfo bdi; +diff --git a/blockdev.c b/blockdev.c +index c2b2be1..b6f3e92 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -1488,7 +1488,7 @@ typedef struct BlkActionOps { + struct BlkActionState { + TransactionAction *action; + const BlkActionOps *ops; +- BlockJobTxn *block_job_txn; ++ JobTxn *block_job_txn; + TransactionProperties *txn_props; + QSIMPLEQ_ENTRY(BlkActionState) entry; + }; +@@ -1906,7 +1906,7 @@ typedef struct DriveBackupState { + BlockJob *job; + } DriveBackupState; + +-static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn, ++static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, + Error **errp); + + static void drive_backup_prepare(BlkActionState *common, Error **errp) +@@ -1996,7 +1996,7 @@ typedef struct BlockdevBackupState { + BlockJob *job; + } BlockdevBackupState; + +-static BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn, ++static BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn, + Error **errp); + + static void blockdev_backup_prepare(BlkActionState *common, Error **errp) +@@ -2285,7 +2285,7 @@ void qmp_transaction(TransactionActionList *dev_list, + Error **errp) + { + TransactionActionList *dev_entry = dev_list; +- BlockJobTxn *block_job_txn = NULL; ++ JobTxn *block_job_txn = NULL; + BlkActionState *state, *next; + Error *local_err = NULL; + +@@ -2293,7 +2293,7 @@ void qmp_transaction(TransactionActionList *dev_list, + QSIMPLEQ_INIT(&snap_bdrv_states); + + /* Does this transaction get canceled as a group on failure? +- * If not, we don't really need to make a BlockJobTxn. ++ * If not, we don't really need to make a JobTxn. + */ + props = get_transaction_properties(props); + if (props->completion_mode != ACTION_COMPLETION_MODE_INDIVIDUAL) { +@@ -3311,7 +3311,7 @@ out: + aio_context_release(aio_context); + } + +-static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn, ++static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, + Error **errp) + { + BlockDriverState *bs; +@@ -3481,7 +3481,7 @@ BlockDeviceInfoList *qmp_query_named_block_nodes(Error **errp) + return bdrv_named_nodes_list(errp); + } + +-BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn, ++BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn, + Error **errp) + { + BlockDriverState *bs; +diff --git a/blockjob.c b/blockjob.c +index 1ed3e9c..bd35c4f 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -37,13 +37,13 @@ + #include "qemu/timer.h" + + /* Transactional group of block jobs */ +-struct BlockJobTxn { ++struct JobTxn { + + /* Is this txn being cancelled? */ + bool aborting; + + /* List of jobs */ +- QLIST_HEAD(, BlockJob) jobs; ++ QLIST_HEAD(, Job) jobs; + + /* Reference count */ + int refcnt; +@@ -94,27 +94,27 @@ BlockJob *block_job_get(const char *id) + } + } + +-BlockJobTxn *block_job_txn_new(void) ++JobTxn *block_job_txn_new(void) + { +- BlockJobTxn *txn = g_new0(BlockJobTxn, 1); ++ JobTxn *txn = g_new0(JobTxn, 1); + QLIST_INIT(&txn->jobs); + txn->refcnt = 1; + return txn; + } + +-static void block_job_txn_ref(BlockJobTxn *txn) ++static void block_job_txn_ref(JobTxn *txn) + { + txn->refcnt++; + } + +-void block_job_txn_unref(BlockJobTxn *txn) ++void block_job_txn_unref(JobTxn *txn) + { + if (txn && --txn->refcnt == 0) { + g_free(txn); + } + } + +-void block_job_txn_add_job(BlockJobTxn *txn, BlockJob *job) ++void block_job_txn_add_job(JobTxn *txn, BlockJob *job) + { + if (!txn) { + return; +@@ -123,14 +123,14 @@ void block_job_txn_add_job(BlockJobTxn *txn, BlockJob *job) + assert(!job->txn); + job->txn = txn; + +- QLIST_INSERT_HEAD(&txn->jobs, job, txn_list); ++ QLIST_INSERT_HEAD(&txn->jobs, &job->job, txn_list); + block_job_txn_ref(txn); + } + + void block_job_txn_del_job(BlockJob *job) + { + if (job->txn) { +- QLIST_REMOVE(job, txn_list); ++ QLIST_REMOVE(&job->job, txn_list); + block_job_txn_unref(job->txn); + job->txn = NULL; + } +@@ -285,18 +285,22 @@ static void job_cancel_async(Job *job, bool force) + job->force_cancel |= force; + } + +-static int block_job_txn_apply(BlockJobTxn *txn, int fn(BlockJob *), bool lock) ++static int block_job_txn_apply(JobTxn *txn, int fn(BlockJob *), bool lock) + { + AioContext *ctx; +- BlockJob *job, *next; ++ Job *job, *next; ++ BlockJob *bjob; + int rc = 0; + + QLIST_FOREACH_SAFE(job, &txn->jobs, txn_list, next) { ++ assert(is_block_job(job)); ++ bjob = container_of(job, BlockJob, job); ++ + if (lock) { +- ctx = blk_get_aio_context(job->blk); ++ ctx = job->aio_context; + aio_context_acquire(ctx); + } +- rc = fn(job); ++ rc = fn(bjob); + if (lock) { + aio_context_release(ctx); + } +@@ -310,8 +314,8 @@ static int block_job_txn_apply(BlockJobTxn *txn, int fn(BlockJob *), bool lock) + static void block_job_completed_txn_abort(BlockJob *job) + { + AioContext *ctx; +- BlockJobTxn *txn = job->txn; +- BlockJob *other_job; ++ JobTxn *txn = job->txn; ++ Job *other_job; + + if (txn->aborting) { + /* +@@ -324,7 +328,7 @@ static void block_job_completed_txn_abort(BlockJob *job) + + /* We are the first failed job. Cancel other jobs. */ + QLIST_FOREACH(other_job, &txn->jobs, txn_list) { +- ctx = blk_get_aio_context(other_job->blk); ++ ctx = other_job->aio_context; + aio_context_acquire(ctx); + } + +@@ -332,18 +336,18 @@ static void block_job_completed_txn_abort(BlockJob *job) + * them; this job, however, may or may not be cancelled, depending + * on the caller, so leave it. */ + QLIST_FOREACH(other_job, &txn->jobs, txn_list) { +- if (other_job != job) { +- job_cancel_async(&other_job->job, false); ++ if (other_job != &job->job) { ++ job_cancel_async(other_job, false); + } + } + while (!QLIST_EMPTY(&txn->jobs)) { + other_job = QLIST_FIRST(&txn->jobs); +- ctx = blk_get_aio_context(other_job->blk); +- if (!job_is_completed(&other_job->job)) { +- assert(job_is_cancelled(&other_job->job)); +- job_finish_sync(&other_job->job, NULL, NULL); ++ ctx = other_job->aio_context; ++ if (!job_is_completed(other_job)) { ++ assert(job_is_cancelled(other_job)); ++ job_finish_sync(other_job, NULL, NULL); + } +- job_finalize_single(&other_job->job); ++ job_finalize_single(other_job); + aio_context_release(ctx); + } + +@@ -385,8 +389,8 @@ static int block_job_transition_to_pending(BlockJob *job) + + static void block_job_completed_txn_success(BlockJob *job) + { +- BlockJobTxn *txn = job->txn; +- BlockJob *other_job; ++ JobTxn *txn = job->txn; ++ Job *other_job; + + job_state_transition(&job->job, JOB_STATUS_WAITING); + +@@ -395,10 +399,10 @@ static void block_job_completed_txn_success(BlockJob *job) + * txn. + */ + QLIST_FOREACH(other_job, &txn->jobs, txn_list) { +- if (!job_is_completed(&other_job->job)) { ++ if (!job_is_completed(other_job)) { + return; + } +- assert(other_job->job.ret == 0); ++ assert(other_job->ret == 0); + } + + block_job_txn_apply(txn, block_job_transition_to_pending, false); +@@ -628,7 +632,7 @@ static void block_job_event_pending(Notifier *n, void *opaque) + */ + + void *block_job_create(const char *job_id, const BlockJobDriver *driver, +- BlockJobTxn *txn, BlockDriverState *bs, uint64_t perm, ++ JobTxn *txn, BlockDriverState *bs, uint64_t perm, + uint64_t shared_perm, int64_t speed, int flags, + BlockCompletionFunc *cb, void *opaque, Error **errp) + { +diff --git a/include/block/block_int.h b/include/block/block_int.h +index d913ed1..ad2b852 100644 +--- a/include/block/block_int.h ++++ b/include/block/block_int.h +@@ -1018,7 +1018,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, + BlockdevOnError on_target_error, + int creation_flags, + BlockCompletionFunc *cb, void *opaque, +- BlockJobTxn *txn, Error **errp); ++ JobTxn *txn, Error **errp); + + void hmp_drive_add_node(Monitor *mon, const char *optstr); + +diff --git a/include/block/blockjob.h b/include/block/blockjob.h +index 85ce18a..44df025 100644 +--- a/include/block/blockjob.h ++++ b/include/block/blockjob.h +@@ -33,7 +33,7 @@ + #define BLOCK_JOB_SLICE_TIME 100000000ULL /* ns */ + + typedef struct BlockJobDriver BlockJobDriver; +-typedef struct BlockJobTxn BlockJobTxn; ++typedef struct JobTxn JobTxn; + + /** + * BlockJob: +@@ -85,8 +85,7 @@ typedef struct BlockJob { + /** BlockDriverStates that are involved in this block job */ + GSList *nodes; + +- BlockJobTxn *txn; +- QLIST_ENTRY(BlockJob) txn_list; ++ JobTxn *txn; + } BlockJob; + + /** +@@ -273,7 +272,7 @@ void block_job_iostatus_reset(BlockJob *job); + * group. Jobs wait for each other before completing. Cancelling one job + * cancels all jobs in the transaction. + */ +-BlockJobTxn *block_job_txn_new(void); ++JobTxn *block_job_txn_new(void); + + /** + * block_job_txn_unref: +@@ -282,7 +281,7 @@ BlockJobTxn *block_job_txn_new(void); + * or block_job_txn_new. If it's the last reference to the object, it will be + * freed. + */ +-void block_job_txn_unref(BlockJobTxn *txn); ++void block_job_txn_unref(JobTxn *txn); + + /** + * block_job_txn_add_job: +@@ -293,7 +292,7 @@ void block_job_txn_unref(BlockJobTxn *txn); + * The caller must call either block_job_txn_unref() or block_job_completed() + * to release the reference that is automatically grabbed here. + */ +-void block_job_txn_add_job(BlockJobTxn *txn, BlockJob *job); ++void block_job_txn_add_job(JobTxn *txn, BlockJob *job); + + /** + * block_job_is_internal: +diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h +index b8ca7bb..ce66a9b 100644 +--- a/include/block/blockjob_int.h ++++ b/include/block/blockjob_int.h +@@ -91,7 +91,7 @@ struct BlockJobDriver { + * called from a wrapper that is specific to the job type. + */ + void *block_job_create(const char *job_id, const BlockJobDriver *driver, +- BlockJobTxn *txn, BlockDriverState *bs, uint64_t perm, ++ JobTxn *txn, BlockDriverState *bs, uint64_t perm, + uint64_t shared_perm, int64_t speed, int flags, + BlockCompletionFunc *cb, void *opaque, Error **errp); + +diff --git a/include/qemu/job.h b/include/qemu/job.h +index 17e2cec..d4aa7fa 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -132,6 +132,9 @@ typedef struct Job { + + /** Element of the list of jobs */ + QLIST_ENTRY(Job) job_list; ++ ++ /** Element of the list of jobs in a job transaction */ ++ QLIST_ENTRY(Job) txn_list; + } Job; + + /** +diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c +index 1572f8d..ec5d592 100644 +--- a/tests/test-blockjob-txn.c ++++ b/tests/test-blockjob-txn.c +@@ -93,7 +93,7 @@ static const BlockJobDriver test_block_job_driver = { + */ + static BlockJob *test_block_job_start(unsigned int iterations, + bool use_timer, +- int rc, int *result, BlockJobTxn *txn) ++ int rc, int *result, JobTxn *txn) + { + BlockDriverState *bs; + TestBlockJob *s; +@@ -122,7 +122,7 @@ static BlockJob *test_block_job_start(unsigned int iterations, + static void test_single_job(int expected) + { + BlockJob *job; +- BlockJobTxn *txn; ++ JobTxn *txn; + int result = -EINPROGRESS; + + txn = block_job_txn_new(); +@@ -160,7 +160,7 @@ static void test_pair_jobs(int expected1, int expected2) + { + BlockJob *job1; + BlockJob *job2; +- BlockJobTxn *txn; ++ JobTxn *txn; + int result1 = -EINPROGRESS; + int result2 = -EINPROGRESS; + +@@ -222,7 +222,7 @@ static void test_pair_jobs_fail_cancel_race(void) + { + BlockJob *job1; + BlockJob *job2; +- BlockJobTxn *txn; ++ JobTxn *txn; + int result1 = -EINPROGRESS; + int result2 = -EINPROGRESS; + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-job-Use-AIO_WAIT_WHILE-in-job_finish_sync.patch b/SOURCES/kvm-job-Use-AIO_WAIT_WHILE-in-job_finish_sync.patch new file mode 100644 index 0000000..9bf6503 --- /dev/null +++ b/SOURCES/kvm-job-Use-AIO_WAIT_WHILE-in-job_finish_sync.patch @@ -0,0 +1,75 @@ +From 1c16ba251ec8d0bf64ee34a0ef71b5912907de12 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:29 +0200 +Subject: [PATCH 38/49] job: Use AIO_WAIT_WHILE() in job_finish_sync() + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-32-kwolf@redhat.com> +Patchwork-id: 82184 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 31/42] job: Use AIO_WAIT_WHILE() in job_finish_sync() +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +job_finish_sync() needs to release the AioContext lock of the job before +calling aio_poll(). Otherwise, callbacks called by aio_poll() would +possibly take the lock a second time and run into a deadlock with a +nested AIO_WAIT_WHILE() call. + +Also, job_drain() without aio_poll() isn't necessarily enough to make +progress on a job, it could depend on bottom halves to be executed. + +Combine both open-coded while loops into a single AIO_WAIT_WHILE() call +that solves both of these problems. + +Signed-off-by: Kevin Wolf +Reviewed-by: Fam Zheng +Reviewed-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + job.c | 14 ++++++-------- + 1 file changed, 6 insertions(+), 8 deletions(-) + +diff --git a/job.c b/job.c +index 5a0ccc7..47b5a11 100644 +--- a/job.c ++++ b/job.c +@@ -29,6 +29,7 @@ + #include "qemu/job.h" + #include "qemu/id.h" + #include "qemu/main-loop.h" ++#include "block/aio-wait.h" + #include "trace-root.h" + #include "qapi/qapi-events-job.h" + +@@ -957,6 +958,7 @@ void job_complete(Job *job, Error **errp) + int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp) + { + Error *local_err = NULL; ++ AioWait dummy_wait = {}; + int ret; + + job_ref(job); +@@ -969,14 +971,10 @@ int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp) + job_unref(job); + return -EBUSY; + } +- /* job_drain calls job_enter, and it should be enough to induce progress +- * until the job completes or moves to the main thread. */ +- while (!job->deferred_to_main_loop && !job_is_completed(job)) { +- job_drain(job); +- } +- while (!job_is_completed(job)) { +- aio_poll(qemu_get_aio_context(), true); +- } ++ ++ AIO_WAIT_WHILE(&dummy_wait, job->aio_context, ++ (job_drain(job), !job_is_completed(job))); ++ + ret = (job_is_cancelled(job) && job->ret == 0) ? -ECANCELED : job->ret; + job_unref(job); + return ret; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-jobs-add-exit-shim.patch b/SOURCES/kvm-jobs-add-exit-shim.patch new file mode 100644 index 0000000..bef4c76 --- /dev/null +++ b/SOURCES/kvm-jobs-add-exit-shim.patch @@ -0,0 +1,108 @@ +From 8ca94edad4b07d6191bc4761a44d8289b0f8ad5d Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 10 Sep 2018 18:17:41 +0200 +Subject: [PATCH 03/25] jobs: add exit shim + +RH-Author: John Snow +Message-id: <20180910181803.11781-4-jsnow@redhat.com> +Patchwork-id: 82104 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 03/25] jobs: add exit shim +Bugzilla: 1626061 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +All jobs do the same thing when they leave their running loop: +- Store the return code in a structure +- wait to receive this structure in the main thread +- signal job completion via job_completed + +Few jobs do anything beyond exactly this. Consolidate this exit +logic for a net reduction in SLOC. + +More seriously, when we utilize job_defer_to_main_loop_bh to call +a function that calls job_completed, job_finalize_single will run +in a context where it has recursively taken the aio_context lock, +which can cause hangs if it puts down a reference that causes a flush. + +You can observe this in practice by looking at mirror_exit's careful +placement of job_completed and bdrv_unref calls. + +If we centralize job exiting, we can signal job completion from outside +of the aio_context, which should allow for job cleanup code to run with +only one lock, which makes cleanup callbacks less tricky to write. + +Signed-off-by: John Snow +Reviewed-by: Max Reitz +Message-id: 20180830015734.19765-4-jsnow@redhat.com +Reviewed-by: Jeff Cody +Signed-off-by: Max Reitz +(cherry picked from commit 00359a71d45a414ee47d8e423104dc0afd24ec65) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + include/qemu/job.h | 11 +++++++++++ + job.c | 18 ++++++++++++++++++ + 2 files changed, 29 insertions(+) + +diff --git a/include/qemu/job.h b/include/qemu/job.h +index 905dfdd..24b5f3f 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -209,6 +209,17 @@ struct JobDriver { + void (*drain)(Job *job); + + /** ++ * If the callback is not NULL, exit will be invoked from the main thread ++ * when the job's coroutine has finished, but before transactional ++ * convergence; before @prepare or @abort. ++ * ++ * FIXME TODO: This callback is only temporary to transition remaining jobs ++ * to prepare/commit/abort/clean callbacks and will be removed before 3.1. ++ * is released. ++ */ ++ void (*exit)(Job *job); ++ ++ /** + * If the callback is not NULL, prepare will be invoked when all the jobs + * belonging to the same transaction complete; or upon this job's completion + * if it is not in a transaction. +diff --git a/job.c b/job.c +index 020ee0d..a814857 100644 +--- a/job.c ++++ b/job.c +@@ -530,6 +530,18 @@ void job_drain(Job *job) + } + } + ++static void job_exit(void *opaque) ++{ ++ Job *job = (Job *)opaque; ++ AioContext *aio_context = job->aio_context; ++ ++ if (job->driver->exit) { ++ aio_context_acquire(aio_context); ++ job->driver->exit(job); ++ aio_context_release(aio_context); ++ } ++ job_completed(job, job->ret); ++} + + /** + * All jobs must allow a pause point before entering their job proper. This +@@ -542,6 +554,12 @@ static void coroutine_fn job_co_entry(void *opaque) + assert(job && job->driver && job->driver->run); + job_pause_point(job); + job->ret = job->driver->run(job, &job->err); ++ if (!job->deferred_to_main_loop) { ++ job->deferred_to_main_loop = true; ++ aio_bh_schedule_oneshot(qemu_get_aio_context(), ++ job_exit, ++ job); ++ } + } + + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-jobs-canonize-Error-object.patch b/SOURCES/kvm-jobs-canonize-Error-object.patch new file mode 100644 index 0000000..6b75ce5 --- /dev/null +++ b/SOURCES/kvm-jobs-canonize-Error-object.patch @@ -0,0 +1,285 @@ +From d384736e7c77d64142f33fabc0aa50878d8f252e Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 10 Sep 2018 18:17:40 +0200 +Subject: [PATCH 02/25] jobs: canonize Error object + +RH-Author: John Snow +Message-id: <20180910181803.11781-3-jsnow@redhat.com> +Patchwork-id: 82085 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 02/25] jobs: canonize Error object +Bugzilla: 1626061 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Jobs presently use both an Error object in the case of the create job, +and char strings in the case of generic errors elsewhere. + +Unify the two paths as just j->err, and remove the extra argument from +job_completed. The integer error code for job_completed is kept for now, +to be removed shortly in a separate patch. + +Signed-off-by: John Snow +Message-id: 20180830015734.19765-3-jsnow@redhat.com +[mreitz: Dropped a superfluous g_strdup()] +Reviewed-by: Eric Blake +Signed-off-by: Max Reitz +(cherry picked from commit 3d1f8b07a4c241f81949eff507d9f3a8fd73b87b) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + block/backup.c | 2 +- + block/commit.c | 2 +- + block/create.c | 5 ++--- + block/mirror.c | 2 +- + block/stream.c | 2 +- + include/qemu/job.h | 14 ++++++++------ + job-qmp.c | 5 +++-- + job.c | 18 ++++++------------ + tests/test-bdrv-drain.c | 2 +- + tests/test-blockjob-txn.c | 2 +- + tests/test-blockjob.c | 2 +- + 11 files changed, 26 insertions(+), 30 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index a142518..a5bf699 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -388,7 +388,7 @@ static void backup_complete(Job *job, void *opaque) + { + BackupCompleteData *data = opaque; + +- job_completed(job, data->ret, NULL); ++ job_completed(job, data->ret); + g_free(data); + } + +diff --git a/block/commit.c b/block/commit.c +index 905a1c5..af7579d 100644 +--- a/block/commit.c ++++ b/block/commit.c +@@ -117,7 +117,7 @@ static void commit_complete(Job *job, void *opaque) + * bdrv_set_backing_hd() to fail. */ + block_job_remove_all_bdrv(bjob); + +- job_completed(job, ret, NULL); ++ job_completed(job, ret); + g_free(data); + + /* If bdrv_drop_intermediate() didn't already do that, remove the commit +diff --git a/block/create.c b/block/create.c +index 04733c3..26a385c 100644 +--- a/block/create.c ++++ b/block/create.c +@@ -35,14 +35,13 @@ typedef struct BlockdevCreateJob { + BlockDriver *drv; + BlockdevCreateOptions *opts; + int ret; +- Error *err; + } BlockdevCreateJob; + + static void blockdev_create_complete(Job *job, void *opaque) + { + BlockdevCreateJob *s = container_of(job, BlockdevCreateJob, common); + +- job_completed(job, s->ret, s->err); ++ job_completed(job, s->ret); + } + + static int coroutine_fn blockdev_create_run(Job *job, Error **errp) +@@ -50,7 +49,7 @@ static int coroutine_fn blockdev_create_run(Job *job, Error **errp) + BlockdevCreateJob *s = container_of(job, BlockdevCreateJob, common); + + job_progress_set_remaining(&s->common, 1); +- s->ret = s->drv->bdrv_co_create(s->opts, &s->err); ++ s->ret = s->drv->bdrv_co_create(s->opts, errp); + job_progress_update(&s->common, 1); + + qapi_free_BlockdevCreateOptions(s->opts); +diff --git a/block/mirror.c b/block/mirror.c +index 03b326d..459f944 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -581,7 +581,7 @@ static void mirror_exit(Job *job, void *opaque) + blk_set_perm(bjob->blk, 0, BLK_PERM_ALL, &error_abort); + blk_insert_bs(bjob->blk, mirror_top_bs, &error_abort); + +- job_completed(job, data->ret, NULL); ++ job_completed(job, data->ret); + + g_free(data); + bdrv_drained_end(src); +diff --git a/block/stream.c b/block/stream.c +index b4b987d..26a7753 100644 +--- a/block/stream.c ++++ b/block/stream.c +@@ -93,7 +93,7 @@ out: + } + + g_free(s->backing_file_str); +- job_completed(job, data->ret, NULL); ++ job_completed(job, data->ret); + g_free(data); + } + +diff --git a/include/qemu/job.h b/include/qemu/job.h +index e81cc34..905dfdd 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -124,12 +124,16 @@ typedef struct Job { + /** Estimated progress_current value at the completion of the job */ + int64_t progress_total; + +- /** Error string for a failed job (NULL if, and only if, job->ret == 0) */ +- char *error; +- + /** ret code passed to job_completed. */ + int ret; + ++ /** ++ * Error object for a failed job. ++ * If job->ret is nonzero and an error object was not set, it will be set ++ * to strerror(-job->ret) during job_completed. ++ */ ++ Error *err; ++ + /** The completion function that will be called when the job completes. */ + BlockCompletionFunc *cb; + +@@ -469,15 +473,13 @@ void job_transition_to_ready(Job *job); + /** + * @job: The job being completed. + * @ret: The status code. +- * @error: The error message for a failing job (only with @ret < 0). If @ret is +- * negative, but NULL is given for @error, strerror() is used. + * + * Marks @job as completed. If @ret is non-zero, the job transaction it is part + * of is aborted. If @ret is zero, the job moves into the WAITING state. If it + * is the last job to complete in its transaction, all jobs in the transaction + * move from WAITING to PENDING. + */ +-void job_completed(Job *job, int ret, Error *error); ++void job_completed(Job *job, int ret); + + /** Asynchronously complete the specified @job. */ + void job_complete(Job *job, Error **errp); +diff --git a/job-qmp.c b/job-qmp.c +index 410775d..a969b2b 100644 +--- a/job-qmp.c ++++ b/job-qmp.c +@@ -146,8 +146,9 @@ static JobInfo *job_query_single(Job *job, Error **errp) + .status = job->status, + .current_progress = job->progress_current, + .total_progress = job->progress_total, +- .has_error = !!job->error, +- .error = g_strdup(job->error), ++ .has_error = !!job->err, ++ .error = job->err ? \ ++ g_strdup(error_get_pretty(job->err)) : NULL, + }; + + return info; +diff --git a/job.c b/job.c +index 0d07700..020ee0d 100644 +--- a/job.c ++++ b/job.c +@@ -369,7 +369,7 @@ void job_unref(Job *job) + + QLIST_REMOVE(job, job_list); + +- g_free(job->error); ++ error_free(job->err); + g_free(job->id); + g_free(job); + } +@@ -541,7 +541,7 @@ static void coroutine_fn job_co_entry(void *opaque) + + assert(job && job->driver && job->driver->run); + job_pause_point(job); +- job->ret = job->driver->run(job, NULL); ++ job->ret = job->driver->run(job, &job->err); + } + + +@@ -661,8 +661,8 @@ static void job_update_rc(Job *job) + job->ret = -ECANCELED; + } + if (job->ret) { +- if (!job->error) { +- job->error = g_strdup(strerror(-job->ret)); ++ if (!job->err) { ++ error_setg(&job->err, "%s", strerror(-job->ret)); + } + job_state_transition(job, JOB_STATUS_ABORTING); + } +@@ -860,17 +860,11 @@ static void job_completed_txn_success(Job *job) + } + } + +-void job_completed(Job *job, int ret, Error *error) ++void job_completed(Job *job, int ret) + { + assert(job && job->txn && !job_is_completed(job)); + + job->ret = ret; +- if (error) { +- assert(job->ret < 0); +- job->error = g_strdup(error_get_pretty(error)); +- error_free(error); +- } +- + job_update_rc(job); + trace_job_completed(job, ret, job->ret); + if (job->ret) { +@@ -888,7 +882,7 @@ void job_cancel(Job *job, bool force) + } + job_cancel_async(job, force); + if (!job_started(job)) { +- job_completed(job, -ECANCELED, NULL); ++ job_completed(job, -ECANCELED); + } else if (job->deferred_to_main_loop) { + job_completed_txn_abort(job); + } else { +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index 798445a..8937894 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -498,7 +498,7 @@ typedef struct TestBlockJob { + + static void test_job_completed(Job *job, void *opaque) + { +- job_completed(job, 0, NULL); ++ job_completed(job, 0); + } + + static int coroutine_fn test_job_run(Job *job, Error **errp) +diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c +index 3194924..82cedee 100644 +--- a/tests/test-blockjob-txn.c ++++ b/tests/test-blockjob-txn.c +@@ -34,7 +34,7 @@ static void test_block_job_complete(Job *job, void *opaque) + rc = -ECANCELED; + } + +- job_completed(job, rc, NULL); ++ job_completed(job, rc); + bdrv_unref(bs); + } + +diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c +index b0462bf..408a226 100644 +--- a/tests/test-blockjob.c ++++ b/tests/test-blockjob.c +@@ -167,7 +167,7 @@ static void cancel_job_completed(Job *job, void *opaque) + { + CancelJob *s = opaque; + s->completed = true; +- job_completed(job, 0, NULL); ++ job_completed(job, 0); + } + + static void cancel_job_complete(Job *job, Error **errp) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-jobs-change-start-callback-to-run-callback.patch b/SOURCES/kvm-jobs-change-start-callback-to-run-callback.patch new file mode 100644 index 0000000..d2a9a4e --- /dev/null +++ b/SOURCES/kvm-jobs-change-start-callback-to-run-callback.patch @@ -0,0 +1,372 @@ +From 751387e28f5006dd063010ff0b0912ff9b44c2fe Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 10 Sep 2018 18:17:39 +0200 +Subject: [PATCH 01/25] jobs: change start callback to run callback + +RH-Author: John Snow +Message-id: <20180910181803.11781-2-jsnow@redhat.com> +Patchwork-id: 82102 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 01/25] jobs: change start callback to run callback +Bugzilla: 1626061 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Presently we codify the entry point for a job as the "start" callback, +but a more apt name would be "run" to clarify the idea that when this +function returns we consider the job to have "finished," except for +any cleanup which occurs in separate callbacks later. + +As part of this clarification, change the signature to include an error +object and a return code. The error ptr is not yet used, and the return +code while captured, will be overwritten by actions in the job_completed +function. + +Signed-off-by: John Snow +Reviewed-by: Max Reitz +Message-id: 20180830015734.19765-2-jsnow@redhat.com +Reviewed-by: Jeff Cody +Signed-off-by: Max Reitz +(cherry picked from commit f67432a2019caf05b57a146bf45c1024a5cb608e) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/backup.c | 7 ++++--- + block/commit.c | 7 ++++--- + block/create.c | 8 +++++--- + block/mirror.c | 10 ++++++---- + block/stream.c | 7 ++++--- + include/qemu/job.h | 2 +- + job.c | 6 +++--- + tests/test-bdrv-drain.c | 7 ++++--- + tests/test-blockjob-txn.c | 16 ++++++++-------- + tests/test-blockjob.c | 7 ++++--- + 10 files changed, 43 insertions(+), 34 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index 4ba1a6a..a142518 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -480,9 +480,9 @@ static void backup_incremental_init_copy_bitmap(BackupBlockJob *job) + bdrv_dirty_iter_free(dbi); + } + +-static void coroutine_fn backup_run(void *opaque) ++static int coroutine_fn backup_run(Job *opaque_job, Error **errp) + { +- BackupBlockJob *job = opaque; ++ BackupBlockJob *job = container_of(opaque_job, BackupBlockJob, common.job); + BackupCompleteData *data; + BlockDriverState *bs = blk_bs(job->common.blk); + int64_t offset, nb_clusters; +@@ -587,6 +587,7 @@ static void coroutine_fn backup_run(void *opaque) + data = g_malloc(sizeof(*data)); + data->ret = ret; + job_defer_to_main_loop(&job->common.job, backup_complete, data); ++ return ret; + } + + static const BlockJobDriver backup_job_driver = { +@@ -596,7 +597,7 @@ static const BlockJobDriver backup_job_driver = { + .free = block_job_free, + .user_resume = block_job_user_resume, + .drain = block_job_drain, +- .start = backup_run, ++ .run = backup_run, + .commit = backup_commit, + .abort = backup_abort, + .clean = backup_clean, +diff --git a/block/commit.c b/block/commit.c +index e1814d9..905a1c5 100644 +--- a/block/commit.c ++++ b/block/commit.c +@@ -134,9 +134,9 @@ static void commit_complete(Job *job, void *opaque) + bdrv_unref(top); + } + +-static void coroutine_fn commit_run(void *opaque) ++static int coroutine_fn commit_run(Job *job, Error **errp) + { +- CommitBlockJob *s = opaque; ++ CommitBlockJob *s = container_of(job, CommitBlockJob, common.job); + CommitCompleteData *data; + int64_t offset; + uint64_t delay_ns = 0; +@@ -213,6 +213,7 @@ out: + data = g_malloc(sizeof(*data)); + data->ret = ret; + job_defer_to_main_loop(&s->common.job, commit_complete, data); ++ return ret; + } + + static const BlockJobDriver commit_job_driver = { +@@ -222,7 +223,7 @@ static const BlockJobDriver commit_job_driver = { + .free = block_job_free, + .user_resume = block_job_user_resume, + .drain = block_job_drain, +- .start = commit_run, ++ .run = commit_run, + }, + }; + +diff --git a/block/create.c b/block/create.c +index 915cd41..04733c3 100644 +--- a/block/create.c ++++ b/block/create.c +@@ -45,9 +45,9 @@ static void blockdev_create_complete(Job *job, void *opaque) + job_completed(job, s->ret, s->err); + } + +-static void coroutine_fn blockdev_create_run(void *opaque) ++static int coroutine_fn blockdev_create_run(Job *job, Error **errp) + { +- BlockdevCreateJob *s = opaque; ++ BlockdevCreateJob *s = container_of(job, BlockdevCreateJob, common); + + job_progress_set_remaining(&s->common, 1); + s->ret = s->drv->bdrv_co_create(s->opts, &s->err); +@@ -55,12 +55,14 @@ static void coroutine_fn blockdev_create_run(void *opaque) + + qapi_free_BlockdevCreateOptions(s->opts); + job_defer_to_main_loop(&s->common, blockdev_create_complete, NULL); ++ ++ return s->ret; + } + + static const JobDriver blockdev_create_job_driver = { + .instance_size = sizeof(BlockdevCreateJob), + .job_type = JOB_TYPE_CREATE, +- .start = blockdev_create_run, ++ .run = blockdev_create_run, + }; + + void qmp_blockdev_create(const char *job_id, BlockdevCreateOptions *options, +diff --git a/block/mirror.c b/block/mirror.c +index 65cf43d..03b326d 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -683,9 +683,9 @@ static int mirror_flush(MirrorBlockJob *s) + return ret; + } + +-static void coroutine_fn mirror_run(void *opaque) ++static int coroutine_fn mirror_run(Job *job, Error **errp) + { +- MirrorBlockJob *s = opaque; ++ MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job); + MirrorExitData *data; + BlockDriverState *bs = s->source; + BlockDriverState *target_bs = blk_bs(s->target); +@@ -902,7 +902,9 @@ immediate_exit: + if (need_drain) { + bdrv_drained_begin(bs); + } ++ + job_defer_to_main_loop(&s->common.job, mirror_exit, data); ++ return ret; + } + + static void mirror_complete(Job *job, Error **errp) +@@ -993,7 +995,7 @@ static const BlockJobDriver mirror_job_driver = { + .free = block_job_free, + .user_resume = block_job_user_resume, + .drain = block_job_drain, +- .start = mirror_run, ++ .run = mirror_run, + .pause = mirror_pause, + .complete = mirror_complete, + }, +@@ -1008,7 +1010,7 @@ static const BlockJobDriver commit_active_job_driver = { + .free = block_job_free, + .user_resume = block_job_user_resume, + .drain = block_job_drain, +- .start = mirror_run, ++ .run = mirror_run, + .pause = mirror_pause, + .complete = mirror_complete, + }, +diff --git a/block/stream.c b/block/stream.c +index 9264b68..b4b987d 100644 +--- a/block/stream.c ++++ b/block/stream.c +@@ -97,9 +97,9 @@ out: + g_free(data); + } + +-static void coroutine_fn stream_run(void *opaque) ++static int coroutine_fn stream_run(Job *job, Error **errp) + { +- StreamBlockJob *s = opaque; ++ StreamBlockJob *s = container_of(job, StreamBlockJob, common.job); + StreamCompleteData *data; + BlockBackend *blk = s->common.blk; + BlockDriverState *bs = blk_bs(blk); +@@ -206,6 +206,7 @@ out: + data = g_malloc(sizeof(*data)); + data->ret = ret; + job_defer_to_main_loop(&s->common.job, stream_complete, data); ++ return ret; + } + + static const BlockJobDriver stream_job_driver = { +@@ -213,7 +214,7 @@ static const BlockJobDriver stream_job_driver = { + .instance_size = sizeof(StreamBlockJob), + .job_type = JOB_TYPE_STREAM, + .free = block_job_free, +- .start = stream_run, ++ .run = stream_run, + .user_resume = block_job_user_resume, + .drain = block_job_drain, + }, +diff --git a/include/qemu/job.h b/include/qemu/job.h +index 1d82053..e81cc34 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -169,7 +169,7 @@ struct JobDriver { + JobType job_type; + + /** Mandatory: Entrypoint for the Coroutine. */ +- CoroutineEntry *start; ++ int coroutine_fn (*run)(Job *job, Error **errp); + + /** + * If the callback is not NULL, it will be invoked when the job transitions +diff --git a/job.c b/job.c +index 95dc998..0d07700 100644 +--- a/job.c ++++ b/job.c +@@ -539,16 +539,16 @@ static void coroutine_fn job_co_entry(void *opaque) + { + Job *job = opaque; + +- assert(job && job->driver && job->driver->start); ++ assert(job && job->driver && job->driver->run); + job_pause_point(job); +- job->driver->start(job); ++ job->ret = job->driver->run(job, NULL); + } + + + void job_start(Job *job) + { + assert(job && !job_started(job) && job->paused && +- job->driver && job->driver->start); ++ job->driver && job->driver->run); + job->co = qemu_coroutine_create(job_co_entry, job); + job->pause_count--; + job->busy = true; +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index a11c4cf..798445a 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -501,9 +501,9 @@ static void test_job_completed(Job *job, void *opaque) + job_completed(job, 0, NULL); + } + +-static void coroutine_fn test_job_start(void *opaque) ++static int coroutine_fn test_job_run(Job *job, Error **errp) + { +- TestBlockJob *s = opaque; ++ TestBlockJob *s = container_of(job, TestBlockJob, common.job); + + job_transition_to_ready(&s->common.job); + while (!s->should_complete) { +@@ -511,6 +511,7 @@ static void coroutine_fn test_job_start(void *opaque) + } + + job_defer_to_main_loop(&s->common.job, test_job_completed, NULL); ++ return 0; + } + + static void test_job_complete(Job *job, Error **errp) +@@ -525,7 +526,7 @@ BlockJobDriver test_job_driver = { + .free = block_job_free, + .user_resume = block_job_user_resume, + .drain = block_job_drain, +- .start = test_job_start, ++ .run = test_job_run, + .complete = test_job_complete, + }, + }; +diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c +index 58d9b87..3194924 100644 +--- a/tests/test-blockjob-txn.c ++++ b/tests/test-blockjob-txn.c +@@ -38,25 +38,25 @@ static void test_block_job_complete(Job *job, void *opaque) + bdrv_unref(bs); + } + +-static void coroutine_fn test_block_job_run(void *opaque) ++static int coroutine_fn test_block_job_run(Job *job, Error **errp) + { +- TestBlockJob *s = opaque; +- BlockJob *job = &s->common; ++ TestBlockJob *s = container_of(job, TestBlockJob, common.job); + + while (s->iterations--) { + if (s->use_timer) { +- job_sleep_ns(&job->job, 0); ++ job_sleep_ns(job, 0); + } else { +- job_yield(&job->job); ++ job_yield(job); + } + +- if (job_is_cancelled(&job->job)) { ++ if (job_is_cancelled(job)) { + break; + } + } + +- job_defer_to_main_loop(&job->job, test_block_job_complete, ++ job_defer_to_main_loop(job, test_block_job_complete, + (void *)(intptr_t)s->rc); ++ return s->rc; + } + + typedef struct { +@@ -80,7 +80,7 @@ static const BlockJobDriver test_block_job_driver = { + .free = block_job_free, + .user_resume = block_job_user_resume, + .drain = block_job_drain, +- .start = test_block_job_run, ++ .run = test_block_job_run, + }, + }; + +diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c +index cb42f06..b0462bf 100644 +--- a/tests/test-blockjob.c ++++ b/tests/test-blockjob.c +@@ -176,9 +176,9 @@ static void cancel_job_complete(Job *job, Error **errp) + s->should_complete = true; + } + +-static void coroutine_fn cancel_job_start(void *opaque) ++static int coroutine_fn cancel_job_run(Job *job, Error **errp) + { +- CancelJob *s = opaque; ++ CancelJob *s = container_of(job, CancelJob, common.job); + + while (!s->should_complete) { + if (job_is_cancelled(&s->common.job)) { +@@ -194,6 +194,7 @@ static void coroutine_fn cancel_job_start(void *opaque) + + defer: + job_defer_to_main_loop(&s->common.job, cancel_job_completed, s); ++ return 0; + } + + static const BlockJobDriver test_cancel_driver = { +@@ -202,7 +203,7 @@ static const BlockJobDriver test_cancel_driver = { + .free = block_job_free, + .user_resume = block_job_user_resume, + .drain = block_job_drain, +- .start = cancel_job_start, ++ .run = cancel_job_run, + .complete = cancel_job_complete, + }, + }; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-jobs-fix-stale-wording.patch b/SOURCES/kvm-jobs-fix-stale-wording.patch new file mode 100644 index 0000000..ad9f936 --- /dev/null +++ b/SOURCES/kvm-jobs-fix-stale-wording.patch @@ -0,0 +1,62 @@ +From 8fa85725f454d8e727763460dcfa63aaa16b18b2 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:53 +0200 +Subject: [PATCH 84/89] jobs: fix stale wording + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-71-kwolf@redhat.com> +Patchwork-id: 81107 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 70/73] jobs: fix stale wording +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +From: John Snow + +During the design for manual completion, we decided not to use the +"manual" property as a shorthand for both auto-dismiss and auto-finalize. + +Fix the wording. + +Signed-off-by: John Snow +Reviewed-by: Jeff Cody +Reviewed-by: Markus Armbruster +Signed-off-by: Kevin Wolf +(cherry picked from commit c5b09f3f2c4db32f39ecbde2cf2f78e7a657a85d) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + qapi/job.json | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/qapi/job.json b/qapi/job.json +index 17d1003..2264435 100644 +--- a/qapi/job.json ++++ b/qapi/job.json +@@ -50,16 +50,17 @@ + # the last job in a transaction. + # + # @pending: The job has finished its work, but has finalization steps that it +-# needs to make prior to completing. These changes may require +-# manual intervention by the management process if manual was set +-# to true. These changes may still fail. ++# needs to make prior to completing. These changes will require ++# manual intervention via @job-finalize if auto-finalize was set to ++# false. These pending changes may still fail. + # + # @aborting: The job is in the process of being aborted, and will finish with + # an error. The job will afterwards report that it is @concluded. + # This status may not be visible to the management process. + # +-# @concluded: The job has finished all work. If manual was set to true, the job +-# will remain in the query list until it is dismissed. ++# @concluded: The job has finished all work. If auto-dismiss was set to false, ++# the job will remain in the query list until it is dismissed via ++# @job-dismiss. + # + # @null: The job is in the process of being dismantled. This state should not + # ever be visible externally. +-- +1.8.3.1 + diff --git a/SOURCES/kvm-jobs-fix-verb-references-in-docs.patch b/SOURCES/kvm-jobs-fix-verb-references-in-docs.patch new file mode 100644 index 0000000..073c7e3 --- /dev/null +++ b/SOURCES/kvm-jobs-fix-verb-references-in-docs.patch @@ -0,0 +1,66 @@ +From b4b170fbc6181b49bae5d5bfa7a45e00356d1230 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:54 +0200 +Subject: [PATCH 85/89] jobs: fix verb references in docs + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-72-kwolf@redhat.com> +Patchwork-id: 81108 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 71/73] jobs: fix verb references in docs +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +From: John Snow + +These point to the job versions now, not the blockjob versions which +don't really exist anymore. + +Except set-speed, which does. It sticks out like a sore thumb. This +patch doesn't fix that, but it doesn't make it any worse, either. + +Signed-off-by: John Snow +Reviewed-by: Jeff Cody +Reviewed-by: Markus Armbruster +Signed-off-by: Kevin Wolf +(cherry picked from commit b8a366feb2aa2200c42fa983a9c607fb78a501db) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + qapi/job.json | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/qapi/job.json b/qapi/job.json +index 2264435..9d074eb 100644 +--- a/qapi/job.json ++++ b/qapi/job.json +@@ -76,19 +76,19 @@ + # + # Represents command verbs that can be applied to a job. + # +-# @cancel: see @block-job-cancel ++# @cancel: see @job-cancel + # +-# @pause: see @block-job-pause ++# @pause: see @job-pause + # +-# @resume: see @block-job-resume ++# @resume: see @job-resume + # + # @set-speed: see @block-job-set-speed + # +-# @complete: see @block-job-complete ++# @complete: see @job-complete + # +-# @dismiss: see @block-job-dismiss ++# @dismiss: see @job-dismiss + # +-# @finalize: see @block-job-finalize ++# @finalize: see @job-finalize + # + # Since: 2.12 + ## +-- +1.8.3.1 + diff --git a/SOURCES/kvm-jobs-remove-.exit-callback.patch b/SOURCES/kvm-jobs-remove-.exit-callback.patch new file mode 100644 index 0000000..1507ad8 --- /dev/null +++ b/SOURCES/kvm-jobs-remove-.exit-callback.patch @@ -0,0 +1,156 @@ +From 583fce2c4839f5b0f3da8794182cc7738311a991 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 10 Sep 2018 18:17:58 +0200 +Subject: [PATCH 20/25] jobs: remove .exit callback + +RH-Author: John Snow +Message-id: <20180910181803.11781-21-jsnow@redhat.com> +Patchwork-id: 82101 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 20/25] jobs: remove .exit callback +Bugzilla: 1626061 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Now that all of the jobs use the component finalization callbacks, +there's no use for the heavy-hammer .exit callback anymore. + +job_exit becomes a glorified type shim so that we can call +job_completed from aio_bh_schedule_oneshot. + +Move these three functions down into job.c to eliminate a +forward reference. + +Signed-off-by: John Snow +Reviewed-by: Max Reitz +Message-id: 20180906130225.5118-12-jsnow@redhat.com +Reviewed-by: Jeff Cody +Signed-off-by: Max Reitz +(cherry picked from commit 7e9e7780ef18e902a6458dfa6b024d9e2053923c) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + include/qemu/job.h | 11 -------- + job.c | 77 ++++++++++++++++++++++++------------------------------ + 2 files changed, 34 insertions(+), 54 deletions(-) + +diff --git a/include/qemu/job.h b/include/qemu/job.h +index 04090ba..fdaa06f 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -222,17 +222,6 @@ struct JobDriver { + void (*drain)(Job *job); + + /** +- * If the callback is not NULL, exit will be invoked from the main thread +- * when the job's coroutine has finished, but before transactional +- * convergence; before @prepare or @abort. +- * +- * FIXME TODO: This callback is only temporary to transition remaining jobs +- * to prepare/commit/abort/clean callbacks and will be removed before 3.1. +- * is released. +- */ +- void (*exit)(Job *job); +- +- /** + * If the callback is not NULL, prepare will be invoked when all the jobs + * belonging to the same transaction complete; or upon this job's completion + * if it is not in a transaction. +diff --git a/job.c b/job.c +index f56e6a3..dfba4bc 100644 +--- a/job.c ++++ b/job.c +@@ -530,49 +530,6 @@ void job_drain(Job *job) + } + } + +-static void job_completed(Job *job); +- +-static void job_exit(void *opaque) +-{ +- Job *job = (Job *)opaque; +- AioContext *aio_context = job->aio_context; +- +- if (job->driver->exit) { +- aio_context_acquire(aio_context); +- job->driver->exit(job); +- aio_context_release(aio_context); +- } +- job_completed(job); +-} +- +-/** +- * All jobs must allow a pause point before entering their job proper. This +- * ensures that jobs can be paused prior to being started, then resumed later. +- */ +-static void coroutine_fn job_co_entry(void *opaque) +-{ +- Job *job = opaque; +- +- assert(job && job->driver && job->driver->run); +- job_pause_point(job); +- job->ret = job->driver->run(job, &job->err); +- job->deferred_to_main_loop = true; +- aio_bh_schedule_oneshot(qemu_get_aio_context(), job_exit, job); +-} +- +- +-void job_start(Job *job) +-{ +- assert(job && !job_started(job) && job->paused && +- job->driver && job->driver->run); +- job->co = qemu_coroutine_create(job_co_entry, job); +- job->pause_count--; +- job->busy = true; +- job->paused = false; +- job_state_transition(job, JOB_STATUS_RUNNING); +- aio_co_enter(job->aio_context, job->co); +-} +- + /* Assumes the block_job_mutex is held */ + static bool job_timer_not_pending(Job *job) + { +@@ -889,6 +846,40 @@ static void job_completed(Job *job) + } + } + ++/** Useful only as a type shim for aio_bh_schedule_oneshot. */ ++static void job_exit(void *opaque) ++{ ++ Job *job = (Job *)opaque; ++ job_completed(job); ++} ++ ++/** ++ * All jobs must allow a pause point before entering their job proper. This ++ * ensures that jobs can be paused prior to being started, then resumed later. ++ */ ++static void coroutine_fn job_co_entry(void *opaque) ++{ ++ Job *job = opaque; ++ ++ assert(job && job->driver && job->driver->run); ++ job_pause_point(job); ++ job->ret = job->driver->run(job, &job->err); ++ job->deferred_to_main_loop = true; ++ aio_bh_schedule_oneshot(qemu_get_aio_context(), job_exit, job); ++} ++ ++void job_start(Job *job) ++{ ++ assert(job && !job_started(job) && job->paused && ++ job->driver && job->driver->run); ++ job->co = qemu_coroutine_create(job_co_entry, job); ++ job->pause_count--; ++ job->busy = true; ++ job->paused = false; ++ job_state_transition(job, JOB_STATUS_RUNNING); ++ aio_co_enter(job->aio_context, job->co); ++} ++ + void job_cancel(Job *job, bool force) + { + if (job->status == JOB_STATUS_CONCLUDED) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-jobs-remove-job_defer_to_main_loop.patch b/SOURCES/kvm-jobs-remove-job_defer_to_main_loop.patch new file mode 100644 index 0000000..6e84315 --- /dev/null +++ b/SOURCES/kvm-jobs-remove-job_defer_to_main_loop.patch @@ -0,0 +1,119 @@ +From 580a6b0332f21a364e2b807dcf63434fddaceada Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 10 Sep 2018 18:17:47 +0200 +Subject: [PATCH 09/25] jobs: remove job_defer_to_main_loop + +RH-Author: John Snow +Message-id: <20180910181803.11781-10-jsnow@redhat.com> +Patchwork-id: 82107 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 09/25] jobs: remove job_defer_to_main_loop +Bugzilla: 1626061 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Now that the job infrastructure is handling the job_completed call for +all implemented jobs, we can remove the interface that allowed jobs to +schedule their own completion. + +Signed-off-by: John Snow +Reviewed-by: Max Reitz +Message-id: 20180830015734.19765-10-jsnow@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit e21a1c9831fc80ae3f3c1affdfa43350035d8588) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + include/qemu/job.h | 17 ----------------- + job.c | 40 ++-------------------------------------- + 2 files changed, 2 insertions(+), 55 deletions(-) + +diff --git a/include/qemu/job.h b/include/qemu/job.h +index 952ac3a..04090ba 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -553,23 +553,6 @@ void job_finalize(Job *job, Error **errp); + */ + void job_dismiss(Job **job, Error **errp); + +-typedef void JobDeferToMainLoopFn(Job *job, void *opaque); +- +-/** +- * @job: The job +- * @fn: The function to run in the main loop +- * @opaque: The opaque value that is passed to @fn +- * +- * This function must be called by the main job coroutine just before it +- * returns. @fn is executed in the main loop with the job AioContext acquired. +- * +- * Block jobs must call bdrv_unref(), bdrv_close(), and anything that uses +- * bdrv_drain_all() in the main loop. +- * +- * The @job AioContext is held while @fn executes. +- */ +-void job_defer_to_main_loop(Job *job, JobDeferToMainLoopFn *fn, void *opaque); +- + /** + * Synchronously finishes the given @job. If @finish is given, it is called to + * trigger completion or cancellation of the job. +diff --git a/job.c b/job.c +index 1acbcbc..f56e6a3 100644 +--- a/job.c ++++ b/job.c +@@ -556,12 +556,8 @@ static void coroutine_fn job_co_entry(void *opaque) + assert(job && job->driver && job->driver->run); + job_pause_point(job); + job->ret = job->driver->run(job, &job->err); +- if (!job->deferred_to_main_loop) { +- job->deferred_to_main_loop = true; +- aio_bh_schedule_oneshot(qemu_get_aio_context(), +- job_exit, +- job); +- } ++ job->deferred_to_main_loop = true; ++ aio_bh_schedule_oneshot(qemu_get_aio_context(), job_exit, job); + } + + +@@ -964,38 +960,6 @@ void job_complete(Job *job, Error **errp) + job->driver->complete(job, errp); + } + +- +-typedef struct { +- Job *job; +- JobDeferToMainLoopFn *fn; +- void *opaque; +-} JobDeferToMainLoopData; +- +-static void job_defer_to_main_loop_bh(void *opaque) +-{ +- JobDeferToMainLoopData *data = opaque; +- Job *job = data->job; +- AioContext *aio_context = job->aio_context; +- +- aio_context_acquire(aio_context); +- data->fn(data->job, data->opaque); +- aio_context_release(aio_context); +- +- g_free(data); +-} +- +-void job_defer_to_main_loop(Job *job, JobDeferToMainLoopFn *fn, void *opaque) +-{ +- JobDeferToMainLoopData *data = g_malloc(sizeof(*data)); +- data->job = job; +- data->fn = fn; +- data->opaque = opaque; +- job->deferred_to_main_loop = true; +- +- aio_bh_schedule_oneshot(qemu_get_aio_context(), +- job_defer_to_main_loop_bh, data); +-} +- + int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp) + { + Error *local_err = NULL; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-jobs-remove-ret-argument-to-job_completed-privatize-.patch b/SOURCES/kvm-jobs-remove-ret-argument-to-job_completed-privatize-.patch new file mode 100644 index 0000000..086a750 --- /dev/null +++ b/SOURCES/kvm-jobs-remove-ret-argument-to-job_completed-privatize-.patch @@ -0,0 +1,154 @@ +From 8a39bfe61aa3e30907f583f7f2e90e7d90004f56 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 10 Sep 2018 18:17:46 +0200 +Subject: [PATCH 08/25] jobs: remove ret argument to job_completed; privatize + it + +RH-Author: John Snow +Message-id: <20180910181803.11781-9-jsnow@redhat.com> +Patchwork-id: 82095 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 08/25] jobs: remove ret argument to job_completed; privatize it +Bugzilla: 1626061 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Jobs are now expected to return their retcode on the stack, from the +.run callback, so we can remove that argument. + +job_cancel does not need to set -ECANCELED because job_completed will +update the return code itself if the job was canceled. + +While we're here, make job_completed static to job.c and remove it from +job.h; move the documentation of return code to the .run() callback and +to the job->ret property, accordingly. + +Signed-off-by: John Snow +Message-id: 20180830015734.19765-9-jsnow@redhat.com +Reviewed-by: Max Reitz +Signed-off-by: Max Reitz +(cherry picked from commit 404ff28d6ae59fc1c24d631710d4063fc68aed03) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + include/qemu/job.h | 28 +++++++++++++++------------- + job.c | 11 ++++++----- + trace-events | 2 +- + 3 files changed, 22 insertions(+), 19 deletions(-) + +diff --git a/include/qemu/job.h b/include/qemu/job.h +index 24b5f3f..952ac3a 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -124,7 +124,11 @@ typedef struct Job { + /** Estimated progress_current value at the completion of the job */ + int64_t progress_total; + +- /** ret code passed to job_completed. */ ++ /** ++ * Return code from @run and/or @prepare callback(s). ++ * Not final until the job has reached the CONCLUDED status. ++ * 0 on success, -errno on failure. ++ */ + int ret; + + /** +@@ -172,7 +176,16 @@ struct JobDriver { + /** Enum describing the operation */ + JobType job_type; + +- /** Mandatory: Entrypoint for the Coroutine. */ ++ /** ++ * Mandatory: Entrypoint for the Coroutine. ++ * ++ * This callback will be invoked when moving from CREATED to RUNNING. ++ * ++ * If this callback returns nonzero, the job transaction it is part of is ++ * aborted. If it returns zero, the job moves into the WAITING state. If it ++ * is the last job to complete in its transaction, all jobs in the ++ * transaction move from WAITING to PENDING. ++ */ + int coroutine_fn (*run)(Job *job, Error **errp); + + /** +@@ -481,17 +494,6 @@ void job_early_fail(Job *job); + /** Moves the @job from RUNNING to READY */ + void job_transition_to_ready(Job *job); + +-/** +- * @job: The job being completed. +- * @ret: The status code. +- * +- * Marks @job as completed. If @ret is non-zero, the job transaction it is part +- * of is aborted. If @ret is zero, the job moves into the WAITING state. If it +- * is the last job to complete in its transaction, all jobs in the transaction +- * move from WAITING to PENDING. +- */ +-void job_completed(Job *job, int ret); +- + /** Asynchronously complete the specified @job. */ + void job_complete(Job *job, Error **errp); + +diff --git a/job.c b/job.c +index a814857..1acbcbc 100644 +--- a/job.c ++++ b/job.c +@@ -530,6 +530,8 @@ void job_drain(Job *job) + } + } + ++static void job_completed(Job *job); ++ + static void job_exit(void *opaque) + { + Job *job = (Job *)opaque; +@@ -540,7 +542,7 @@ static void job_exit(void *opaque) + job->driver->exit(job); + aio_context_release(aio_context); + } +- job_completed(job, job->ret); ++ job_completed(job); + } + + /** +@@ -878,13 +880,12 @@ static void job_completed_txn_success(Job *job) + } + } + +-void job_completed(Job *job, int ret) ++static void job_completed(Job *job) + { + assert(job && job->txn && !job_is_completed(job)); + +- job->ret = ret; + job_update_rc(job); +- trace_job_completed(job, ret, job->ret); ++ trace_job_completed(job, job->ret); + if (job->ret) { + job_completed_txn_abort(job); + } else { +@@ -900,7 +901,7 @@ void job_cancel(Job *job, bool force) + } + job_cancel_async(job, force); + if (!job_started(job)) { +- job_completed(job, -ECANCELED); ++ job_completed(job); + } else if (job->deferred_to_main_loop) { + job_completed_txn_abort(job); + } else { +diff --git a/trace-events b/trace-events +index c445f54..4fd2cb4 100644 +--- a/trace-events ++++ b/trace-events +@@ -107,7 +107,7 @@ gdbstub_err_checksum_incorrect(uint8_t expected, uint8_t got) "got command packe + # job.c + job_state_transition(void *job, int ret, const char *legal, const char *s0, const char *s1) "job %p (ret: %d) attempting %s transition (%s-->%s)" + job_apply_verb(void *job, const char *state, const char *verb, const char *legal) "job %p in state %s; applying verb %s (%s)" +-job_completed(void *job, int ret, int jret) "job %p ret %d corrected ret %d" ++job_completed(void *job, int ret) "job %p ret %d" + + # job-qmp.c + qmp_job_cancel(void *job) "job %p" +-- +1.8.3.1 + diff --git a/SOURCES/kvm-jobs-utilize-job_exit-shim.patch b/SOURCES/kvm-jobs-utilize-job_exit-shim.patch new file mode 100644 index 0000000..aac8e8b --- /dev/null +++ b/SOURCES/kvm-jobs-utilize-job_exit-shim.patch @@ -0,0 +1,307 @@ +From 2986609502d393267e97d2bb874427acef906a61 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 10 Sep 2018 18:17:44 +0200 +Subject: [PATCH 06/25] jobs: utilize job_exit shim + +RH-Author: John Snow +Message-id: <20180910181803.11781-7-jsnow@redhat.com> +Patchwork-id: 82106 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 06/25] jobs: utilize job_exit shim +Bugzilla: 1626061 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Utilize the job_exit shim by not calling job_defer_to_main_loop, and +where applicable, converting the deferred callback into the job_exit +callback. + +This converts backup, stream, create, and the unit tests all at once. +Most of these jobs do not see any changes to the order in which they +clean up their resources, except the test-blockjob-txn test, which +now puts down its bs before job_completed is called. + +This is safe for the same reason the reordering in the mirror job is +safe, because job_completed no longer runs under two locks, making +the unref safe even if it causes a flush. + +Signed-off-by: John Snow +Reviewed-by: Max Reitz +Message-id: 20180830015734.19765-7-jsnow@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit eb23654dbe43b549ea2a9ebff9d8edf544d34a73) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/backup.c | 16 ---------------- + block/create.c | 14 +++----------- + block/stream.c | 22 +++++++--------------- + tests/test-bdrv-drain.c | 6 ------ + tests/test-blockjob-txn.c | 11 ++--------- + tests/test-blockjob.c | 10 ++++------ + 6 files changed, 16 insertions(+), 63 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index a5bf699..08a5b74 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -380,18 +380,6 @@ static BlockErrorAction backup_error_action(BackupBlockJob *job, + } + } + +-typedef struct { +- int ret; +-} BackupCompleteData; +- +-static void backup_complete(Job *job, void *opaque) +-{ +- BackupCompleteData *data = opaque; +- +- job_completed(job, data->ret); +- g_free(data); +-} +- + static bool coroutine_fn yield_and_check(BackupBlockJob *job) + { + uint64_t delay_ns; +@@ -483,7 +471,6 @@ static void backup_incremental_init_copy_bitmap(BackupBlockJob *job) + static int coroutine_fn backup_run(Job *opaque_job, Error **errp) + { + BackupBlockJob *job = container_of(opaque_job, BackupBlockJob, common.job); +- BackupCompleteData *data; + BlockDriverState *bs = blk_bs(job->common.blk); + int64_t offset, nb_clusters; + int ret = 0; +@@ -584,9 +571,6 @@ static int coroutine_fn backup_run(Job *opaque_job, Error **errp) + qemu_co_rwlock_unlock(&job->flush_rwlock); + hbitmap_free(job->copy_bitmap); + +- data = g_malloc(sizeof(*data)); +- data->ret = ret; +- job_defer_to_main_loop(&job->common.job, backup_complete, data); + return ret; + } + +diff --git a/block/create.c b/block/create.c +index 26a385c..9534121 100644 +--- a/block/create.c ++++ b/block/create.c +@@ -34,28 +34,20 @@ typedef struct BlockdevCreateJob { + Job common; + BlockDriver *drv; + BlockdevCreateOptions *opts; +- int ret; + } BlockdevCreateJob; + +-static void blockdev_create_complete(Job *job, void *opaque) +-{ +- BlockdevCreateJob *s = container_of(job, BlockdevCreateJob, common); +- +- job_completed(job, s->ret); +-} +- + static int coroutine_fn blockdev_create_run(Job *job, Error **errp) + { + BlockdevCreateJob *s = container_of(job, BlockdevCreateJob, common); ++ int ret; + + job_progress_set_remaining(&s->common, 1); +- s->ret = s->drv->bdrv_co_create(s->opts, errp); ++ ret = s->drv->bdrv_co_create(s->opts, errp); + job_progress_update(&s->common, 1); + + qapi_free_BlockdevCreateOptions(s->opts); +- job_defer_to_main_loop(&s->common, blockdev_create_complete, NULL); + +- return s->ret; ++ return ret; + } + + static const JobDriver blockdev_create_job_driver = { +diff --git a/block/stream.c b/block/stream.c +index 26a7753..67e1e72 100644 +--- a/block/stream.c ++++ b/block/stream.c +@@ -54,20 +54,16 @@ static int coroutine_fn stream_populate(BlockBackend *blk, + return blk_co_preadv(blk, offset, qiov.size, &qiov, BDRV_REQ_COPY_ON_READ); + } + +-typedef struct { +- int ret; +-} StreamCompleteData; +- +-static void stream_complete(Job *job, void *opaque) ++static void stream_exit(Job *job) + { + StreamBlockJob *s = container_of(job, StreamBlockJob, common.job); + BlockJob *bjob = &s->common; +- StreamCompleteData *data = opaque; + BlockDriverState *bs = blk_bs(bjob->blk); + BlockDriverState *base = s->base; + Error *local_err = NULL; ++ int ret = job->ret; + +- if (!job_is_cancelled(job) && bs->backing && data->ret == 0) { ++ if (!job_is_cancelled(job) && bs->backing && ret == 0) { + const char *base_id = NULL, *base_fmt = NULL; + if (base) { + base_id = s->backing_file_str; +@@ -75,11 +71,11 @@ static void stream_complete(Job *job, void *opaque) + base_fmt = base->drv->format_name; + } + } +- data->ret = bdrv_change_backing_file(bs, base_id, base_fmt); ++ ret = bdrv_change_backing_file(bs, base_id, base_fmt); + bdrv_set_backing_hd(bs, base, &local_err); + if (local_err) { + error_report_err(local_err); +- data->ret = -EPERM; ++ ret = -EPERM; + goto out; + } + } +@@ -93,14 +89,12 @@ out: + } + + g_free(s->backing_file_str); +- job_completed(job, data->ret); +- g_free(data); ++ job->ret = ret; + } + + static int coroutine_fn stream_run(Job *job, Error **errp) + { + StreamBlockJob *s = container_of(job, StreamBlockJob, common.job); +- StreamCompleteData *data; + BlockBackend *blk = s->common.blk; + BlockDriverState *bs = blk_bs(blk); + BlockDriverState *base = s->base; +@@ -203,9 +197,6 @@ static int coroutine_fn stream_run(Job *job, Error **errp) + + out: + /* Modify backing chain and close BDSes in main loop */ +- data = g_malloc(sizeof(*data)); +- data->ret = ret; +- job_defer_to_main_loop(&s->common.job, stream_complete, data); + return ret; + } + +@@ -215,6 +206,7 @@ static const BlockJobDriver stream_job_driver = { + .job_type = JOB_TYPE_STREAM, + .free = block_job_free, + .run = stream_run, ++ .exit = stream_exit, + .user_resume = block_job_user_resume, + .drain = block_job_drain, + }, +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index 8937894..403446e 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -496,11 +496,6 @@ typedef struct TestBlockJob { + bool should_complete; + } TestBlockJob; + +-static void test_job_completed(Job *job, void *opaque) +-{ +- job_completed(job, 0); +-} +- + static int coroutine_fn test_job_run(Job *job, Error **errp) + { + TestBlockJob *s = container_of(job, TestBlockJob, common.job); +@@ -510,7 +505,6 @@ static int coroutine_fn test_job_run(Job *job, Error **errp) + job_sleep_ns(&s->common.job, 100000); + } + +- job_defer_to_main_loop(&s->common.job, test_job_completed, NULL); + return 0; + } + +diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c +index 82cedee..ef29f35 100644 +--- a/tests/test-blockjob-txn.c ++++ b/tests/test-blockjob-txn.c +@@ -24,17 +24,11 @@ typedef struct { + int *result; + } TestBlockJob; + +-static void test_block_job_complete(Job *job, void *opaque) ++static void test_block_job_exit(Job *job) + { + BlockJob *bjob = container_of(job, BlockJob, job); + BlockDriverState *bs = blk_bs(bjob->blk); +- int rc = (intptr_t)opaque; + +- if (job_is_cancelled(job)) { +- rc = -ECANCELED; +- } +- +- job_completed(job, rc); + bdrv_unref(bs); + } + +@@ -54,8 +48,6 @@ static int coroutine_fn test_block_job_run(Job *job, Error **errp) + } + } + +- job_defer_to_main_loop(job, test_block_job_complete, +- (void *)(intptr_t)s->rc); + return s->rc; + } + +@@ -81,6 +73,7 @@ static const BlockJobDriver test_block_job_driver = { + .user_resume = block_job_user_resume, + .drain = block_job_drain, + .run = test_block_job_run, ++ .exit = test_block_job_exit, + }, + }; + +diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c +index 408a226..ad4a65b 100644 +--- a/tests/test-blockjob.c ++++ b/tests/test-blockjob.c +@@ -163,11 +163,10 @@ typedef struct CancelJob { + bool completed; + } CancelJob; + +-static void cancel_job_completed(Job *job, void *opaque) ++static void cancel_job_exit(Job *job) + { +- CancelJob *s = opaque; ++ CancelJob *s = container_of(job, CancelJob, common.job); + s->completed = true; +- job_completed(job, 0); + } + + static void cancel_job_complete(Job *job, Error **errp) +@@ -182,7 +181,7 @@ static int coroutine_fn cancel_job_run(Job *job, Error **errp) + + while (!s->should_complete) { + if (job_is_cancelled(&s->common.job)) { +- goto defer; ++ return 0; + } + + if (!job_is_ready(&s->common.job) && s->should_converge) { +@@ -192,8 +191,6 @@ static int coroutine_fn cancel_job_run(Job *job, Error **errp) + job_sleep_ns(&s->common.job, 100000); + } + +- defer: +- job_defer_to_main_loop(&s->common.job, cancel_job_completed, s); + return 0; + } + +@@ -204,6 +201,7 @@ static const BlockJobDriver test_cancel_driver = { + .user_resume = block_job_user_resume, + .drain = block_job_drain, + .run = cancel_job_run, ++ .exit = cancel_job_exit, + .complete = cancel_job_complete, + }, + }; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-kdump-set-vmcoreinfo-location.patch b/SOURCES/kvm-kdump-set-vmcoreinfo-location.patch deleted file mode 100644 index aaadcaf..0000000 --- a/SOURCES/kvm-kdump-set-vmcoreinfo-location.patch +++ /dev/null @@ -1,79 +0,0 @@ -From b3bd980c95466b3bd35b784b2862a3896e4b3dbc Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Mon, 27 Nov 2017 22:51:08 +0100 -Subject: [PATCH 10/21] kdump: set vmcoreinfo location -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Marc-André Lureau -Message-id: <20171127225111.24518-7-marcandre.lureau@redhat.com> -Patchwork-id: 77923 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 6/9] kdump: set vmcoreinfo location -Bugzilla: 1398633 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Andrew Jones -RH-Acked-by: Miroslav Rezanina - -kdump header provides offset and size of the vmcoreinfo content, -append it if available (skip the ELF note header). - -crash-7.1.9 was the first version that started looking in the -vmcoreinfo data for phys_base instead of in the kdump_sub_header. - -Signed-off-by: Marc-André Lureau -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin - -(cherry picked from commit 9ada575bbafaf6d3724a7f59df9da89776817cac) -Signed-off-by: Marc-André Lureau -Signed-off-by: Miroslav Rezanina ---- - dump.c | 24 ++++++++++++++++++++++++ - 1 file changed, 24 insertions(+) - -diff --git a/dump.c b/dump.c -index e3175d7..1852db9 100644 ---- a/dump.c -+++ b/dump.c -@@ -858,6 +858,18 @@ static void create_header32(DumpState *s, Error **errp) - kh->dump_level = cpu_to_dump32(s, DUMP_LEVEL); - - offset_note = DISKDUMP_HEADER_BLOCKS * block_size + size; -+ if (s->guest_note && -+ note_name_equal(s, s->guest_note, "VMCOREINFO")) { -+ uint64_t hsize, name_size, size_vmcoreinfo_desc, offset_vmcoreinfo; -+ -+ get_note_sizes(s, s->guest_note, -+ &hsize, &name_size, &size_vmcoreinfo_desc); -+ offset_vmcoreinfo = offset_note + s->note_size - s->guest_note_size + -+ (DIV_ROUND_UP(hsize, 4) + DIV_ROUND_UP(name_size, 4)) * 4; -+ kh->offset_vmcoreinfo = cpu_to_dump64(s, offset_vmcoreinfo); -+ kh->size_vmcoreinfo = cpu_to_dump32(s, size_vmcoreinfo_desc); -+ } -+ - kh->offset_note = cpu_to_dump64(s, offset_note); - kh->note_size = cpu_to_dump32(s, s->note_size); - -@@ -958,6 +970,18 @@ static void create_header64(DumpState *s, Error **errp) - kh->dump_level = cpu_to_dump32(s, DUMP_LEVEL); - - offset_note = DISKDUMP_HEADER_BLOCKS * block_size + size; -+ if (s->guest_note && -+ note_name_equal(s, s->guest_note, "VMCOREINFO")) { -+ uint64_t hsize, name_size, size_vmcoreinfo_desc, offset_vmcoreinfo; -+ -+ get_note_sizes(s, s->guest_note, -+ &hsize, &name_size, &size_vmcoreinfo_desc); -+ offset_vmcoreinfo = offset_note + s->note_size - s->guest_note_size + -+ (DIV_ROUND_UP(hsize, 4) + DIV_ROUND_UP(name_size, 4)) * 4; -+ kh->offset_vmcoreinfo = cpu_to_dump64(s, offset_vmcoreinfo); -+ kh->size_vmcoreinfo = cpu_to_dump64(s, size_vmcoreinfo_desc); -+ } -+ - kh->offset_note = cpu_to_dump64(s, offset_note); - kh->note_size = cpu_to_dump64(s, s->note_size); - --- -1.8.3.1 - diff --git a/SOURCES/kvm-libvhost-user-support-host-notifier.patch b/SOURCES/kvm-libvhost-user-support-host-notifier.patch new file mode 100644 index 0000000..62099e0 --- /dev/null +++ b/SOURCES/kvm-libvhost-user-support-host-notifier.patch @@ -0,0 +1,239 @@ +From bf38c0c9b897040dddc38456f731006c817e3c39 Mon Sep 17 00:00:00 2001 +From: "plai@redhat.com" +Date: Thu, 21 Jun 2018 18:54:45 +0200 +Subject: [PATCH 36/57] libvhost-user: support host notifier + +RH-Author: plai@redhat.com +Message-id: <1529607285-9942-11-git-send-email-plai@redhat.com> +Patchwork-id: 80939 +O-Subject: [RHEL7.6 PATCH BZ 1526645 10/10] libvhost-user: support host notifier +Bugzilla: 1526645 +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Maxime Coquelin +RH-Acked-by: Laurent Vivier + +From: Tiwei Bie + +This patch introduces the host notifier support in +libvhost-user. A new API is added to support setting +host notifier for each queue. + +Signed-off-by: Tiwei Bie +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit d84599f56c820d8c1ac9928a76500dcdfbbf194d) +Signed-off-by: Paul Lai +Signed-off-by: Miroslav Rezanina +--- + contrib/libvhost-user/libvhost-user.c | 81 +++++++++++++++++++++++++++++++---- + contrib/libvhost-user/libvhost-user.h | 32 ++++++++++++++ + 2 files changed, 105 insertions(+), 8 deletions(-) + +diff --git a/contrib/libvhost-user/libvhost-user.c b/contrib/libvhost-user/libvhost-user.c +index beeed0c..fa06eee 100644 +--- a/contrib/libvhost-user/libvhost-user.c ++++ b/contrib/libvhost-user/libvhost-user.c +@@ -314,11 +314,6 @@ vu_message_write(VuDev *dev, int conn_fd, VhostUserMsg *vmsg) + msg.msg_controllen = 0; + } + +- /* Set the version in the flags when sending the reply */ +- vmsg->flags &= ~VHOST_USER_VERSION_MASK; +- vmsg->flags |= VHOST_USER_VERSION; +- vmsg->flags |= VHOST_USER_REPLY_MASK; +- + do { + rc = sendmsg(conn_fd, &msg, 0); + } while (rc < 0 && (errno == EINTR || errno == EAGAIN)); +@@ -339,6 +334,39 @@ vu_message_write(VuDev *dev, int conn_fd, VhostUserMsg *vmsg) + return true; + } + ++static bool ++vu_send_reply(VuDev *dev, int conn_fd, VhostUserMsg *vmsg) ++{ ++ /* Set the version in the flags when sending the reply */ ++ vmsg->flags &= ~VHOST_USER_VERSION_MASK; ++ vmsg->flags |= VHOST_USER_VERSION; ++ vmsg->flags |= VHOST_USER_REPLY_MASK; ++ ++ return vu_message_write(dev, conn_fd, vmsg); ++} ++ ++static bool ++vu_process_message_reply(VuDev *dev, const VhostUserMsg *vmsg) ++{ ++ VhostUserMsg msg_reply; ++ ++ if ((vmsg->flags & VHOST_USER_NEED_REPLY_MASK) == 0) { ++ return true; ++ } ++ ++ if (!vu_message_read(dev, dev->slave_fd, &msg_reply)) { ++ return false; ++ } ++ ++ if (msg_reply.request != vmsg->request) { ++ DPRINT("Received unexpected msg type. Expected %d received %d", ++ vmsg->request, msg_reply.request); ++ return false; ++ } ++ ++ return msg_reply.payload.u64 == 0; ++} ++ + /* Kick the log_call_fd if required. */ + static void + vu_log_kick(VuDev *dev) +@@ -534,7 +562,7 @@ vu_set_mem_table_exec_postcopy(VuDev *dev, VhostUserMsg *vmsg) + + /* Send the message back to qemu with the addresses filled in */ + vmsg->fd_num = 0; +- if (!vu_message_write(dev, dev->sock, vmsg)) { ++ if (!vu_send_reply(dev, dev->sock, vmsg)) { + vu_panic(dev, "failed to respond to set-mem-table for postcopy"); + return false; + } +@@ -914,6 +942,41 @@ void vu_set_queue_handler(VuDev *dev, VuVirtq *vq, + } + } + ++bool vu_set_queue_host_notifier(VuDev *dev, VuVirtq *vq, int fd, ++ int size, int offset) ++{ ++ int qidx = vq - dev->vq; ++ int fd_num = 0; ++ VhostUserMsg vmsg = { ++ .request = VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG, ++ .flags = VHOST_USER_VERSION | VHOST_USER_NEED_REPLY_MASK, ++ .size = sizeof(vmsg.payload.area), ++ .payload.area = { ++ .u64 = qidx & VHOST_USER_VRING_IDX_MASK, ++ .size = size, ++ .offset = offset, ++ }, ++ }; ++ ++ if (fd == -1) { ++ vmsg.payload.area.u64 |= VHOST_USER_VRING_NOFD_MASK; ++ } else { ++ vmsg.fds[fd_num++] = fd; ++ } ++ ++ vmsg.fd_num = fd_num; ++ ++ if ((dev->protocol_features & VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD) == 0) { ++ return false; ++ } ++ ++ if (!vu_message_write(dev, dev->slave_fd, &vmsg)) { ++ return false; ++ } ++ ++ return vu_process_message_reply(dev, &vmsg); ++} ++ + static bool + vu_set_vring_call_exec(VuDev *dev, VhostUserMsg *vmsg) + { +@@ -966,7 +1029,9 @@ static bool + vu_get_protocol_features_exec(VuDev *dev, VhostUserMsg *vmsg) + { + uint64_t features = 1ULL << VHOST_USER_PROTOCOL_F_LOG_SHMFD | +- 1ULL << VHOST_USER_PROTOCOL_F_SLAVE_REQ; ++ 1ULL << VHOST_USER_PROTOCOL_F_SLAVE_REQ | ++ 1ULL << VHOST_USER_PROTOCOL_F_HOST_NOTIFIER | ++ 1ULL << VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD; + + if (have_userfault()) { + features |= 1ULL << VHOST_USER_PROTOCOL_F_PAGEFAULT; +@@ -1250,7 +1315,7 @@ vu_dispatch(VuDev *dev) + goto end; + } + +- if (!vu_message_write(dev, dev->sock, &vmsg)) { ++ if (!vu_send_reply(dev, dev->sock, &vmsg)) { + goto end; + } + +diff --git a/contrib/libvhost-user/libvhost-user.h b/contrib/libvhost-user/libvhost-user.h +index b27075e..4aa55b4 100644 +--- a/contrib/libvhost-user/libvhost-user.h ++++ b/contrib/libvhost-user/libvhost-user.h +@@ -51,6 +51,8 @@ enum VhostUserProtocolFeature { + VHOST_USER_PROTOCOL_F_CRYPTO_SESSION = 7, + VHOST_USER_PROTOCOL_F_PAGEFAULT = 8, + VHOST_USER_PROTOCOL_F_CONFIG = 9, ++ VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD = 10, ++ VHOST_USER_PROTOCOL_F_HOST_NOTIFIER = 11, + + VHOST_USER_PROTOCOL_F_MAX + }; +@@ -92,6 +94,14 @@ typedef enum VhostUserRequest { + VHOST_USER_MAX + } VhostUserRequest; + ++typedef enum VhostUserSlaveRequest { ++ VHOST_USER_SLAVE_NONE = 0, ++ VHOST_USER_SLAVE_IOTLB_MSG = 1, ++ VHOST_USER_SLAVE_CONFIG_CHANGE_MSG = 2, ++ VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG = 3, ++ VHOST_USER_SLAVE_MAX ++} VhostUserSlaveRequest; ++ + typedef struct VhostUserMemoryRegion { + uint64_t guest_phys_addr; + uint64_t memory_size; +@@ -122,6 +132,12 @@ static VhostUserConfig c __attribute__ ((unused)); + + sizeof(c.size) \ + + sizeof(c.flags)) + ++typedef struct VhostUserVringArea { ++ uint64_t u64; ++ uint64_t size; ++ uint64_t offset; ++} VhostUserVringArea; ++ + #if defined(_WIN32) + # define VU_PACKED __attribute__((gcc_struct, packed)) + #else +@@ -133,6 +149,7 @@ typedef struct VhostUserMsg { + + #define VHOST_USER_VERSION_MASK (0x3) + #define VHOST_USER_REPLY_MASK (0x1 << 2) ++#define VHOST_USER_NEED_REPLY_MASK (0x1 << 3) + uint32_t flags; + uint32_t size; /* the following payload size */ + +@@ -145,6 +162,7 @@ typedef struct VhostUserMsg { + VhostUserMemory memory; + VhostUserLog log; + VhostUserConfig config; ++ VhostUserVringArea area; + } payload; + + int fds[VHOST_MEMORY_MAX_NREGIONS]; +@@ -368,6 +386,20 @@ VuVirtq *vu_get_queue(VuDev *dev, int qidx); + void vu_set_queue_handler(VuDev *dev, VuVirtq *vq, + vu_queue_handler_cb handler); + ++/** ++ * vu_set_queue_host_notifier: ++ * @dev: a VuDev context ++ * @vq: a VuVirtq queue ++ * @fd: a file descriptor ++ * @size: host page size ++ * @offset: notifier offset in @fd file ++ * ++ * Set queue's host notifier. This function may be called several ++ * times for the same queue. If called with -1 @fd, the notifier ++ * is removed. ++ */ ++bool vu_set_queue_host_notifier(VuDev *dev, VuVirtq *vq, int fd, ++ int size, int offset); + + /** + * vu_queue_set_notification: +-- +1.8.3.1 + diff --git a/SOURCES/kvm-linux-headers-Partial-header-update-against-v4.15-rc.patch b/SOURCES/kvm-linux-headers-Partial-header-update-against-v4.15-rc.patch deleted file mode 100644 index 6cb0baa..0000000 --- a/SOURCES/kvm-linux-headers-Partial-header-update-against-v4.15-rc.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 0669bbc6c287d15912c9501b391f051ff463801e Mon Sep 17 00:00:00 2001 -From: Auger Eric -Date: Tue, 28 Nov 2017 15:14:07 +0100 -Subject: [PATCH 6/9] linux-headers: Partial header update against v4.15-rc1 - for ITS reset - -RH-Author: Auger Eric -Message-id: <1511882048-11256-7-git-send-email-eric.auger@redhat.com> -Patchwork-id: 77938 -O-Subject: [RHV7.5 qemu-kvm-ma PATCH 6/7] linux-headers: Partial header update against v4.15-rc1 for ITS reset -Bugzilla: 1513323 -RH-Acked-by: Andrew Jones -RH-Acked-by: Miroslav Rezanina -RH-Acked-by: Wei Huang - -This aims at importing the KVM_DEV_ARM_ITS_CTRL_RESET attribute -which allows to trigger a reset of the in-kernel emulated ITS. - -Signed-off-by: Eric Auger -Signed-off-by: Miroslav Rezanina ---- - linux-headers/asm-arm/kvm.h | 1 + - linux-headers/asm-arm64/kvm.h | 1 + - 2 files changed, 2 insertions(+) - -diff --git a/linux-headers/asm-arm/kvm.h b/linux-headers/asm-arm/kvm.h -index fa9fae8..8dd0ba7 100644 ---- a/linux-headers/asm-arm/kvm.h -+++ b/linux-headers/asm-arm/kvm.h -@@ -215,6 +215,7 @@ struct kvm_arch_memory_slot { - #define KVM_DEV_ARM_ITS_SAVE_TABLES 1 - #define KVM_DEV_ARM_ITS_RESTORE_TABLES 2 - #define KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES 3 -+#define KVM_DEV_ARM_ITS_CTRL_RESET 4 - - /* KVM_IRQ_LINE irq field index values */ - #define KVM_ARM_IRQ_TYPE_SHIFT 24 -diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h -index d254700..2585a50 100644 ---- a/linux-headers/asm-arm64/kvm.h -+++ b/linux-headers/asm-arm64/kvm.h -@@ -227,6 +227,7 @@ struct kvm_arch_memory_slot { - #define KVM_DEV_ARM_ITS_SAVE_TABLES 1 - #define KVM_DEV_ARM_ITS_RESTORE_TABLES 2 - #define KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES 3 -+#define KVM_DEV_ARM_ITS_CTRL_RESET 4 - - /* Device Control API on vcpu fd */ - #define KVM_ARM_VCPU_PMU_V3_CTRL 0 --- -1.8.3.1 - diff --git a/SOURCES/kvm-linux-headers-asm-s390-kvm.h-header-sync.patch b/SOURCES/kvm-linux-headers-asm-s390-kvm.h-header-sync.patch new file mode 100644 index 0000000..808ce50 --- /dev/null +++ b/SOURCES/kvm-linux-headers-asm-s390-kvm.h-header-sync.patch @@ -0,0 +1,56 @@ +From cbc01f1f70ca63d88bc80b38884a064957c9dc41 Mon Sep 17 00:00:00 2001 +From: Thomas Huth +Date: Tue, 28 Aug 2018 17:03:11 +0200 +Subject: [PATCH 01/29] linux-headers: asm-s390/kvm.h header sync + +RH-Author: Thomas Huth +Message-id: <1535475792-21136-2-git-send-email-thuth@redhat.com> +Patchwork-id: 81947 +O-Subject: [RHEL-7.6 qemu-kvm-ma PATCH 1/2] linux-headers: asm-s390/kvm.h header sync +Bugzilla: 1622962 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Cornelia Huck +RH-Acked-by: Jens Freimann + +This is a header sync with the linux uapi header. The corresponding +kernel commit id is a3da7b4a3be51f37f434f14e11e60491f098b6ea. + +Signed-off-by: Thomas Huth +Signed-off-by: Miroslav Rezanina +--- + linux-headers/asm-s390/kvm.h | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/linux-headers/asm-s390/kvm.h b/linux-headers/asm-s390/kvm.h +index 11def14..1ab9901 100644 +--- a/linux-headers/asm-s390/kvm.h ++++ b/linux-headers/asm-s390/kvm.h +@@ -4,7 +4,7 @@ + /* + * KVM s390 specific structures and definitions + * +- * Copyright IBM Corp. 2008 ++ * Copyright IBM Corp. 2008, 2018 + * + * Author(s): Carsten Otte + * Christian Borntraeger +@@ -225,6 +225,7 @@ struct kvm_guest_debug_arch { + #define KVM_SYNC_FPRS (1UL << 8) + #define KVM_SYNC_GSCB (1UL << 9) + #define KVM_SYNC_BPBC (1UL << 10) ++#define KVM_SYNC_ETOKEN (1UL << 11) + /* length and alignment of the sdnx as a power of two */ + #define SDNXC 8 + #define SDNXL (1UL << SDNXC) +@@ -258,6 +259,8 @@ struct kvm_sync_regs { + struct { + __u64 reserved1[2]; + __u64 gscb[4]; ++ __u64 etoken; ++ __u64 etoken_extension; + }; + }; + }; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-linux-headers-update.patch b/SOURCES/kvm-linux-headers-update.patch deleted file mode 100644 index d968825..0000000 --- a/SOURCES/kvm-linux-headers-update.patch +++ /dev/null @@ -1,176 +0,0 @@ -From 170662bb45c6a4290391c8f896e437b5dc67e229 Mon Sep 17 00:00:00 2001 -From: Thomas Huth -Date: Tue, 23 Jan 2018 19:12:44 +0100 -Subject: [PATCH 2/8] linux-headers: update - -RH-Author: Thomas Huth -Message-id: <1516734766-12075-2-git-send-email-thuth@redhat.com> -Patchwork-id: 78699 -O-Subject: [RHEL-7.5 qemu-kvm-ma PATCH 1/3] linux-headers: update -Bugzilla: 1535606 -RH-Acked-by: David Hildenbrand -RH-Acked-by: Cornelia Huck -RH-Acked-by: Jens Freimann - -From: Cornelia Huck - -Update headers against 4.15-rc9. - -Signed-off-by: Cornelia Huck -(cherry picked from commit 9cbb636270b4df6f0a548e5c34b895330db5df8b) -Signed-off-by: Miroslav Rezanina - -Conflicts: - include/standard-headers/asm-s390/virtio-ccw.h - linux-headers/linux/kvm.h - (simple conflicts since commit dd8739669f95b3065 was missing) - -Signed-off-by: Thomas Huth ---- - include/standard-headers/asm-s390/virtio-ccw.h | 5 +---- - linux-headers/asm-powerpc/kvm.h | 25 +++++++++++++++++++++++++ - linux-headers/asm-s390/kvm.h | 9 ++++----- - linux-headers/asm-s390/kvm_para.h | 4 ---- - linux-headers/linux/kvm.h | 9 +++++++-- - 5 files changed, 37 insertions(+), 15 deletions(-) - -diff --git a/include/standard-headers/asm-s390/virtio-ccw.h b/include/standard-headers/asm-s390/virtio-ccw.h -index a9a4ebf..2b605f7 100644 ---- a/include/standard-headers/asm-s390/virtio-ccw.h -+++ b/include/standard-headers/asm-s390/virtio-ccw.h -@@ -1,12 +1,9 @@ -+/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ - /* - * Definitions for virtio-ccw devices. - * - * Copyright IBM Corp. 2013 - * -- * This program is free software; you can redistribute it and/or modify -- * it under the terms of the GNU General Public License (version 2 only) -- * as published by the Free Software Foundation. -- * - * Author(s): Cornelia Huck - */ - #ifndef __KVM_VIRTIO_CCW_H -diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h -index 8cf8f0c..a1cb407 100644 ---- a/linux-headers/asm-powerpc/kvm.h -+++ b/linux-headers/asm-powerpc/kvm.h -@@ -442,6 +442,31 @@ struct kvm_ppc_rmmu_info { - __u32 ap_encodings[8]; - }; - -+/* For KVM_PPC_GET_CPU_CHAR */ -+struct kvm_ppc_cpu_char { -+ __u64 character; /* characteristics of the CPU */ -+ __u64 behaviour; /* recommended software behaviour */ -+ __u64 character_mask; /* valid bits in character */ -+ __u64 behaviour_mask; /* valid bits in behaviour */ -+}; -+ -+/* -+ * Values for character and character_mask. -+ * These are identical to the values used by H_GET_CPU_CHARACTERISTICS. -+ */ -+#define KVM_PPC_CPU_CHAR_SPEC_BAR_ORI31 (1ULL << 63) -+#define KVM_PPC_CPU_CHAR_BCCTRL_SERIALISED (1ULL << 62) -+#define KVM_PPC_CPU_CHAR_L1D_FLUSH_ORI30 (1ULL << 61) -+#define KVM_PPC_CPU_CHAR_L1D_FLUSH_TRIG2 (1ULL << 60) -+#define KVM_PPC_CPU_CHAR_L1D_THREAD_PRIV (1ULL << 59) -+#define KVM_PPC_CPU_CHAR_BR_HINT_HONOURED (1ULL << 58) -+#define KVM_PPC_CPU_CHAR_MTTRIG_THR_RECONF (1ULL << 57) -+#define KVM_PPC_CPU_CHAR_COUNT_CACHE_DIS (1ULL << 56) -+ -+#define KVM_PPC_CPU_BEHAV_FAVOUR_SECURITY (1ULL << 63) -+#define KVM_PPC_CPU_BEHAV_L1D_FLUSH_PR (1ULL << 62) -+#define KVM_PPC_CPU_BEHAV_BNDS_CHK_SPEC_BAR (1ULL << 61) -+ - /* Per-vcpu XICS interrupt controller state */ - #define KVM_REG_PPC_ICP_STATE (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x8c) - -diff --git a/linux-headers/asm-s390/kvm.h b/linux-headers/asm-s390/kvm.h -index 8387d71..08ee46a 100644 ---- a/linux-headers/asm-s390/kvm.h -+++ b/linux-headers/asm-s390/kvm.h -@@ -5,10 +5,6 @@ - * - * Copyright IBM Corp. 2008 - * -- * This program is free software; you can redistribute it and/or modify -- * it under the terms of the GNU General Public License (version 2 only) -- * as published by the Free Software Foundation. -- * - * Author(s): Carsten Otte - * Christian Borntraeger - */ -@@ -221,6 +217,7 @@ struct kvm_guest_debug_arch { - #define KVM_SYNC_RICCB (1UL << 7) - #define KVM_SYNC_FPRS (1UL << 8) - #define KVM_SYNC_GSCB (1UL << 9) -+#define KVM_SYNC_BPBC (1UL << 10) - /* length and alignment of the sdnx as a power of two */ - #define SDNXC 8 - #define SDNXL (1UL << SDNXC) -@@ -244,7 +241,9 @@ struct kvm_sync_regs { - }; - __u8 reserved[512]; /* for future vector expansion */ - __u32 fpc; /* valid on KVM_SYNC_VRS or KVM_SYNC_FPRS */ -- __u8 padding1[52]; /* riccb needs to be 64byte aligned */ -+ __u8 bpbc : 1; /* bp mode */ -+ __u8 reserved2 : 7; -+ __u8 padding1[51]; /* riccb needs to be 64byte aligned */ - __u8 riccb[64]; /* runtime instrumentation controls block */ - __u8 padding2[192]; /* sdnx needs to be 256byte aligned */ - union { -diff --git a/linux-headers/asm-s390/kvm_para.h b/linux-headers/asm-s390/kvm_para.h -index ff1f4e7..1a81ec9 100644 ---- a/linux-headers/asm-s390/kvm_para.h -+++ b/linux-headers/asm-s390/kvm_para.h -@@ -3,9 +3,5 @@ - * - * Copyright IBM Corp. 2008 - * -- * This program is free software; you can redistribute it and/or modify -- * it under the terms of the GNU General Public License (version 2 only) -- * as published by the Free Software Foundation. -- * - * Author(s): Christian Borntraeger - */ -diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h -index 7971a4f..fabd075 100644 ---- a/linux-headers/linux/kvm.h -+++ b/linux-headers/linux/kvm.h -@@ -629,9 +629,9 @@ struct kvm_s390_irq { - - struct kvm_s390_irq_state { - __u64 buf; -- __u32 flags; -+ __u32 flags; /* will stay unused for compatibility reasons */ - __u32 len; -- __u32 reserved[4]; -+ __u32 reserved[4]; /* will stay unused for compatibility reasons */ - }; - - /* for KVM_SET_GUEST_DEBUG */ -@@ -929,6 +929,9 @@ struct kvm_ppc_resize_hpt { - #define KVM_CAP_PPC_SMT_POSSIBLE 147 - #define KVM_CAP_HYPERV_SYNIC2 148 - #define KVM_CAP_HYPERV_VP_INDEX 149 -+#define KVM_CAP_S390_AIS_MIGRATION 150 -+#define KVM_CAP_PPC_GET_CPU_CHAR 151 -+#define KVM_CAP_S390_BPB 152 - - #ifdef KVM_CAP_IRQ_ROUTING - -@@ -1258,6 +1261,8 @@ struct kvm_s390_ucas_mapping { - #define KVM_PPC_CONFIGURE_V3_MMU _IOW(KVMIO, 0xaf, struct kvm_ppc_mmuv3_cfg) - /* Available with KVM_CAP_PPC_RADIX_MMU */ - #define KVM_PPC_GET_RMMU_INFO _IOW(KVMIO, 0xb0, struct kvm_ppc_rmmu_info) -+/* Available with KVM_CAP_PPC_GET_CPU_CHAR */ -+#define KVM_PPC_GET_CPU_CHAR _IOR(KVMIO, 0xb1, struct kvm_ppc_cpu_char) - - /* ioctl for vm fd */ - #define KVM_CREATE_DEVICE _IOWR(KVMIO, 0xe0, struct kvm_create_device) --- -1.8.3.1 - diff --git a/SOURCES/kvm-machine-compat-pci_bridge-shpc-always-enable.patch b/SOURCES/kvm-machine-compat-pci_bridge-shpc-always-enable.patch deleted file mode 100644 index cecc604..0000000 --- a/SOURCES/kvm-machine-compat-pci_bridge-shpc-always-enable.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 229441f111066fb4340ac6ae49cf26db2f81b884 Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Fri, 3 Nov 2017 13:03:42 +0100 -Subject: [PATCH 5/9] machine compat: pci_bridge/shpc always enable - -RH-Author: Dr. David Alan Gilbert -Message-id: <20171103130342.9839-1-dgilbert@redhat.com> -Patchwork-id: 77494 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 1/1] machine compat: pci_bridge/shpc always enable -Bugzilla: 1508271 -RH-Acked-by: Marcel Apfelbaum -RH-Acked-by: Laurent Vivier -RH-Acked-by: Miroslav Rezanina - -From: "Dr. David Alan Gilbert" - -The 'shpc' property on bridges has changed its default back and -forward. -Upstream it's off on 2.9 machine types but on for all the others -(upstream dc0ae767 turned it off, 2fa35662 reverted it). -Downstream we always had it on, even for 7.4 that was derived from -2.9. -Unfortunately we imported the 2.9 entry that turned it off, which -breaks migration. Remove that entry, shpc is now on again for -all our machine types. - -Signed-off-by: Dr. David Alan Gilbert -Signed-off-by: Miroslav Rezanina ---- - include/hw/compat.h | 4 ---- - 1 file changed, 4 deletions(-) - -diff --git a/include/hw/compat.h b/include/hw/compat.h -index 85c6cbe..7a2a4a6 100644 ---- a/include/hw/compat.h -+++ b/include/hw/compat.h -@@ -419,10 +419,6 @@ - */ - #define HW_COMPAT_RHEL7_4 \ - { /* HW_COMPAT_RHEL7_4 */ \ -- .driver = "pci-bridge",\ -- .property = "shpc",\ -- .value = "off",\ -- },{ /* HW_COMPAT_RHEL7_4 */ \ - .driver = "intel-iommu",\ - .property = "pt",\ - .value = "off",\ --- -1.8.3.1 - diff --git a/SOURCES/kvm-main-loop-drop-spin_counter.patch b/SOURCES/kvm-main-loop-drop-spin_counter.patch new file mode 100644 index 0000000..ce519f3 --- /dev/null +++ b/SOURCES/kvm-main-loop-drop-spin_counter.patch @@ -0,0 +1,106 @@ +From d215f56d789b8d6a2cb27501c89a516d213b1af3 Mon Sep 17 00:00:00 2001 +From: Jeffrey Cody +Date: Wed, 20 Jun 2018 17:44:46 +0200 +Subject: [PATCH 51/54] main-loop: drop spin_counter + +RH-Author: Jeffrey Cody +Message-id: <835200bb37bc622f0f6f9c471c809a1b73a08482.1529516334.git.jcody@redhat.com> +Patchwork-id: 80906 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v2 1/1] main-loop: drop spin_counter +Bugzilla: 1168213 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Markus Armbruster + +From: Stefan Hajnoczi + +Commit d759c951f3287fad04210a52f2dc93f94cf58c7f ("replay: push +replay_mutex_lock up the call tree") removed the !timeout lock +optimization in the main loop. + +The idea of the optimization was to avoid ping-pongs between threads by +keeping the Big QEMU Lock held across non-blocking (!timeout) main loop +iterations. + +A warning is printed when the main loop spins without releasing BQL for +long periods of time. These warnings were supposed to aid debugging but +in practice they just alarm users. They are considered noise because +the cause of spinning is not shown and is hard to find. + +Now that the lock optimization has been removed, there is no danger of +hogging the BQL. Drop the spin counter and the infamous warning. + +Signed-off-by: Stefan Hajnoczi +Reviewed-by: Jeff Cody +(cherry picked from commit 21891a5a3011608845b5d7f1f9cce60cdc2bcc62) +Note: The original patch series from Stefan makes note that the + patch can be dropped because the lock optimization changed + upstream. + + However, even without that optimization change upstream, this + warning / debug message is not very useful, and is just noise that + does not aid in debugging. Go ahead and remove it anyway. +Signed-off-by: Jeff Cody + +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/common.filter | 1 - + util/main-loop.c | 25 ------------------------- + 2 files changed, 26 deletions(-) + +diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter +index c5f4bcf..7acb454 100644 +--- a/tests/qemu-iotests/common.filter ++++ b/tests/qemu-iotests/common.filter +@@ -77,7 +77,6 @@ _filter_qemu() + { + sed -e "s#\\(^\\|(qemu) \\)$(basename $QEMU_PROG):#\1QEMU_PROG:#" \ + -e 's#^QEMU [0-9]\+\.[0-9]\+\.[0-9]\+ monitor#QEMU X.Y.Z monitor#' \ +- -e '/main-loop: WARNING: I\/O thread spun for [0-9]\+ iterations/d' \ + -e $'s#\r##' # QEMU monitor uses \r\n line endings + } + +diff --git a/util/main-loop.c b/util/main-loop.c +index 992f9b0..affe040 100644 +--- a/util/main-loop.c ++++ b/util/main-loop.c +@@ -222,36 +222,11 @@ static int os_host_main_loop_wait(int64_t timeout) + { + GMainContext *context = g_main_context_default(); + int ret; +- static int spin_counter; + + g_main_context_acquire(context); + + glib_pollfds_fill(&timeout); + +- /* If the I/O thread is very busy or we are incorrectly busy waiting in +- * the I/O thread, this can lead to starvation of the BQL such that the +- * VCPU threads never run. To make sure we can detect the later case, +- * print a message to the screen. If we run into this condition, create +- * a fake timeout in order to give the VCPU threads a chance to run. +- */ +- if (!timeout && (spin_counter > MAX_MAIN_LOOP_SPIN)) { +- static bool notified; +- +- if (!notified && !qtest_enabled() && !qtest_driver()) { +- warn_report("I/O thread spun for %d iterations", +- MAX_MAIN_LOOP_SPIN); +- notified = true; +- } +- +- timeout = SCALE_MS; +- } +- +- +- if (timeout) { +- spin_counter = 0; +- } else { +- spin_counter++; +- } + qemu_mutex_unlock_iothread(); + replay_mutex_unlock(); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-mem-nvdimm-ensure-write-persistence-to-PMEM-in-label.patch b/SOURCES/kvm-mem-nvdimm-ensure-write-persistence-to-PMEM-in-label.patch new file mode 100644 index 0000000..b5b809f --- /dev/null +++ b/SOURCES/kvm-mem-nvdimm-ensure-write-persistence-to-PMEM-in-label.patch @@ -0,0 +1,108 @@ +From 22200b24c1f26602467d47738b4bb3e6da6c4f86 Mon Sep 17 00:00:00 2001 +From: "plai@redhat.com" +Date: Fri, 31 Aug 2018 16:25:57 +0200 +Subject: [PATCH 15/29] mem/nvdimm: ensure write persistence to PMEM in label + emulation + +RH-Author: plai@redhat.com +Message-id: <1535732759-22481-8-git-send-email-plai@redhat.com> +Patchwork-id: 82013 +O-Subject: [RHEL7.6 PATCH BZ 1539280 7/9] mem/nvdimm: ensure write persistence to PMEM in label emulation +Bugzilla: 1539280 +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Pankaj Gupta +RH-Acked-by: Miroslav Rezanina + +From: Junyan He + +Guest writes to vNVDIMM labels are intercepted and performed on the +backend by QEMU. When the backend is a real persistent memort, QEMU +needs to take proper operations to ensure its write persistence on the +persistent memory. Otherwise, a host power failure may result in the +loss of guest label configurations. + +Signed-off-by: Haozhong Zhang +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Igor Mammedov +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Richard Henderson +(cherry picked from commit faf8a13d80de98b43342a7ec9878b4fd76b18327) +Signed-off-by: Paul Lai +Signed-off-by: Miroslav Rezanina +--- + hw/mem/nvdimm.c | 9 ++++++++- + include/qemu/pmem.h | 30 ++++++++++++++++++++++++++++++ + 2 files changed, 38 insertions(+), 1 deletion(-) + create mode 100644 include/qemu/pmem.h + +diff --git a/hw/mem/nvdimm.c b/hw/mem/nvdimm.c +index acb656b..0c962fd 100644 +--- a/hw/mem/nvdimm.c ++++ b/hw/mem/nvdimm.c +@@ -23,6 +23,7 @@ + */ + + #include "qemu/osdep.h" ++#include "qemu/pmem.h" + #include "qapi/error.h" + #include "qapi/visitor.h" + #include "hw/mem/nvdimm.h" +@@ -155,11 +156,17 @@ static void nvdimm_write_label_data(NVDIMMDevice *nvdimm, const void *buf, + { + MemoryRegion *mr; + PCDIMMDevice *dimm = PC_DIMM(nvdimm); ++ bool is_pmem = object_property_get_bool(OBJECT(dimm->hostmem), ++ "pmem", NULL); + uint64_t backend_offset; + + nvdimm_validate_rw_label_data(nvdimm, size, offset); + +- memcpy(nvdimm->label_data + offset, buf, size); ++ if (!is_pmem) { ++ memcpy(nvdimm->label_data + offset, buf, size); ++ } else { ++ pmem_memcpy_persist(nvdimm->label_data + offset, buf, size); ++ } + + mr = host_memory_backend_get_memory(dimm->hostmem, &error_abort); + backend_offset = memory_region_size(mr) - nvdimm->label_size + offset; +diff --git a/include/qemu/pmem.h b/include/qemu/pmem.h +new file mode 100644 +index 0000000..ebdb070 +--- /dev/null ++++ b/include/qemu/pmem.h +@@ -0,0 +1,30 @@ ++/* ++ * QEMU header file for libpmem. ++ * ++ * Copyright (c) 2018 Intel Corporation. ++ * ++ * Author: Haozhong Zhang ++ * ++ * 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 QEMU_PMEM_H ++#define QEMU_PMEM_H ++ ++#ifdef CONFIG_LIBPMEM ++#include ++#else /* !CONFIG_LIBPMEM */ ++ ++static inline void * ++pmem_memcpy_persist(void *pmemdest, const void *src, size_t len) ++{ ++ /* If 'pmem' option is 'on', we should always have libpmem support, ++ or qemu will report a error and exit, never come here. */ ++ g_assert_not_reached(); ++ return NULL; ++} ++ ++#endif /* CONFIG_LIBPMEM */ ++ ++#endif /* !QEMU_PMEM_H */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-memory-Alloc-dispatch-tree-where-topology-is-generar.patch b/SOURCES/kvm-memory-Alloc-dispatch-tree-where-topology-is-generar.patch deleted file mode 100644 index c5b9f77..0000000 --- a/SOURCES/kvm-memory-Alloc-dispatch-tree-where-topology-is-generar.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 3ff6f640c89c152317214aecb7cb8071f60164d5 Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Thu, 16 Nov 2017 03:07:23 +0100 -Subject: [PATCH 19/30] memory: Alloc dispatch tree where topology is generared - -RH-Author: David Gibson -Message-id: <20171116030732.8560-14-dgibson@redhat.com> -Patchwork-id: 77704 -O-Subject: [PATCH 13/22] memory: Alloc dispatch tree where topology is generared -Bugzilla: 1481593 -RH-Acked-by: Thomas Huth -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Eduardo Habkost -RH-Acked-by: Laurent Vivier - -From: Alexey Kardashevskiy - -This is to make next patches simpler. - -Signed-off-by: Alexey Kardashevskiy -Message-Id: <20170921085110.25598-11-aik@ozlabs.ru> -Signed-off-by: Paolo Bonzini -(cherry picked from commit 9bf561e36cf8fed9565011a19ba9ea0100e1811e) - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - memory.c | 18 +++++++++--------- - 1 file changed, 9 insertions(+), 9 deletions(-) - -diff --git a/memory.c b/memory.c -index 7972235..8034520 100644 ---- a/memory.c -+++ b/memory.c -@@ -742,6 +742,7 @@ static MemoryRegion *memory_region_get_flatview_root(MemoryRegion *mr) - /* Render a memory topology into a list of disjoint absolute ranges. */ - static FlatView *generate_memory_topology(MemoryRegion *mr) - { -+ int i; - FlatView *view; - - view = flatview_new(mr); -@@ -752,6 +753,14 @@ static FlatView *generate_memory_topology(MemoryRegion *mr) - } - flatview_simplify(view); - -+ view->dispatch = address_space_dispatch_new(view); -+ for (i = 0; i < view->nr; i++) { -+ MemoryRegionSection mrs = -+ section_from_flat_range(&view->ranges[i], view); -+ flatview_add_to_dispatch(view, &mrs); -+ } -+ address_space_dispatch_compact(view->dispatch); -+ - return view; - } - -@@ -925,15 +934,6 @@ static void address_space_update_topology(AddressSpace *as) - FlatView *old_view = address_space_get_flatview(as); - MemoryRegion *physmr = memory_region_get_flatview_root(old_view->root); - FlatView *new_view = generate_memory_topology(physmr); -- int i; -- -- new_view->dispatch = address_space_dispatch_new(new_view); -- for (i = 0; i < new_view->nr; i++) { -- MemoryRegionSection mrs = -- section_from_flat_range(&new_view->ranges[i], new_view); -- flatview_add_to_dispatch(new_view, &mrs); -- } -- address_space_dispatch_compact(new_view->dispatch); - - if (!QTAILQ_EMPTY(&as->listeners)) { - address_space_update_topology_pass(as, old_view, new_view, false); --- -1.8.3.1 - diff --git a/SOURCES/kvm-memory-Cleanup-after-switching-to-FlatView.patch b/SOURCES/kvm-memory-Cleanup-after-switching-to-FlatView.patch deleted file mode 100644 index 2affa44..0000000 --- a/SOURCES/kvm-memory-Cleanup-after-switching-to-FlatView.patch +++ /dev/null @@ -1,98 +0,0 @@ -From f11d0111c641b1ea0c961f1faee7f9682c4f272c Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Thu, 16 Nov 2017 03:07:20 +0100 -Subject: [PATCH 16/30] memory: Cleanup after switching to FlatView - -RH-Author: David Gibson -Message-id: <20171116030732.8560-11-dgibson@redhat.com> -Patchwork-id: 77701 -O-Subject: [PATCH 10/22] memory: Cleanup after switching to FlatView -Bugzilla: 1481593 -RH-Acked-by: Thomas Huth -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Eduardo Habkost -RH-Acked-by: Laurent Vivier - -From: Alexey Kardashevskiy - -We store AddressSpaceDispatch* in FlatView anyway so there is no need -to carry it from mem_add() to register_subpage/register_multipage. - -This should cause no behavioural change. - -Signed-off-by: Alexey Kardashevskiy -Message-Id: <20170921085110.25598-8-aik@ozlabs.ru> -Signed-off-by: Paolo Bonzini -(cherry picked from commit 9950322a593ff900a860fb52938159461798a831) - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - exec.c | 16 ++++++++-------- - 1 file changed, 8 insertions(+), 8 deletions(-) - -diff --git a/exec.c b/exec.c -index 0eedeb2..d1d8486 100644 ---- a/exec.c -+++ b/exec.c -@@ -1314,9 +1314,9 @@ static void phys_sections_free(PhysPageMap *map) - g_free(map->nodes); - } - --static void register_subpage(FlatView *fv, AddressSpaceDispatch *d, -- MemoryRegionSection *section) -+static void register_subpage(FlatView *fv, MemoryRegionSection *section) - { -+ AddressSpaceDispatch *d = flatview_to_dispatch(fv); - subpage_t *subpage; - hwaddr base = section->offset_within_address_space - & TARGET_PAGE_MASK; -@@ -1345,9 +1345,10 @@ static void register_subpage(FlatView *fv, AddressSpaceDispatch *d, - } - - --static void register_multipage(AddressSpaceDispatch *d, -+static void register_multipage(FlatView *fv, - MemoryRegionSection *section) - { -+ AddressSpaceDispatch *d = flatview_to_dispatch(fv); - hwaddr start_addr = section->offset_within_address_space; - uint16_t section_index = phys_section_add(&d->map, section); - uint64_t num_pages = int128_get64(int128_rshift(section->size, -@@ -1359,7 +1360,6 @@ static void register_multipage(AddressSpaceDispatch *d, - - void mem_add(FlatView *fv, MemoryRegionSection *section) - { -- AddressSpaceDispatch *d = flatview_to_dispatch(fv); - MemoryRegionSection now = *section, remain = *section; - Int128 page_size = int128_make64(TARGET_PAGE_SIZE); - -@@ -1368,7 +1368,7 @@ void mem_add(FlatView *fv, MemoryRegionSection *section) - - now.offset_within_address_space; - - now.size = int128_min(int128_make64(left), now.size); -- register_subpage(fv, d, &now); -+ register_subpage(fv, &now); - } else { - now.size = int128_zero(); - } -@@ -1378,13 +1378,13 @@ void mem_add(FlatView *fv, MemoryRegionSection *section) - remain.offset_within_region += int128_get64(now.size); - now = remain; - if (int128_lt(remain.size, page_size)) { -- register_subpage(fv, d, &now); -+ register_subpage(fv, &now); - } else if (remain.offset_within_address_space & ~TARGET_PAGE_MASK) { - now.size = page_size; -- register_subpage(fv, d, &now); -+ register_subpage(fv, &now); - } else { - now.size = int128_and(now.size, int128_neg(page_size)); -- register_multipage(d, &now); -+ register_multipage(fv, &now); - } - } - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-memory-Create-FlatView-directly.patch b/SOURCES/kvm-memory-Create-FlatView-directly.patch deleted file mode 100644 index ab73cde..0000000 --- a/SOURCES/kvm-memory-Create-FlatView-directly.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 61fad0cef2ed50a900717d11aab2e5e0ef121894 Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Thu, 16 Nov 2017 03:07:29 +0100 -Subject: [PATCH 25/30] memory: Create FlatView directly - -RH-Author: David Gibson -Message-id: <20171116030732.8560-20-dgibson@redhat.com> -Patchwork-id: 77703 -O-Subject: [PATCH 19/22] memory: Create FlatView directly -Bugzilla: 1481593 -RH-Acked-by: Thomas Huth -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Eduardo Habkost -RH-Acked-by: Laurent Vivier - -From: Alexey Kardashevskiy - -This avoids usual memory_region_transaction_commit() which rebuilds -all FVs. - -On POWER8 with 255 CPUs, 255 virtio-net, 40 PCI bridges guest this brings -down the boot time from 25s to 20s and reduces the amount of temporary FVs -allocated during machine constructon (~800000 -> ~640000) and amount of -temporary dispatch trees (~370000 -> ~300000), the total memory footprint -goes down (18G -> 17G). - -Signed-off-by: Alexey Kardashevskiy -Message-Id: <20170921085110.25598-18-aik@ozlabs.ru> -Signed-off-by: Paolo Bonzini -(cherry picked from commit 202fc01b05572ecb258fdf4c5bd56cf6de8140c7) - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - memory.c | 16 +++++++++++++--- - 1 file changed, 13 insertions(+), 3 deletions(-) - -diff --git a/memory.c b/memory.c -index 00d5788..93b4221 100644 ---- a/memory.c -+++ b/memory.c -@@ -1009,6 +1009,17 @@ static void address_space_set_flatview(AddressSpace *as) - } - } - -+static void address_space_update_topology(AddressSpace *as) -+{ -+ MemoryRegion *physmr = memory_region_get_flatview_root(as->root); -+ -+ flatviews_init(); -+ if (!g_hash_table_lookup(flat_views, physmr)) { -+ generate_memory_topology(physmr); -+ } -+ address_space_set_flatview(as); -+} -+ - void memory_region_transaction_begin(void) - { - qemu_flush_coalesced_mmio_buffer(); -@@ -2720,7 +2731,6 @@ void memory_region_invalidate_mmio_ptr(MemoryRegion *mr, hwaddr offset, - void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name) - { - memory_region_ref(root); -- memory_region_transaction_begin(); - as->root = root; - as->current_map = NULL; - as->ioeventfd_nb = 0; -@@ -2728,8 +2738,8 @@ void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name) - QTAILQ_INIT(&as->listeners); - QTAILQ_INSERT_TAIL(&address_spaces, as, address_spaces_link); - as->name = g_strdup(name ? name : "anonymous"); -- memory_region_update_pending |= root->enabled; -- memory_region_transaction_commit(); -+ address_space_update_topology(as); -+ address_space_update_ioeventfds(as); - } - - static void do_address_space_destroy(AddressSpace *as) --- -1.8.3.1 - diff --git a/SOURCES/kvm-memory-Do-not-allocate-FlatView-in-address_space_ini.patch b/SOURCES/kvm-memory-Do-not-allocate-FlatView-in-address_space_ini.patch deleted file mode 100644 index 0948209..0000000 --- a/SOURCES/kvm-memory-Do-not-allocate-FlatView-in-address_space_ini.patch +++ /dev/null @@ -1,100 +0,0 @@ -From 5bfc2be91ba382cf0c0353794ff9289cb9b064de Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Thu, 16 Nov 2017 03:07:26 +0100 -Subject: [PATCH 22/30] memory: Do not allocate FlatView in address_space_init - -RH-Author: David Gibson -Message-id: <20171116030732.8560-17-dgibson@redhat.com> -Patchwork-id: 77705 -O-Subject: [PATCH 16/22] memory: Do not allocate FlatView in address_space_init -Bugzilla: 1481593 -RH-Acked-by: Thomas Huth -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Eduardo Habkost -RH-Acked-by: Laurent Vivier - -From: Alexey Kardashevskiy - -This creates a new AS object without any FlatView as -memory_region_transaction_commit() may want to reuse the empty FV. - -Signed-off-by: Alexey Kardashevskiy -Message-Id: <20170921085110.25598-14-aik@ozlabs.ru> -Signed-off-by: Paolo Bonzini -(cherry picked from commit 67ace39b253ed5ae465275bc870f7e495547658b) - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - memory.c | 29 +++++++++++++++++++++++------ - 1 file changed, 23 insertions(+), 6 deletions(-) - -diff --git a/memory.c b/memory.c -index f0c8642..6914d87 100644 ---- a/memory.c -+++ b/memory.c -@@ -966,22 +966,37 @@ static void flatviews_reset(void) - - static void address_space_set_flatview(AddressSpace *as) - { -- FlatView *old_view = address_space_get_flatview(as); -+ FlatView *old_view = address_space_to_flatview(as); - MemoryRegion *physmr = memory_region_get_flatview_root(as->root); - FlatView *new_view = g_hash_table_lookup(flat_views, physmr); - - assert(new_view); - -+ if (old_view == new_view) { -+ return; -+ } -+ -+ if (old_view) { -+ flatview_ref(old_view); -+ } -+ - flatview_ref(new_view); - - if (!QTAILQ_EMPTY(&as->listeners)) { -- address_space_update_topology_pass(as, old_view, new_view, false); -- address_space_update_topology_pass(as, old_view, new_view, true); -+ FlatView tmpview = { .nr = 0 }, *old_view2 = old_view; -+ -+ if (!old_view2) { -+ old_view2 = &tmpview; -+ } -+ address_space_update_topology_pass(as, old_view2, new_view, false); -+ address_space_update_topology_pass(as, old_view2, new_view, true); - } - - /* Writes are protected by the BQL. */ - atomic_rcu_set(&as->current_map, new_view); -- flatview_unref(old_view); -+ if (old_view) { -+ flatview_unref(old_view); -+ } - - /* Note that all the old MemoryRegions are still alive up to this - * point. This relieves most MemoryListeners from the need to -@@ -989,7 +1004,9 @@ static void address_space_set_flatview(AddressSpace *as) - * outside the iothread mutex, in which case precise reference - * counting is necessary. - */ -- flatview_unref(old_view); -+ if (old_view) { -+ flatview_unref(old_view); -+ } - } - - void memory_region_transaction_begin(void) -@@ -2707,7 +2724,7 @@ void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name) - as->ref_count = 1; - as->root = root; - as->malloced = false; -- as->current_map = flatview_new(root); -+ as->current_map = NULL; - as->ioeventfd_nb = 0; - as->ioeventfds = NULL; - QTAILQ_INIT(&as->listeners); --- -1.8.3.1 - diff --git a/SOURCES/kvm-memory-Get-rid-of-address_space_init_shareable.patch b/SOURCES/kvm-memory-Get-rid-of-address_space_init_shareable.patch deleted file mode 100644 index 4a5222c..0000000 --- a/SOURCES/kvm-memory-Get-rid-of-address_space_init_shareable.patch +++ /dev/null @@ -1,264 +0,0 @@ -From 9695c6db4ca09b6bebcffcccfd37aae5c1845021 Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Thu, 16 Nov 2017 03:07:28 +0100 -Subject: [PATCH 24/30] memory: Get rid of address_space_init_shareable - -RH-Author: David Gibson -Message-id: <20171116030732.8560-19-dgibson@redhat.com> -Patchwork-id: 77710 -O-Subject: [PATCH 18/22] memory: Get rid of address_space_init_shareable -Bugzilla: 1481593 -RH-Acked-by: Thomas Huth -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Eduardo Habkost -RH-Acked-by: Laurent Vivier - -From: Alexey Kardashevskiy - -Since FlatViews are shared now and ASes not, this gets rid of -address_space_init_shareable(). - -This should cause no behavioural change. - -Signed-off-by: Alexey Kardashevskiy -Message-Id: <20170921085110.25598-17-aik@ozlabs.ru> -Signed-off-by: Paolo Bonzini -(cherry picked from commit b516572f31c0ea0937cd9d11d9bd72dd83809886) -Signed-off-by: Miroslav Rezanina - -Conflicts: - target/arm/cpu.c - -Conflicts because we don't have 1d2091bc75a "target/arm: Register -second AddressSpace for secure v8M CPUs" downstream. - -Signed-off-by: David Gibson ---- - cpus.c | 5 +++-- - hw/arm/armv7m.c | 9 ++++----- - include/exec/memory.h | 19 ------------------- - include/hw/arm/armv7m.h | 2 +- - memory.c | 21 --------------------- - target/arm/cpu.c | 15 ++++++++------- - target/i386/cpu.c | 5 +++-- - 7 files changed, 19 insertions(+), 57 deletions(-) - -diff --git a/cpus.c b/cpus.c -index 9bed61e..c9a6240 100644 ---- a/cpus.c -+++ b/cpus.c -@@ -1764,8 +1764,9 @@ void qemu_init_vcpu(CPUState *cpu) - /* If the target cpu hasn't set up any address spaces itself, - * give it the default one. - */ -- AddressSpace *as = address_space_init_shareable(cpu->memory, -- "cpu-memory"); -+ AddressSpace *as = g_new0(AddressSpace, 1); -+ -+ address_space_init(as, cpu->memory, "cpu-memory"); - cpu->num_ases = 1; - cpu_address_space_init(cpu, as, 0); - } -diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c -index c8a11f2..475a88f 100644 ---- a/hw/arm/armv7m.c -+++ b/hw/arm/armv7m.c -@@ -41,7 +41,7 @@ static MemTxResult bitband_read(void *opaque, hwaddr offset, - - /* Find address in underlying memory and round down to multiple of size */ - addr = bitband_addr(s, offset) & (-size); -- res = address_space_read(s->source_as, addr, attrs, buf, size); -+ res = address_space_read(&s->source_as, addr, attrs, buf, size); - if (res) { - return res; - } -@@ -66,7 +66,7 @@ static MemTxResult bitband_write(void *opaque, hwaddr offset, uint64_t value, - - /* Find address in underlying memory and round down to multiple of size */ - addr = bitband_addr(s, offset) & (-size); -- res = address_space_read(s->source_as, addr, attrs, buf, size); -+ res = address_space_read(&s->source_as, addr, attrs, buf, size); - if (res) { - return res; - } -@@ -79,7 +79,7 @@ static MemTxResult bitband_write(void *opaque, hwaddr offset, uint64_t value, - } else { - buf[bitpos >> 3] &= ~bit; - } -- return address_space_write(s->source_as, addr, attrs, buf, size); -+ return address_space_write(&s->source_as, addr, attrs, buf, size); - } - - static const MemoryRegionOps bitband_ops = { -@@ -117,8 +117,7 @@ static void bitband_realize(DeviceState *dev, Error **errp) - return; - } - -- s->source_as = address_space_init_shareable(s->source_memory, -- "bitband-source"); -+ address_space_init(&s->source_as, s->source_memory, "bitband-source"); - } - - /* Board init. */ -diff --git a/include/exec/memory.h b/include/exec/memory.h -index 157eae6..8d772b9 100644 ---- a/include/exec/memory.h -+++ b/include/exec/memory.h -@@ -319,8 +319,6 @@ struct AddressSpace { - struct rcu_head rcu; - char *name; - MemoryRegion *root; -- int ref_count; -- bool malloced; - - /* Accessed via RCU. */ - struct FlatView *current_map; -@@ -1596,23 +1594,6 @@ MemTxResult memory_region_dispatch_write(MemoryRegion *mr, - void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name); - - /** -- * address_space_init_shareable: return an address space for a memory region, -- * creating it if it does not already exist -- * -- * @root: a #MemoryRegion that routes addresses for the address space -- * @name: an address space name. The name is only used for debugging -- * output. -- * -- * This function will return a pointer to an existing AddressSpace -- * which was initialized with the specified MemoryRegion, or it will -- * create and initialize one if it does not already exist. The ASes -- * are reference-counted, so the memory will be freed automatically -- * when the AddressSpace is destroyed via address_space_destroy. -- */ --AddressSpace *address_space_init_shareable(MemoryRegion *root, -- const char *name); -- --/** - * address_space_destroy: destroy an address space - * - * Releases all resources associated with an address space. After an address space -diff --git a/include/hw/arm/armv7m.h b/include/hw/arm/armv7m.h -index a9b3f2a..dba77df 100644 ---- a/include/hw/arm/armv7m.h -+++ b/include/hw/arm/armv7m.h -@@ -21,7 +21,7 @@ typedef struct { - SysBusDevice parent_obj; - /*< public >*/ - -- AddressSpace *source_as; -+ AddressSpace source_as; - MemoryRegion iomem; - uint32_t base; - MemoryRegion *source_memory; -diff --git a/memory.c b/memory.c -index 25a8bf2..00d5788 100644 ---- a/memory.c -+++ b/memory.c -@@ -2721,9 +2721,7 @@ void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name) - { - memory_region_ref(root); - memory_region_transaction_begin(); -- as->ref_count = 1; - as->root = root; -- as->malloced = false; - as->current_map = NULL; - as->ioeventfd_nb = 0; - as->ioeventfds = NULL; -@@ -2736,37 +2734,18 @@ void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name) - - static void do_address_space_destroy(AddressSpace *as) - { -- bool do_free = as->malloced; -- - assert(QTAILQ_EMPTY(&as->listeners)); - - flatview_unref(as->current_map); - g_free(as->name); - g_free(as->ioeventfds); - memory_region_unref(as->root); -- if (do_free) { -- g_free(as); -- } --} -- --AddressSpace *address_space_init_shareable(MemoryRegion *root, const char *name) --{ -- AddressSpace *as; -- -- as = g_malloc0(sizeof *as); -- address_space_init(as, root, name); -- as->malloced = true; -- return as; - } - - void address_space_destroy(AddressSpace *as) - { - MemoryRegion *root = as->root; - -- as->ref_count--; -- if (as->ref_count) { -- return; -- } - /* Flush out anything from MemoryListeners listening in on this */ - memory_region_transaction_begin(); - as->root = NULL; -diff --git a/target/arm/cpu.c b/target/arm/cpu.c -index 3f90b7e..b6c8d93 100644 ---- a/target/arm/cpu.c -+++ b/target/arm/cpu.c -@@ -650,6 +650,9 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) - CPUARMState *env = &cpu->env; - int pagebits; - Error *local_err = NULL; -+#ifndef CONFIG_USER_ONLY -+ AddressSpace *as; -+#endif - - cpu_exec_realizefn(cs, &local_err); - if (local_err != NULL) { -@@ -835,19 +838,17 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) - } - - if (cpu->has_el3) { -- AddressSpace *as; -+ as = g_new0(AddressSpace, 1); - - if (!cpu->secure_memory) { - cpu->secure_memory = cs->memory; - } -- as = address_space_init_shareable(cpu->secure_memory, -- "cpu-secure-memory"); -+ address_space_init(as, cpu->secure_memory, "cpu-secure-memory"); - cpu_address_space_init(cs, as, ARMASIdx_S); - } -- cpu_address_space_init(cs, -- address_space_init_shareable(cs->memory, -- "cpu-memory"), -- ARMASIdx_NS); -+ as = g_new0(AddressSpace, 1); -+ address_space_init(as, cs->memory, "cpu-memory"); -+ cpu_address_space_init(cs, as, ARMASIdx_NS); - #endif - - qemu_init_vcpu(cs); -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 1cae8fe..ca95336 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -3772,10 +3772,11 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) - - #ifndef CONFIG_USER_ONLY - if (tcg_enabled()) { -- AddressSpace *as_normal = address_space_init_shareable(cs->memory, -- "cpu-memory"); -+ AddressSpace *as_normal = g_new0(AddressSpace, 1); - AddressSpace *as_smm = g_new(AddressSpace, 1); - -+ address_space_init(as_normal, cs->memory, "cpu-memory"); -+ - cpu->cpu_as_mem = g_new(MemoryRegion, 1); - cpu->cpu_as_root = g_new(MemoryRegion, 1); - --- -1.8.3.1 - diff --git a/SOURCES/kvm-memory-Move-AddressSpaceDispatch-from-AddressSpace-t.patch b/SOURCES/kvm-memory-Move-AddressSpaceDispatch-from-AddressSpace-t.patch deleted file mode 100644 index aed8d91..0000000 --- a/SOURCES/kvm-memory-Move-AddressSpaceDispatch-from-AddressSpace-t.patch +++ /dev/null @@ -1,296 +0,0 @@ -From 30acf078fced0fac523d4773fe06983d4cfce64d Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Thu, 16 Nov 2017 03:07:17 +0100 -Subject: [PATCH 13/30] memory: Move AddressSpaceDispatch from AddressSpace to - FlatView - -RH-Author: David Gibson -Message-id: <20171116030732.8560-8-dgibson@redhat.com> -Patchwork-id: 77697 -O-Subject: [PATCH 07/22] memory: Move AddressSpaceDispatch from AddressSpace to FlatView -Bugzilla: 1481593 -RH-Acked-by: Thomas Huth -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Eduardo Habkost -RH-Acked-by: Laurent Vivier - -From: Alexey Kardashevskiy - -As we are going to share FlatView's between AddressSpace's, -and AddressSpaceDispatch is a structure to perform quick lookup -in FlatView, this moves ASD to FlatView. - -After previosly open coded ASD rendering, we can also remove -as->next_dispatch as the new FlatView pointer is stored -on a stack and set to an AS atomically. - -flatview_destroy() is executed under RCU instead of -address_space_dispatch_free() now. - -This makes mem_begin/mem_commit to work with ASD and mem_add with FV -as later on mem_add will be taking FV as an argument anyway. - -This should cause no behavioural change. - -Signed-off-by: Alexey Kardashevskiy -Message-Id: <20170921085110.25598-5-aik@ozlabs.ru> -Signed-off-by: Paolo Bonzini -(cherry picked from commit 66a6df1dc6d5b28cc3e65db0d71683fbdddc6b62) -Signed-off-by: Miroslav Rezanina - -Conflicts: - exec.c - -Conflicts because we applied d5e5fafd "exec: add page_mask for -flatview_do_translate" out of order downstream. - -Signed-off-by: David Gibson ---- - exec.c | 41 +++++++++++------------------------------ - include/exec/memory-internal.h | 12 +++++++----- - include/exec/memory.h | 2 -- - memory.c | 31 ++++++++++++++++++++++++------- - 4 files changed, 42 insertions(+), 44 deletions(-) - -diff --git a/exec.c b/exec.c -index 4fed7b7..3c0b4f8 100644 ---- a/exec.c -+++ b/exec.c -@@ -188,8 +188,6 @@ typedef struct PhysPageMap { - } PhysPageMap; - - struct AddressSpaceDispatch { -- struct rcu_head rcu; -- - MemoryRegionSection *mru_section; - /* This is a multi-level map on the physical address space. - * The bottom level has pointers to MemoryRegionSections. -@@ -493,7 +491,7 @@ static MemoryRegionSection address_space_do_translate(AddressSpace *as, - } - - for (;;) { -- AddressSpaceDispatch *d = atomic_rcu_read(&as->dispatch); -+ AddressSpaceDispatch *d = address_space_to_dispatch(as); - section = address_space_translate_internal(d, addr, &addr, &plen, is_mmio); - - iommu_mr = memory_region_get_iommu(section->mr); -@@ -1233,7 +1231,7 @@ hwaddr memory_region_section_get_iotlb(CPUState *cpu, - } else { - AddressSpaceDispatch *d; - -- d = atomic_rcu_read(§ion->address_space->dispatch); -+ d = address_space_to_dispatch(section->address_space); - iotlb = section - d->map.sections; - iotlb += xlat; - } -@@ -1358,9 +1356,9 @@ static void register_multipage(AddressSpaceDispatch *d, - phys_page_set(d, start_addr >> TARGET_PAGE_BITS, num_pages, section_index); - } - --void mem_add(AddressSpace *as, MemoryRegionSection *section) -+void mem_add(AddressSpace *as, FlatView *fv, MemoryRegionSection *section) - { -- AddressSpaceDispatch *d = as->next_dispatch; -+ AddressSpaceDispatch *d = flatview_to_dispatch(fv); - MemoryRegionSection now = *section, remain = *section; - Int128 page_size = int128_make64(TARGET_PAGE_SIZE); - -@@ -2683,7 +2681,7 @@ static void io_mem_init(void) - NULL, UINT64_MAX); - } - --void mem_begin(AddressSpace *as) -+AddressSpaceDispatch *mem_begin(AddressSpace *as) - { - AddressSpaceDispatch *d = g_new0(AddressSpaceDispatch, 1); - uint16_t n; -@@ -2699,26 +2697,19 @@ void mem_begin(AddressSpace *as) - - d->phys_map = (PhysPageEntry) { .ptr = PHYS_MAP_NODE_NIL, .skip = 1 }; - d->as = as; -- as->next_dispatch = d; -+ -+ return d; - } - --static void address_space_dispatch_free(AddressSpaceDispatch *d) -+void address_space_dispatch_free(AddressSpaceDispatch *d) - { - phys_sections_free(&d->map); - g_free(d); - } - --void mem_commit(AddressSpace *as) -+void mem_commit(AddressSpaceDispatch *d) - { -- AddressSpaceDispatch *cur = as->dispatch; -- AddressSpaceDispatch *next = as->next_dispatch; -- -- phys_page_compact_all(next, next->map.nodes_nb); -- -- atomic_rcu_set(&as->dispatch, next); -- if (cur) { -- call_rcu(cur, address_space_dispatch_free, rcu); -- } -+ phys_page_compact_all(d, d->map.nodes_nb); - } - - static void tcg_commit(MemoryListener *listener) -@@ -2734,21 +2725,11 @@ static void tcg_commit(MemoryListener *listener) - * We reload the dispatch pointer now because cpu_reloading_memory_map() - * may have split the RCU critical section. - */ -- d = atomic_rcu_read(&cpuas->as->dispatch); -+ d = address_space_to_dispatch(cpuas->as); - atomic_rcu_set(&cpuas->memory_dispatch, d); - tlb_flush(cpuas->cpu); - } - --void address_space_destroy_dispatch(AddressSpace *as) --{ -- AddressSpaceDispatch *d = as->dispatch; -- -- atomic_rcu_set(&as->dispatch, NULL); -- if (d) { -- call_rcu(d, address_space_dispatch_free, rcu); -- } --} -- - static void memory_map_init(void) - { - system_memory = g_malloc(sizeof(*system_memory)); -diff --git a/include/exec/memory-internal.h b/include/exec/memory-internal.h -index 9abde2f..6e08eda 100644 ---- a/include/exec/memory-internal.h -+++ b/include/exec/memory-internal.h -@@ -22,16 +22,18 @@ - #ifndef CONFIG_USER_ONLY - typedef struct AddressSpaceDispatch AddressSpaceDispatch; - --void address_space_destroy_dispatch(AddressSpace *as); -- - extern const MemoryRegionOps unassigned_mem_ops; - - bool memory_region_access_valid(MemoryRegion *mr, hwaddr addr, - unsigned size, bool is_write); - --void mem_add(AddressSpace *as, MemoryRegionSection *section); --void mem_begin(AddressSpace *as); --void mem_commit(AddressSpace *as); -+void mem_add(AddressSpace *as, FlatView *fv, MemoryRegionSection *section); -+AddressSpaceDispatch *mem_begin(AddressSpace *as); -+void mem_commit(AddressSpaceDispatch *d); -+ -+AddressSpaceDispatch *address_space_to_dispatch(AddressSpace *as); -+AddressSpaceDispatch *flatview_to_dispatch(FlatView *fv); -+void address_space_dispatch_free(AddressSpaceDispatch *d); - - #endif - #endif -diff --git a/include/exec/memory.h b/include/exec/memory.h -index 9ee0f2e..8f26d63 100644 ---- a/include/exec/memory.h -+++ b/include/exec/memory.h -@@ -326,8 +326,6 @@ struct AddressSpace { - - int ioeventfd_nb; - struct MemoryRegionIoeventfd *ioeventfds; -- struct AddressSpaceDispatch *dispatch; -- struct AddressSpaceDispatch *next_dispatch; - QTAILQ_HEAD(memory_listeners_as, MemoryListener) listeners; - QTAILQ_ENTRY(AddressSpace) address_spaces_link; - }; -diff --git a/memory.c b/memory.c -index f51e499..41e2e67 100644 ---- a/memory.c -+++ b/memory.c -@@ -229,6 +229,7 @@ struct FlatView { - FlatRange *ranges; - unsigned nr; - unsigned nr_allocated; -+ struct AddressSpaceDispatch *dispatch; - }; - - typedef struct AddressSpaceOps AddressSpaceOps; -@@ -289,6 +290,9 @@ static void flatview_destroy(FlatView *view) - { - int i; - -+ if (view->dispatch) { -+ address_space_dispatch_free(view->dispatch); -+ } - for (i = 0; i < view->nr; i++) { - memory_region_unref(view->ranges[i].mr); - } -@@ -304,10 +308,25 @@ static bool flatview_ref(FlatView *view) - static void flatview_unref(FlatView *view) - { - if (atomic_fetch_dec(&view->ref) == 1) { -- flatview_destroy(view); -+ call_rcu(view, flatview_destroy, rcu); - } - } - -+static FlatView *address_space_to_flatview(AddressSpace *as) -+{ -+ return atomic_rcu_read(&as->current_map); -+} -+ -+AddressSpaceDispatch *flatview_to_dispatch(FlatView *fv) -+{ -+ return fv->dispatch; -+} -+ -+AddressSpaceDispatch *address_space_to_dispatch(AddressSpace *as) -+{ -+ return flatview_to_dispatch(address_space_to_flatview(as)); -+} -+ - static bool can_merge(FlatRange *r1, FlatRange *r2) - { - return int128_eq(addrrange_end(r1->addr), r2->addr.start) -@@ -890,13 +909,13 @@ static void address_space_update_topology(AddressSpace *as) - FlatView *new_view = generate_memory_topology(as->root); - int i; - -- mem_begin(as); -+ new_view->dispatch = mem_begin(as); - for (i = 0; i < new_view->nr; i++) { - MemoryRegionSection mrs = - section_from_flat_range(&new_view->ranges[i], as); -- mem_add(as, &mrs); -+ mem_add(as, new_view, &mrs); - } -- mem_commit(as); -+ mem_commit(new_view->dispatch); - - if (!QTAILQ_EMPTY(&as->listeners)) { - address_space_update_topology_pass(as, old_view, new_view, false); -@@ -905,7 +924,7 @@ static void address_space_update_topology(AddressSpace *as) - - /* Writes are protected by the BQL. */ - atomic_rcu_set(&as->current_map, new_view); -- call_rcu(old_view, flatview_unref, rcu); -+ flatview_unref(old_view); - - /* Note that all the old MemoryRegions are still alive up to this - * point. This relieves most MemoryListeners from the need to -@@ -2635,7 +2654,6 @@ void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name) - QTAILQ_INIT(&as->listeners); - QTAILQ_INSERT_TAIL(&address_spaces, as, address_spaces_link); - as->name = g_strdup(name ? name : "anonymous"); -- as->dispatch = NULL; - memory_region_update_pending |= root->enabled; - memory_region_transaction_commit(); - } -@@ -2644,7 +2662,6 @@ static void do_address_space_destroy(AddressSpace *as) - { - bool do_free = as->malloced; - -- address_space_destroy_dispatch(as); - assert(QTAILQ_EMPTY(&as->listeners)); - - flatview_unref(as->current_map); --- -1.8.3.1 - diff --git a/SOURCES/kvm-memory-Move-FlatView-allocation-to-a-helper.patch b/SOURCES/kvm-memory-Move-FlatView-allocation-to-a-helper.patch deleted file mode 100644 index 5293194..0000000 --- a/SOURCES/kvm-memory-Move-FlatView-allocation-to-a-helper.patch +++ /dev/null @@ -1,80 +0,0 @@ -From f99aa9de16a53a783a88cb9049ef42977037c935 Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Thu, 16 Nov 2017 03:07:16 +0100 -Subject: [PATCH 12/30] memory: Move FlatView allocation to a helper - -RH-Author: David Gibson -Message-id: <20171116030732.8560-7-dgibson@redhat.com> -Patchwork-id: 77693 -O-Subject: [PATCH 06/22] memory: Move FlatView allocation to a helper -Bugzilla: 1481593 -RH-Acked-by: Thomas Huth -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Eduardo Habkost -RH-Acked-by: Laurent Vivier - -From: Alexey Kardashevskiy - -This moves a FlatView allocation and initialization to a helper. -While we are nere, replace g_new with g_new0 to not to bother if we add -new fields in the future. - -This should cause no behavioural change. - -Signed-off-by: Alexey Kardashevskiy -Message-Id: <20170921085110.25598-4-aik@ozlabs.ru> -Signed-off-by: Paolo Bonzini -(cherry picked from commit cc94cd6d36602d976a5e7bc29134d1eaefb4102e) - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - memory.c | 16 ++++++++-------- - 1 file changed, 8 insertions(+), 8 deletions(-) - -diff --git a/memory.c b/memory.c -index 8bc1f56..f51e499 100644 ---- a/memory.c -+++ b/memory.c -@@ -258,12 +258,14 @@ static bool flatrange_equal(FlatRange *a, FlatRange *b) - && a->readonly == b->readonly; - } - --static void flatview_init(FlatView *view) -+static FlatView *flatview_new(void) - { -+ FlatView *view; -+ -+ view = g_new0(FlatView, 1); - view->ref = 1; -- view->ranges = NULL; -- view->nr = 0; -- view->nr_allocated = 0; -+ -+ return view; - } - - /* Insert a range into a given position. Caller is responsible for maintaining -@@ -706,8 +708,7 @@ static FlatView *generate_memory_topology(MemoryRegion *mr) - { - FlatView *view; - -- view = g_new(FlatView, 1); -- flatview_init(view); -+ view = flatview_new(); - - if (mr) { - render_memory_region(view, mr, int128_zero(), -@@ -2628,8 +2629,7 @@ void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name) - as->ref_count = 1; - as->root = root; - as->malloced = false; -- as->current_map = g_new(FlatView, 1); -- flatview_init(as->current_map); -+ as->current_map = flatview_new(); - as->ioeventfd_nb = 0; - as->ioeventfds = NULL; - QTAILQ_INIT(&as->listeners); --- -1.8.3.1 - diff --git a/SOURCES/kvm-memory-Move-address_space_update_ioeventfds.patch b/SOURCES/kvm-memory-Move-address_space_update_ioeventfds.patch deleted file mode 100644 index 777e2de..0000000 --- a/SOURCES/kvm-memory-Move-address_space_update_ioeventfds.patch +++ /dev/null @@ -1,55 +0,0 @@ -From b512b7ed1761bb5a288314e3f1ed674bcc40a22c Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Thu, 16 Nov 2017 03:07:24 +0100 -Subject: [PATCH 20/30] memory: Move address_space_update_ioeventfds - -RH-Author: David Gibson -Message-id: <20171116030732.8560-15-dgibson@redhat.com> -Patchwork-id: 77702 -O-Subject: [PATCH 14/22] memory: Move address_space_update_ioeventfds -Bugzilla: 1481593 -RH-Acked-by: Thomas Huth -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Eduardo Habkost -RH-Acked-by: Laurent Vivier - -From: Alexey Kardashevskiy - -So it is called (twice) from the same function. This is to make the next -patches a bit simpler. - -Signed-off-by: Alexey Kardashevskiy -Message-Id: <20170921085110.25598-12-aik@ozlabs.ru> -Signed-off-by: Paolo Bonzini -(cherry picked from commit 02218487649558ed66c3689d4cc55250a42601d8) - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - memory.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/memory.c b/memory.c -index 8034520..1f58d29 100644 ---- a/memory.c -+++ b/memory.c -@@ -951,8 +951,6 @@ static void address_space_update_topology(AddressSpace *as) - * counting is necessary. - */ - flatview_unref(old_view); -- -- address_space_update_ioeventfds(as); - } - - void memory_region_transaction_begin(void) -@@ -975,6 +973,7 @@ void memory_region_transaction_commit(void) - - QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { - address_space_update_topology(as); -+ address_space_update_ioeventfds(as); - } - memory_region_update_pending = false; - MEMORY_LISTENER_CALL_GLOBAL(commit, Forward); --- -1.8.3.1 - diff --git a/SOURCES/kvm-memory-Open-code-FlatView-rendering.patch b/SOURCES/kvm-memory-Open-code-FlatView-rendering.patch deleted file mode 100644 index dabf0ab..0000000 --- a/SOURCES/kvm-memory-Open-code-FlatView-rendering.patch +++ /dev/null @@ -1,190 +0,0 @@ -From 8ce98f8422946cc39437a06fcab4498350d4d482 Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Thu, 16 Nov 2017 03:07:15 +0100 -Subject: [PATCH 11/30] memory: Open code FlatView rendering - -RH-Author: David Gibson -Message-id: <20171116030732.8560-6-dgibson@redhat.com> -Patchwork-id: 77695 -O-Subject: [PATCH 05/22] memory: Open code FlatView rendering -Bugzilla: 1481593 -RH-Acked-by: Thomas Huth -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Eduardo Habkost -RH-Acked-by: Laurent Vivier - -From: Alexey Kardashevskiy - -We are going to share FlatView's between AddressSpace's and per-AS -memory listeners won't suit the purpose anymore so open code -the dispatch tree rendering. - -Since there is a good chance that dispatch_listener was the only -listener, this avoids address_space_update_topology_pass() if there is -no registered listeners; this should improve starting time. - -This should cause no behavioural change. - -Signed-off-by: Alexey Kardashevskiy -Message-Id: <20170921085110.25598-3-aik@ozlabs.ru> -Signed-off-by: Paolo Bonzini -(cherry picked from commit 9a62e24f45bc97f8eaf198caf58906b47c50a8d5) - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - exec.c | 27 +++------------------------ - include/exec/memory-internal.h | 6 ++++-- - include/exec/memory.h | 1 - - memory.c | 19 ++++++++++++++----- - 4 files changed, 21 insertions(+), 32 deletions(-) - -diff --git a/exec.c b/exec.c -index f00bd4e..4fed7b7 100644 ---- a/exec.c -+++ b/exec.c -@@ -1358,9 +1358,8 @@ static void register_multipage(AddressSpaceDispatch *d, - phys_page_set(d, start_addr >> TARGET_PAGE_BITS, num_pages, section_index); - } - --static void mem_add(MemoryListener *listener, MemoryRegionSection *section) -+void mem_add(AddressSpace *as, MemoryRegionSection *section) - { -- AddressSpace *as = container_of(listener, AddressSpace, dispatch_listener); - AddressSpaceDispatch *d = as->next_dispatch; - MemoryRegionSection now = *section, remain = *section; - Int128 page_size = int128_make64(TARGET_PAGE_SIZE); -@@ -2684,9 +2683,8 @@ static void io_mem_init(void) - NULL, UINT64_MAX); - } - --static void mem_begin(MemoryListener *listener) -+void mem_begin(AddressSpace *as) - { -- AddressSpace *as = container_of(listener, AddressSpace, dispatch_listener); - AddressSpaceDispatch *d = g_new0(AddressSpaceDispatch, 1); - uint16_t n; - -@@ -2710,9 +2708,8 @@ static void address_space_dispatch_free(AddressSpaceDispatch *d) - g_free(d); - } - --static void mem_commit(MemoryListener *listener) -+void mem_commit(AddressSpace *as) - { -- AddressSpace *as = container_of(listener, AddressSpace, dispatch_listener); - AddressSpaceDispatch *cur = as->dispatch; - AddressSpaceDispatch *next = as->next_dispatch; - -@@ -2742,24 +2739,6 @@ static void tcg_commit(MemoryListener *listener) - tlb_flush(cpuas->cpu); - } - --void address_space_init_dispatch(AddressSpace *as) --{ -- as->dispatch = NULL; -- as->dispatch_listener = (MemoryListener) { -- .begin = mem_begin, -- .commit = mem_commit, -- .region_add = mem_add, -- .region_nop = mem_add, -- .priority = 0, -- }; -- memory_listener_register(&as->dispatch_listener, as); --} -- --void address_space_unregister(AddressSpace *as) --{ -- memory_listener_unregister(&as->dispatch_listener); --} -- - void address_space_destroy_dispatch(AddressSpace *as) - { - AddressSpaceDispatch *d = as->dispatch; -diff --git a/include/exec/memory-internal.h b/include/exec/memory-internal.h -index fb467ac..9abde2f 100644 ---- a/include/exec/memory-internal.h -+++ b/include/exec/memory-internal.h -@@ -22,8 +22,6 @@ - #ifndef CONFIG_USER_ONLY - typedef struct AddressSpaceDispatch AddressSpaceDispatch; - --void address_space_init_dispatch(AddressSpace *as); --void address_space_unregister(AddressSpace *as); - void address_space_destroy_dispatch(AddressSpace *as); - - extern const MemoryRegionOps unassigned_mem_ops; -@@ -31,5 +29,9 @@ extern const MemoryRegionOps unassigned_mem_ops; - bool memory_region_access_valid(MemoryRegion *mr, hwaddr addr, - unsigned size, bool is_write); - -+void mem_add(AddressSpace *as, MemoryRegionSection *section); -+void mem_begin(AddressSpace *as); -+void mem_commit(AddressSpace *as); -+ - #endif - #endif -diff --git a/include/exec/memory.h b/include/exec/memory.h -index 400dd44..9ee0f2e 100644 ---- a/include/exec/memory.h -+++ b/include/exec/memory.h -@@ -328,7 +328,6 @@ struct AddressSpace { - struct MemoryRegionIoeventfd *ioeventfds; - struct AddressSpaceDispatch *dispatch; - struct AddressSpaceDispatch *next_dispatch; -- MemoryListener dispatch_listener; - QTAILQ_HEAD(memory_listeners_as, MemoryListener) listeners; - QTAILQ_ENTRY(AddressSpace) address_spaces_link; - }; -diff --git a/memory.c b/memory.c -index ca160de..8bc1f56 100644 ---- a/memory.c -+++ b/memory.c -@@ -883,14 +883,24 @@ static void address_space_update_topology_pass(AddressSpace *as, - } - } - -- - static void address_space_update_topology(AddressSpace *as) - { - FlatView *old_view = address_space_get_flatview(as); - FlatView *new_view = generate_memory_topology(as->root); -+ int i; - -- address_space_update_topology_pass(as, old_view, new_view, false); -- address_space_update_topology_pass(as, old_view, new_view, true); -+ mem_begin(as); -+ for (i = 0; i < new_view->nr; i++) { -+ MemoryRegionSection mrs = -+ section_from_flat_range(&new_view->ranges[i], as); -+ mem_add(as, &mrs); -+ } -+ mem_commit(as); -+ -+ if (!QTAILQ_EMPTY(&as->listeners)) { -+ address_space_update_topology_pass(as, old_view, new_view, false); -+ address_space_update_topology_pass(as, old_view, new_view, true); -+ } - - /* Writes are protected by the BQL. */ - atomic_rcu_set(&as->current_map, new_view); -@@ -2625,7 +2635,7 @@ void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name) - QTAILQ_INIT(&as->listeners); - QTAILQ_INSERT_TAIL(&address_spaces, as, address_spaces_link); - as->name = g_strdup(name ? name : "anonymous"); -- address_space_init_dispatch(as); -+ as->dispatch = NULL; - memory_region_update_pending |= root->enabled; - memory_region_transaction_commit(); - } -@@ -2676,7 +2686,6 @@ void address_space_destroy(AddressSpace *as) - as->root = NULL; - memory_region_transaction_commit(); - QTAILQ_REMOVE(&address_spaces, as, address_spaces_link); -- address_space_unregister(as); - - /* At this point, as->dispatch and as->current_map are dummy - * entries that the guest should never use. Wait for the old --- -1.8.3.1 - diff --git a/SOURCES/kvm-memory-Remove-AddressSpace-pointer-from-AddressSpace.patch b/SOURCES/kvm-memory-Remove-AddressSpace-pointer-from-AddressSpace.patch deleted file mode 100644 index 1b80c0a..0000000 --- a/SOURCES/kvm-memory-Remove-AddressSpace-pointer-from-AddressSpace.patch +++ /dev/null @@ -1,100 +0,0 @@ -From 4fe0681fd4d203f6db9f6f025c373a5550c428c7 Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Thu, 16 Nov 2017 03:07:18 +0100 -Subject: [PATCH 14/30] memory: Remove AddressSpace pointer from - AddressSpaceDispatch - -RH-Author: David Gibson -Message-id: <20171116030732.8560-9-dgibson@redhat.com> -Patchwork-id: 77700 -O-Subject: [PATCH 08/22] memory: Remove AddressSpace pointer from AddressSpaceDispatch -Bugzilla: 1481593 -RH-Acked-by: Thomas Huth -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Eduardo Habkost -RH-Acked-by: Laurent Vivier - -From: Alexey Kardashevskiy - -AS in ASD is only used to pass AS from mem_begin() to register_subpage() -to store it in MemoryRegionSection, we can do this directly now. - -This should cause no behavioural change. - -Signed-off-by: Alexey Kardashevskiy -Message-Id: <20170921085110.25598-6-aik@ozlabs.ru> -Signed-off-by: Paolo Bonzini -(cherry picked from commit c7752523787dc148f5ee976162e80ab594c386a1) - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - exec.c | 15 +++++++-------- - 1 file changed, 7 insertions(+), 8 deletions(-) - -diff --git a/exec.c b/exec.c -index 3c0b4f8..6b84771 100644 ---- a/exec.c -+++ b/exec.c -@@ -194,7 +194,6 @@ struct AddressSpaceDispatch { - */ - PhysPageEntry phys_map; - PhysPageMap map; -- AddressSpace *as; - }; - - #define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK) -@@ -1314,7 +1313,8 @@ static void phys_sections_free(PhysPageMap *map) - g_free(map->nodes); - } - --static void register_subpage(AddressSpaceDispatch *d, MemoryRegionSection *section) -+static void register_subpage(AddressSpace *as, AddressSpaceDispatch *d, -+ MemoryRegionSection *section) - { - subpage_t *subpage; - hwaddr base = section->offset_within_address_space -@@ -1329,8 +1329,8 @@ static void register_subpage(AddressSpaceDispatch *d, MemoryRegionSection *secti - assert(existing->mr->subpage || existing->mr == &io_mem_unassigned); - - if (!(existing->mr->subpage)) { -- subpage = subpage_init(d->as, base); -- subsection.address_space = d->as; -+ subpage = subpage_init(as, base); -+ subsection.address_space = as; - subsection.mr = &subpage->iomem; - phys_page_set(d, base >> TARGET_PAGE_BITS, 1, - phys_section_add(&d->map, &subsection)); -@@ -1367,7 +1367,7 @@ void mem_add(AddressSpace *as, FlatView *fv, MemoryRegionSection *section) - - now.offset_within_address_space; - - now.size = int128_min(int128_make64(left), now.size); -- register_subpage(d, &now); -+ register_subpage(as, d, &now); - } else { - now.size = int128_zero(); - } -@@ -1377,10 +1377,10 @@ void mem_add(AddressSpace *as, FlatView *fv, MemoryRegionSection *section) - remain.offset_within_region += int128_get64(now.size); - now = remain; - if (int128_lt(remain.size, page_size)) { -- register_subpage(d, &now); -+ register_subpage(as, d, &now); - } else if (remain.offset_within_address_space & ~TARGET_PAGE_MASK) { - now.size = page_size; -- register_subpage(d, &now); -+ register_subpage(as, d, &now); - } else { - now.size = int128_and(now.size, int128_neg(page_size)); - register_multipage(d, &now); -@@ -2696,7 +2696,6 @@ AddressSpaceDispatch *mem_begin(AddressSpace *as) - assert(n == PHYS_SECTION_WATCH); - - d->phys_map = (PhysPageEntry) { .ptr = PHYS_MAP_NODE_NIL, .skip = 1 }; -- d->as = as; - - return d; - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-memory-Rename-mem_begin-mem_commit-mem_add-helpers.patch b/SOURCES/kvm-memory-Rename-mem_begin-mem_commit-mem_add-helpers.patch deleted file mode 100644 index 91da3a3..0000000 --- a/SOURCES/kvm-memory-Rename-mem_begin-mem_commit-mem_add-helpers.patch +++ /dev/null @@ -1,120 +0,0 @@ -From 1b3b5dcbfa953d50e2b9df7d620bb53234a4f477 Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Thu, 16 Nov 2017 03:07:21 +0100 -Subject: [PATCH 17/30] memory: Rename mem_begin/mem_commit/mem_add helpers - -RH-Author: David Gibson -Message-id: <20171116030732.8560-12-dgibson@redhat.com> -Patchwork-id: 77698 -O-Subject: [PATCH 11/22] memory: Rename mem_begin/mem_commit/mem_add helpers -Bugzilla: 1481593 -RH-Acked-by: Thomas Huth -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Eduardo Habkost -RH-Acked-by: Laurent Vivier - -From: Alexey Kardashevskiy - -This renames some helpers to reflect better what they do. - -This should cause no behavioural change. - -Signed-off-by: Alexey Kardashevskiy -Message-Id: <20170921085110.25598-9-aik@ozlabs.ru> -Signed-off-by: Paolo Bonzini -(cherry picked from commit 8629d3fcb77e9775e44d9051bad0fb5187925eae) - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - exec.c | 12 +++--------- - include/exec/memory-internal.h | 6 +++--- - memory.c | 6 +++--- - 3 files changed, 9 insertions(+), 15 deletions(-) - -diff --git a/exec.c b/exec.c -index d1d8486..1b30e1e 100644 ---- a/exec.c -+++ b/exec.c -@@ -359,7 +359,7 @@ static void phys_page_compact(PhysPageEntry *lp, Node *nodes) - } - } - --static void phys_page_compact_all(AddressSpaceDispatch *d, int nodes_nb) -+void address_space_dispatch_compact(AddressSpaceDispatch *d) - { - if (d->phys_map.skip) { - phys_page_compact(&d->phys_map, d->map.nodes); -@@ -1358,7 +1358,7 @@ static void register_multipage(FlatView *fv, - phys_page_set(d, start_addr >> TARGET_PAGE_BITS, num_pages, section_index); - } - --void mem_add(FlatView *fv, MemoryRegionSection *section) -+void flatview_add_to_dispatch(FlatView *fv, MemoryRegionSection *section) - { - MemoryRegionSection now = *section, remain = *section; - Int128 page_size = int128_make64(TARGET_PAGE_SIZE); -@@ -2684,9 +2684,8 @@ static void io_mem_init(void) - NULL, UINT64_MAX); - } - --AddressSpaceDispatch *mem_begin(AddressSpace *as) -+AddressSpaceDispatch *address_space_dispatch_new(FlatView *fv) - { -- FlatView *fv = address_space_to_flatview(as); - AddressSpaceDispatch *d = g_new0(AddressSpaceDispatch, 1); - uint16_t n; - -@@ -2710,11 +2709,6 @@ void address_space_dispatch_free(AddressSpaceDispatch *d) - g_free(d); - } - --void mem_commit(AddressSpaceDispatch *d) --{ -- phys_page_compact_all(d, d->map.nodes_nb); --} -- - static void tcg_commit(MemoryListener *listener) - { - CPUAddressSpace *cpuas; -diff --git a/include/exec/memory-internal.h b/include/exec/memory-internal.h -index 1cf8ad9..d4a35c6 100644 ---- a/include/exec/memory-internal.h -+++ b/include/exec/memory-internal.h -@@ -27,9 +27,9 @@ extern const MemoryRegionOps unassigned_mem_ops; - bool memory_region_access_valid(MemoryRegion *mr, hwaddr addr, - unsigned size, bool is_write); - --void mem_add(FlatView *fv, MemoryRegionSection *section); --AddressSpaceDispatch *mem_begin(AddressSpace *as); --void mem_commit(AddressSpaceDispatch *d); -+void flatview_add_to_dispatch(FlatView *fv, MemoryRegionSection *section); -+AddressSpaceDispatch *address_space_dispatch_new(FlatView *fv); -+void address_space_dispatch_compact(AddressSpaceDispatch *d); - - AddressSpaceDispatch *address_space_to_dispatch(AddressSpace *as); - AddressSpaceDispatch *flatview_to_dispatch(FlatView *fv); -diff --git a/memory.c b/memory.c -index 6678a53..b7d2536 100644 ---- a/memory.c -+++ b/memory.c -@@ -909,13 +909,13 @@ static void address_space_update_topology(AddressSpace *as) - FlatView *new_view = generate_memory_topology(as->root); - int i; - -- new_view->dispatch = mem_begin(as); -+ new_view->dispatch = address_space_dispatch_new(new_view); - for (i = 0; i < new_view->nr; i++) { - MemoryRegionSection mrs = - section_from_flat_range(&new_view->ranges[i], new_view); -- mem_add(new_view, &mrs); -+ flatview_add_to_dispatch(new_view, &mrs); - } -- mem_commit(new_view->dispatch); -+ address_space_dispatch_compact(new_view->dispatch); - - if (!QTAILQ_EMPTY(&as->listeners)) { - address_space_update_topology_pass(as, old_view, new_view, false); --- -1.8.3.1 - diff --git a/SOURCES/kvm-memory-Rework-info-mtree-to-print-flat-views-and-dis.patch b/SOURCES/kvm-memory-Rework-info-mtree-to-print-flat-views-and-dis.patch deleted file mode 100644 index c903921..0000000 --- a/SOURCES/kvm-memory-Rework-info-mtree-to-print-flat-views-and-dis.patch +++ /dev/null @@ -1,321 +0,0 @@ -From 6a1a074890aa228417dffb2afb49f56234e99c8d Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Thu, 16 Nov 2017 03:07:27 +0100 -Subject: [PATCH 23/30] memory: Rework "info mtree" to print flat views and - dispatch trees - -RH-Author: David Gibson -Message-id: <20171116030732.8560-18-dgibson@redhat.com> -Patchwork-id: 77709 -O-Subject: [PATCH 17/22] memory: Rework "info mtree" to print flat views and dispatch trees -Bugzilla: 1481593 -RH-Acked-by: Thomas Huth -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Eduardo Habkost -RH-Acked-by: Laurent Vivier - -From: Alexey Kardashevskiy - -This adds a new "-d" switch to "info mtree" to print dispatch tree -internals. - -This changes the way "-f" is handled - it prints now flat views and -associated address spaces. - -Signed-off-by: Alexey Kardashevskiy -Message-Id: <20170921085110.25598-15-aik@ozlabs.ru> -Signed-off-by: Paolo Bonzini -(cherry picked from commit 5e8fd947e2670c3c18f139de6a83fafcb56abbcc) - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - exec.c | 84 +++++++++++++++++++++++++++++++++++++++ - hmp-commands-info.hx | 7 ++-- - include/exec/memory-internal.h | 4 ++ - include/exec/memory.h | 3 +- - memory.c | 90 +++++++++++++++++++++++++++++++++++++----- - monitor.c | 3 +- - 6 files changed, 176 insertions(+), 15 deletions(-) - -diff --git a/exec.c b/exec.c -index 1b30e1e..5a12e55 100644 ---- a/exec.c -+++ b/exec.c -@@ -3628,3 +3628,87 @@ void page_size_init(void) - } - qemu_host_page_mask = -(intptr_t)qemu_host_page_size; - } -+ -+#if !defined(CONFIG_USER_ONLY) -+ -+static void mtree_print_phys_entries(fprintf_function mon, void *f, -+ int start, int end, int skip, int ptr) -+{ -+ if (start == end - 1) { -+ mon(f, "\t%3d ", start); -+ } else { -+ mon(f, "\t%3d..%-3d ", start, end - 1); -+ } -+ mon(f, " skip=%d ", skip); -+ if (ptr == PHYS_MAP_NODE_NIL) { -+ mon(f, " ptr=NIL"); -+ } else if (!skip) { -+ mon(f, " ptr=#%d", ptr); -+ } else { -+ mon(f, " ptr=[%d]", ptr); -+ } -+ mon(f, "\n"); -+} -+ -+#define MR_SIZE(size) (int128_nz(size) ? (hwaddr)int128_get64( \ -+ int128_sub((size), int128_one())) : 0) -+ -+void mtree_print_dispatch(fprintf_function mon, void *f, -+ AddressSpaceDispatch *d, MemoryRegion *root) -+{ -+ int i; -+ -+ mon(f, " Dispatch\n"); -+ mon(f, " Physical sections\n"); -+ -+ for (i = 0; i < d->map.sections_nb; ++i) { -+ MemoryRegionSection *s = d->map.sections + i; -+ const char *names[] = { " [unassigned]", " [not dirty]", -+ " [ROM]", " [watch]" }; -+ -+ mon(f, " #%d @" TARGET_FMT_plx ".." TARGET_FMT_plx " %s%s%s%s%s", -+ i, -+ s->offset_within_address_space, -+ s->offset_within_address_space + MR_SIZE(s->mr->size), -+ s->mr->name ? s->mr->name : "(noname)", -+ i < ARRAY_SIZE(names) ? names[i] : "", -+ s->mr == root ? " [ROOT]" : "", -+ s == d->mru_section ? " [MRU]" : "", -+ s->mr->is_iommu ? " [iommu]" : ""); -+ -+ if (s->mr->alias) { -+ mon(f, " alias=%s", s->mr->alias->name ? -+ s->mr->alias->name : "noname"); -+ } -+ mon(f, "\n"); -+ } -+ -+ mon(f, " Nodes (%d bits per level, %d levels) ptr=[%d] skip=%d\n", -+ P_L2_BITS, P_L2_LEVELS, d->phys_map.ptr, d->phys_map.skip); -+ for (i = 0; i < d->map.nodes_nb; ++i) { -+ int j, jprev; -+ PhysPageEntry prev; -+ Node *n = d->map.nodes + i; -+ -+ mon(f, " [%d]\n", i); -+ -+ for (j = 0, jprev = 0, prev = *n[0]; j < ARRAY_SIZE(*n); ++j) { -+ PhysPageEntry *pe = *n + j; -+ -+ if (pe->ptr == prev.ptr && pe->skip == prev.skip) { -+ continue; -+ } -+ -+ mtree_print_phys_entries(mon, f, jprev, j, prev.skip, prev.ptr); -+ -+ jprev = j; -+ prev = *pe; -+ } -+ -+ if (jprev != ARRAY_SIZE(*n)) { -+ mtree_print_phys_entries(mon, f, jprev, j, prev.skip, prev.ptr); -+ } -+ } -+} -+ -+#endif -diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx -index 0967e41..30b335f 100644 ---- a/hmp-commands-info.hx -+++ b/hmp-commands-info.hx -@@ -253,9 +253,10 @@ ETEXI - - { - .name = "mtree", -- .args_type = "flatview:-f", -- .params = "[-f]", -- .help = "show memory tree (-f: dump flat view for address spaces)", -+ .args_type = "flatview:-f,dispatch_tree:-d", -+ .params = "[-f][-d]", -+ .help = "show memory tree (-f: dump flat view for address spaces;" -+ "-d: dump dispatch tree, valid with -f only)", - .cmd = hmp_info_mtree, - }, - -diff --git a/include/exec/memory-internal.h b/include/exec/memory-internal.h -index d4a35c6..647e9bd 100644 ---- a/include/exec/memory-internal.h -+++ b/include/exec/memory-internal.h -@@ -35,5 +35,9 @@ AddressSpaceDispatch *address_space_to_dispatch(AddressSpace *as); - AddressSpaceDispatch *flatview_to_dispatch(FlatView *fv); - void address_space_dispatch_free(AddressSpaceDispatch *d); - -+void mtree_print_dispatch(fprintf_function mon, void *f, -+ struct AddressSpaceDispatch *d, -+ MemoryRegion *root); -+ - #endif - #endif -diff --git a/include/exec/memory.h b/include/exec/memory.h -index 6715551..157eae6 100644 ---- a/include/exec/memory.h -+++ b/include/exec/memory.h -@@ -1525,7 +1525,8 @@ void memory_global_dirty_log_start(void); - */ - void memory_global_dirty_log_stop(void); - --void mtree_info(fprintf_function mon_printf, void *f, bool flatview); -+void mtree_info(fprintf_function mon_printf, void *f, bool flatview, -+ bool dispatch_tree); - - /** - * memory_region_request_mmio_ptr: request a pointer to an mmio -diff --git a/memory.c b/memory.c -index 6914d87..25a8bf2 100644 ---- a/memory.c -+++ b/memory.c -@@ -2906,18 +2906,44 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f, - } - } - --static void mtree_print_flatview(fprintf_function p, void *f, -- AddressSpace *as) -+struct FlatViewInfo { -+ fprintf_function mon_printf; -+ void *f; -+ int counter; -+ bool dispatch_tree; -+}; -+ -+static void mtree_print_flatview(gpointer key, gpointer value, -+ gpointer user_data) - { -- FlatView *view = address_space_get_flatview(as); -+ FlatView *view = key; -+ GArray *fv_address_spaces = value; -+ struct FlatViewInfo *fvi = user_data; -+ fprintf_function p = fvi->mon_printf; -+ void *f = fvi->f; - FlatRange *range = &view->ranges[0]; - MemoryRegion *mr; - int n = view->nr; -+ int i; -+ AddressSpace *as; -+ -+ p(f, "FlatView #%d\n", fvi->counter); -+ ++fvi->counter; -+ -+ for (i = 0; i < fv_address_spaces->len; ++i) { -+ as = g_array_index(fv_address_spaces, AddressSpace*, i); -+ p(f, " AS \"%s\", root: %s", as->name, memory_region_name(as->root)); -+ if (as->root->alias) { -+ p(f, ", alias %s", memory_region_name(as->root->alias)); -+ } -+ p(f, "\n"); -+ } -+ -+ p(f, " Root memory region: %s\n", -+ view->root ? memory_region_name(view->root) : "(none)"); - - if (n <= 0) { -- p(f, MTREE_INDENT "No rendered FlatView for " -- "address space '%s'\n", as->name); -- flatview_unref(view); -+ p(f, MTREE_INDENT "No rendered FlatView\n\n"); - return; - } - -@@ -2944,21 +2970,65 @@ static void mtree_print_flatview(fprintf_function p, void *f, - range++; - } - -+#if !defined(CONFIG_USER_ONLY) -+ if (fvi->dispatch_tree && view->root) { -+ mtree_print_dispatch(p, f, view->dispatch, view->root); -+ } -+#endif -+ -+ p(f, "\n"); -+} -+ -+static gboolean mtree_info_flatview_free(gpointer key, gpointer value, -+ gpointer user_data) -+{ -+ FlatView *view = key; -+ GArray *fv_address_spaces = value; -+ -+ g_array_unref(fv_address_spaces); - flatview_unref(view); -+ -+ return true; - } - --void mtree_info(fprintf_function mon_printf, void *f, bool flatview) -+void mtree_info(fprintf_function mon_printf, void *f, bool flatview, -+ bool dispatch_tree) - { - MemoryRegionListHead ml_head; - MemoryRegionList *ml, *ml2; - AddressSpace *as; - - if (flatview) { -+ FlatView *view; -+ struct FlatViewInfo fvi = { -+ .mon_printf = mon_printf, -+ .f = f, -+ .counter = 0, -+ .dispatch_tree = dispatch_tree -+ }; -+ GArray *fv_address_spaces; -+ GHashTable *views = g_hash_table_new(g_direct_hash, g_direct_equal); -+ -+ /* Gather all FVs in one table */ - QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { -- mon_printf(f, "address-space (flat view): %s\n", as->name); -- mtree_print_flatview(mon_printf, f, as); -- mon_printf(f, "\n"); -+ view = address_space_get_flatview(as); -+ -+ fv_address_spaces = g_hash_table_lookup(views, view); -+ if (!fv_address_spaces) { -+ fv_address_spaces = g_array_new(false, false, sizeof(as)); -+ g_hash_table_insert(views, view, fv_address_spaces); -+ } -+ -+ g_array_append_val(fv_address_spaces, as); - } -+ -+ /* Print */ -+ g_hash_table_foreach(views, mtree_print_flatview, &fvi); -+ -+ /* Free */ -+ g_hash_table_foreach_remove(views, mtree_info_flatview_free, 0); -+ g_hash_table_unref(views); -+ - return; - } - -diff --git a/monitor.c b/monitor.c -index c0a8dbc..6380e4a 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -1734,8 +1734,9 @@ static void hmp_boot_set(Monitor *mon, const QDict *qdict) - static void hmp_info_mtree(Monitor *mon, const QDict *qdict) - { - bool flatview = qdict_get_try_bool(qdict, "flatview", false); -+ bool dispatch_tree = qdict_get_try_bool(qdict, "dispatch_tree", false); - -- mtree_info((fprintf_function)monitor_printf, mon, flatview); -+ mtree_info((fprintf_function)monitor_printf, mon, flatview, dispatch_tree); - } - - static void hmp_info_numa(Monitor *mon, const QDict *qdict) --- -1.8.3.1 - diff --git a/SOURCES/kvm-memory-Share-FlatView-s-and-dispatch-trees-between-a.patch b/SOURCES/kvm-memory-Share-FlatView-s-and-dispatch-trees-between-a.patch deleted file mode 100644 index bd8279a..0000000 --- a/SOURCES/kvm-memory-Share-FlatView-s-and-dispatch-trees-between-a.patch +++ /dev/null @@ -1,143 +0,0 @@ -From f47eec19ea8dd0f693755cf42e4962e3ec43b06b Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Thu, 16 Nov 2017 03:07:25 +0100 -Subject: [PATCH 21/30] memory: Share FlatView's and dispatch trees between - address spaces - -RH-Author: David Gibson -Message-id: <20171116030732.8560-16-dgibson@redhat.com> -Patchwork-id: 77707 -O-Subject: [PATCH 15/22] memory: Share FlatView's and dispatch trees between address spaces -Bugzilla: 1481593 -RH-Acked-by: Thomas Huth -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Eduardo Habkost -RH-Acked-by: Laurent Vivier - -From: Alexey Kardashevskiy - -This allows sharing flat views between address spaces (AS) when -the same root memory region is used when creating a new address space. -This is done by walking through all ASes and caching one FlatView per -a physical root MR (i.e. not aliased). - -This removes search for duplicates from address_space_init_shareable() as -FlatViews are shared elsewhere and keeping as::ref_count correct seems -an unnecessary and useless complication. - -This should cause no change and memory use or boot time yet. - -Signed-off-by: Alexey Kardashevskiy -Message-Id: <20170921085110.25598-13-aik@ozlabs.ru> -Signed-off-by: Paolo Bonzini -(cherry picked from commit 967dc9b1194a9281124b2e1ce67b6c3359a2138f) - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - memory.c | 56 +++++++++++++++++++++++++++++++++++++++++++++----------- - 1 file changed, 45 insertions(+), 11 deletions(-) - -diff --git a/memory.c b/memory.c -index 1f58d29..f0c8642 100644 ---- a/memory.c -+++ b/memory.c -@@ -47,6 +47,8 @@ static QTAILQ_HEAD(memory_listeners, MemoryListener) memory_listeners - static QTAILQ_HEAD(, AddressSpace) address_spaces - = QTAILQ_HEAD_INITIALIZER(address_spaces); - -+static GHashTable *flat_views; -+ - typedef struct AddrRange AddrRange; - - /* -@@ -760,6 +762,7 @@ static FlatView *generate_memory_topology(MemoryRegion *mr) - flatview_add_to_dispatch(view, &mrs); - } - address_space_dispatch_compact(view->dispatch); -+ g_hash_table_replace(flat_views, mr, view); - - return view; - } -@@ -929,11 +932,47 @@ static void address_space_update_topology_pass(AddressSpace *as, - } - } - --static void address_space_update_topology(AddressSpace *as) -+static void flatviews_init(void) -+{ -+ if (flat_views) { -+ return; -+ } -+ -+ flat_views = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, -+ (GDestroyNotify) flatview_unref); -+} -+ -+static void flatviews_reset(void) -+{ -+ AddressSpace *as; -+ -+ if (flat_views) { -+ g_hash_table_unref(flat_views); -+ flat_views = NULL; -+ } -+ flatviews_init(); -+ -+ /* Render unique FVs */ -+ QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { -+ MemoryRegion *physmr = memory_region_get_flatview_root(as->root); -+ -+ if (g_hash_table_lookup(flat_views, physmr)) { -+ continue; -+ } -+ -+ generate_memory_topology(physmr); -+ } -+} -+ -+static void address_space_set_flatview(AddressSpace *as) - { - FlatView *old_view = address_space_get_flatview(as); -- MemoryRegion *physmr = memory_region_get_flatview_root(old_view->root); -- FlatView *new_view = generate_memory_topology(physmr); -+ MemoryRegion *physmr = memory_region_get_flatview_root(as->root); -+ FlatView *new_view = g_hash_table_lookup(flat_views, physmr); -+ -+ assert(new_view); -+ -+ flatview_ref(new_view); - - if (!QTAILQ_EMPTY(&as->listeners)) { - address_space_update_topology_pass(as, old_view, new_view, false); -@@ -969,10 +1008,12 @@ void memory_region_transaction_commit(void) - --memory_region_transaction_depth; - if (!memory_region_transaction_depth) { - if (memory_region_update_pending) { -+ flatviews_reset(); -+ - MEMORY_LISTENER_CALL_GLOBAL(begin, Forward); - - QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { -- address_space_update_topology(as); -+ address_space_set_flatview(as); - address_space_update_ioeventfds(as); - } - memory_region_update_pending = false; -@@ -2695,13 +2736,6 @@ AddressSpace *address_space_init_shareable(MemoryRegion *root, const char *name) - { - AddressSpace *as; - -- QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { -- if (root == as->root && as->malloced) { -- as->ref_count++; -- return as; -- } -- } -- - as = g_malloc0(sizeof *as); - address_space_init(as, root, name); - as->malloced = true; --- -1.8.3.1 - diff --git a/SOURCES/kvm-memory-Share-special-empty-FlatView.patch b/SOURCES/kvm-memory-Share-special-empty-FlatView.patch deleted file mode 100644 index 9ab915b..0000000 --- a/SOURCES/kvm-memory-Share-special-empty-FlatView.patch +++ /dev/null @@ -1,100 +0,0 @@ -From 5643e64ad775e2a14c76faa867ad698c5e1fe9c7 Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Thu, 16 Nov 2017 03:07:32 +0100 -Subject: [PATCH 28/30] memory: Share special empty FlatView - -RH-Author: David Gibson -Message-id: <20171116030732.8560-23-dgibson@redhat.com> -Patchwork-id: 77711 -O-Subject: [PATCH 22/22] memory: Share special empty FlatView -Bugzilla: 1481593 -RH-Acked-by: Thomas Huth -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Eduardo Habkost -RH-Acked-by: Laurent Vivier - -From: Alexey Kardashevskiy - -This shares an cached empty FlatView among address spaces. The empty -FV is used every time when a root MR renders into a FV without memory -sections which happens when MR or its children are not enabled or -zero-sized. The empty_view is not NULL to keep the rest of memory -API intact; it also has a dispatch tree for the same reason. - -On POWER8 with 255 CPUs, 255 virtio-net, 40 PCI bridges guest this halves -the amount of FlatView's in use (557 -> 260) and dispatch tables -(~800000 -> ~370000). In an unrelated experiment with 112 non-virtio -devices on x86 ("-M pc"), only 4 FlatViews are alive, and about ~2000 -are created at startup. - -Signed-off-by: Alexey Kardashevskiy -Message-Id: <20170921085110.25598-16-aik@ozlabs.ru> -Signed-off-by: Paolo Bonzini -(cherry picked from commit 092aa2fc65b7a35121616aad8f39d47b8f921618) - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - memory.c | 18 ++++++++++++++++-- - 1 file changed, 16 insertions(+), 2 deletions(-) - -diff --git a/memory.c b/memory.c -index 38eabe7..a1f1e68 100644 ---- a/memory.c -+++ b/memory.c -@@ -317,6 +317,7 @@ static void flatview_unref(FlatView *view) - { - if (atomic_fetch_dec(&view->ref) == 1) { - trace_flatview_destroy_rcu(view, view->root); -+ assert(view->root); - call_rcu(view, flatview_destroy, rcu); - } - } -@@ -760,16 +761,19 @@ static MemoryRegion *memory_region_get_flatview_root(MemoryRegion *mr) - } - } - } -+ if (found == 0) { -+ return NULL; -+ } - if (next) { - mr = next; - continue; - } - } - -- break; -+ return mr; - } - -- return mr; -+ return NULL; - } - - /* Render a memory topology into a list of disjoint absolute ranges. */ -@@ -965,12 +969,22 @@ static void address_space_update_topology_pass(AddressSpace *as, - - static void flatviews_init(void) - { -+ static FlatView *empty_view; -+ - if (flat_views) { - return; - } - - flat_views = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, - (GDestroyNotify) flatview_unref); -+ if (!empty_view) { -+ empty_view = generate_memory_topology(NULL); -+ /* We keep it alive forever in the global variable. */ -+ flatview_ref(empty_view); -+ } else { -+ g_hash_table_replace(flat_views, NULL, empty_view); -+ flatview_ref(empty_view); -+ } - } - - static void flatviews_reset(void) --- -1.8.3.1 - diff --git a/SOURCES/kvm-memory-Store-physical-root-MR-in-FlatView.patch b/SOURCES/kvm-memory-Store-physical-root-MR-in-FlatView.patch deleted file mode 100644 index 0a56068..0000000 --- a/SOURCES/kvm-memory-Store-physical-root-MR-in-FlatView.patch +++ /dev/null @@ -1,117 +0,0 @@ -From 44af3e507b25491e8ee996f83076138925a23e16 Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Thu, 16 Nov 2017 03:07:22 +0100 -Subject: [PATCH 18/30] memory: Store physical root MR in FlatView - -RH-Author: David Gibson -Message-id: <20171116030732.8560-13-dgibson@redhat.com> -Patchwork-id: 77699 -O-Subject: [PATCH 12/22] memory: Store physical root MR in FlatView -Bugzilla: 1481593 -RH-Acked-by: Thomas Huth -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Eduardo Habkost -RH-Acked-by: Laurent Vivier - -From: Alexey Kardashevskiy - -Address spaces get to keep a root MR (alias or not) but FlatView stores -the actual MR as this is going to be used later on to decide whether to -share a particular FlatView or not. - -Signed-off-by: Alexey Kardashevskiy -Message-Id: <20170921085110.25598-10-aik@ozlabs.ru> -Signed-off-by: Paolo Bonzini -(cherry picked from commit 89c177bbdd6cf8e50b3fd4831697d50e195d6432) - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - memory.c | 26 ++++++++++++++++++++++---- - 1 file changed, 22 insertions(+), 4 deletions(-) - -diff --git a/memory.c b/memory.c -index b7d2536..7972235 100644 ---- a/memory.c -+++ b/memory.c -@@ -230,6 +230,7 @@ struct FlatView { - unsigned nr; - unsigned nr_allocated; - struct AddressSpaceDispatch *dispatch; -+ MemoryRegion *root; - }; - - typedef struct AddressSpaceOps AddressSpaceOps; -@@ -259,12 +260,14 @@ static bool flatrange_equal(FlatRange *a, FlatRange *b) - && a->readonly == b->readonly; - } - --static FlatView *flatview_new(void) -+static FlatView *flatview_new(MemoryRegion *mr_root) - { - FlatView *view; - - view = g_new0(FlatView, 1); - view->ref = 1; -+ view->root = mr_root; -+ memory_region_ref(mr_root); - - return view; - } -@@ -297,6 +300,7 @@ static void flatview_destroy(FlatView *view) - memory_region_unref(view->ranges[i].mr); - } - g_free(view->ranges); -+ memory_region_unref(view->root); - g_free(view); - } - -@@ -722,12 +726,25 @@ static void render_memory_region(FlatView *view, - } - } - -+static MemoryRegion *memory_region_get_flatview_root(MemoryRegion *mr) -+{ -+ while (mr->alias && !mr->alias_offset && -+ int128_ge(mr->size, mr->alias->size)) { -+ /* The alias is included in its entirety. Use it as -+ * the "real" root, so that we can share more FlatViews. -+ */ -+ mr = mr->alias; -+ } -+ -+ return mr; -+} -+ - /* Render a memory topology into a list of disjoint absolute ranges. */ - static FlatView *generate_memory_topology(MemoryRegion *mr) - { - FlatView *view; - -- view = flatview_new(); -+ view = flatview_new(mr); - - if (mr) { - render_memory_region(view, mr, int128_zero(), -@@ -906,7 +923,8 @@ static void address_space_update_topology_pass(AddressSpace *as, - static void address_space_update_topology(AddressSpace *as) - { - FlatView *old_view = address_space_get_flatview(as); -- FlatView *new_view = generate_memory_topology(as->root); -+ MemoryRegion *physmr = memory_region_get_flatview_root(old_view->root); -+ FlatView *new_view = generate_memory_topology(physmr); - int i; - - new_view->dispatch = address_space_dispatch_new(new_view); -@@ -2649,7 +2667,7 @@ void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name) - as->ref_count = 1; - as->root = root; - as->malloced = false; -- as->current_map = flatview_new(); -+ as->current_map = flatview_new(root); - as->ioeventfd_nb = 0; - as->ioeventfds = NULL; - QTAILQ_INIT(&as->listeners); --- -1.8.3.1 - diff --git a/SOURCES/kvm-memory-Switch-memory-from-using-AddressSpace-to-Flat.patch b/SOURCES/kvm-memory-Switch-memory-from-using-AddressSpace-to-Flat.patch deleted file mode 100644 index d547631..0000000 --- a/SOURCES/kvm-memory-Switch-memory-from-using-AddressSpace-to-Flat.patch +++ /dev/null @@ -1,814 +0,0 @@ -From f343747d64a32b4642b7969f97d43d820cc2d8ce Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Thu, 16 Nov 2017 03:07:19 +0100 -Subject: [PATCH 15/30] memory: Switch memory from using AddressSpace to - FlatView - -RH-Author: David Gibson -Message-id: <20171116030732.8560-10-dgibson@redhat.com> -Patchwork-id: 77694 -O-Subject: [PATCH 09/22] memory: Switch memory from using AddressSpace to FlatView -Bugzilla: 1481593 -RH-Acked-by: Thomas Huth -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Eduardo Habkost -RH-Acked-by: Laurent Vivier - -From: Alexey Kardashevskiy - -FlatView's will be shared between AddressSpace's and subpage_t -and MemoryRegionSection cannot store AS anymore, hence this change. - -In particular, for: - - typedef struct subpage_t { - MemoryRegion iomem; -- AddressSpace *as; -+ FlatView *fv; - hwaddr base; - uint16_t sub_section[]; - } subpage_t; - - struct MemoryRegionSection { - MemoryRegion *mr; -- AddressSpace *address_space; -+ FlatView *fv; - hwaddr offset_within_region; - Int128 size; - hwaddr offset_within_address_space; - bool readonly; - }; - -This should cause no behavioural change. - -Signed-off-by: Alexey Kardashevskiy -Message-Id: <20170921085110.25598-7-aik@ozlabs.ru> -Signed-off-by: Paolo Bonzini -(cherry picked from commit 166206845f7fd75e720e6feea0bb01957c8da07f) -Signed-off-by: Miroslav Rezanina - -Conflicts: - exec.c - -Conflicts because we applied d5e5fafd "exec: add page_mask for -flatview_do_translate" out of order downstream. - -Signed-off-by: David Gibson ---- - exec.c | 183 ++++++++++++++++++++++++----------------- - hw/intc/openpic_kvm.c | 2 +- - include/exec/memory-internal.h | 2 +- - include/exec/memory.h | 51 ++++++++---- - memory.c | 33 ++++---- - 5 files changed, 161 insertions(+), 110 deletions(-) - -diff --git a/exec.c b/exec.c -index 6b84771..0eedeb2 100644 ---- a/exec.c -+++ b/exec.c -@@ -199,7 +199,7 @@ struct AddressSpaceDispatch { - #define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK) - typedef struct subpage_t { - MemoryRegion iomem; -- AddressSpace *as; -+ FlatView *fv; - hwaddr base; - uint16_t sub_section[]; - } subpage_t; -@@ -469,14 +469,14 @@ address_space_translate_internal(AddressSpaceDispatch *d, hwaddr addr, hwaddr *x - } - - /* Called from RCU critical section */ --static MemoryRegionSection address_space_do_translate(AddressSpace *as, -- hwaddr addr, -- hwaddr *xlat, -- hwaddr *plen_out, -- hwaddr *page_mask_out, -- bool is_write, -- bool is_mmio, -- AddressSpace **target_as) -+static MemoryRegionSection flatview_do_translate(FlatView *fv, -+ hwaddr addr, -+ hwaddr *xlat, -+ hwaddr *plen_out, -+ hwaddr *page_mask_out, -+ bool is_write, -+ bool is_mmio, -+ AddressSpace **target_as) - { - IOMMUTLBEntry iotlb; - MemoryRegionSection *section; -@@ -490,8 +490,9 @@ static MemoryRegionSection address_space_do_translate(AddressSpace *as, - } - - for (;;) { -- AddressSpaceDispatch *d = address_space_to_dispatch(as); -- section = address_space_translate_internal(d, addr, &addr, &plen, is_mmio); -+ section = address_space_translate_internal( -+ flatview_to_dispatch(fv), addr, &addr, -+ &plen, is_mmio); - - iommu_mr = memory_region_get_iommu(section->mr); - if (!iommu_mr) { -@@ -509,7 +510,7 @@ static MemoryRegionSection address_space_do_translate(AddressSpace *as, - goto translate_fail; - } - -- as = iotlb.target_as; -+ fv = address_space_to_flatview(iotlb.target_as); - *target_as = iotlb.target_as; - } - -@@ -545,8 +546,8 @@ IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr, - * This can never be MMIO, and we don't really care about plen, - * but page mask. - */ -- section = address_space_do_translate(as, addr, &xlat, NULL, -- &page_mask, is_write, false, &as); -+ section = flatview_do_translate(address_space_to_flatview(as), addr, &xlat, NULL, -+ &page_mask, is_write, false, &as); - - /* Illegal translation */ - if (section.mr == &io_mem_unassigned) { -@@ -571,16 +572,16 @@ iotlb_fail: - } - - /* Called from RCU critical section */ --MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr, -- hwaddr *xlat, hwaddr *plen, -- bool is_write) -+MemoryRegion *flatview_translate(FlatView *fv, hwaddr addr, hwaddr *xlat, -+ hwaddr *plen, bool is_write) - { - MemoryRegion *mr; - MemoryRegionSection section; -+ AddressSpace *as = NULL; - - /* This can be MMIO, so setup MMIO bit. */ -- section = address_space_do_translate(as, addr, xlat, plen, NULL, -- is_write, true, &as); -+ section = flatview_do_translate(fv, addr, xlat, plen, NULL, -+ is_write, true, &as); - mr = section.mr; - - if (xen_enabled() && memory_access_is_direct(mr, is_write)) { -@@ -1230,7 +1231,7 @@ hwaddr memory_region_section_get_iotlb(CPUState *cpu, - } else { - AddressSpaceDispatch *d; - -- d = address_space_to_dispatch(section->address_space); -+ d = flatview_to_dispatch(section->fv); - iotlb = section - d->map.sections; - iotlb += xlat; - } -@@ -1256,7 +1257,7 @@ hwaddr memory_region_section_get_iotlb(CPUState *cpu, - - static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end, - uint16_t section); --static subpage_t *subpage_init(AddressSpace *as, hwaddr base); -+static subpage_t *subpage_init(FlatView *fv, hwaddr base); - - static void *(*phys_mem_alloc)(size_t size, uint64_t *align) = - qemu_anon_ram_alloc; -@@ -1313,7 +1314,7 @@ static void phys_sections_free(PhysPageMap *map) - g_free(map->nodes); - } - --static void register_subpage(AddressSpace *as, AddressSpaceDispatch *d, -+static void register_subpage(FlatView *fv, AddressSpaceDispatch *d, - MemoryRegionSection *section) - { - subpage_t *subpage; -@@ -1329,8 +1330,8 @@ static void register_subpage(AddressSpace *as, AddressSpaceDispatch *d, - assert(existing->mr->subpage || existing->mr == &io_mem_unassigned); - - if (!(existing->mr->subpage)) { -- subpage = subpage_init(as, base); -- subsection.address_space = as; -+ subpage = subpage_init(fv, base); -+ subsection.fv = fv; - subsection.mr = &subpage->iomem; - phys_page_set(d, base >> TARGET_PAGE_BITS, 1, - phys_section_add(&d->map, &subsection)); -@@ -1356,7 +1357,7 @@ static void register_multipage(AddressSpaceDispatch *d, - phys_page_set(d, start_addr >> TARGET_PAGE_BITS, num_pages, section_index); - } - --void mem_add(AddressSpace *as, FlatView *fv, MemoryRegionSection *section) -+void mem_add(FlatView *fv, MemoryRegionSection *section) - { - AddressSpaceDispatch *d = flatview_to_dispatch(fv); - MemoryRegionSection now = *section, remain = *section; -@@ -1367,7 +1368,7 @@ void mem_add(AddressSpace *as, FlatView *fv, MemoryRegionSection *section) - - now.offset_within_address_space; - - now.size = int128_min(int128_make64(left), now.size); -- register_subpage(as, d, &now); -+ register_subpage(fv, d, &now); - } else { - now.size = int128_zero(); - } -@@ -1377,10 +1378,10 @@ void mem_add(AddressSpace *as, FlatView *fv, MemoryRegionSection *section) - remain.offset_within_region += int128_get64(now.size); - now = remain; - if (int128_lt(remain.size, page_size)) { -- register_subpage(as, d, &now); -+ register_subpage(fv, d, &now); - } else if (remain.offset_within_address_space & ~TARGET_PAGE_MASK) { - now.size = page_size; -- register_subpage(as, d, &now); -+ register_subpage(fv, d, &now); - } else { - now.size = int128_and(now.size, int128_neg(page_size)); - register_multipage(d, &now); -@@ -2511,6 +2512,11 @@ static const MemoryRegionOps watch_mem_ops = { - .endianness = DEVICE_NATIVE_ENDIAN, - }; - -+static MemTxResult flatview_write(FlatView *fv, hwaddr addr, MemTxAttrs attrs, -+ const uint8_t *buf, int len); -+static bool flatview_access_valid(FlatView *fv, hwaddr addr, int len, -+ bool is_write); -+ - static MemTxResult subpage_read(void *opaque, hwaddr addr, uint64_t *data, - unsigned len, MemTxAttrs attrs) - { -@@ -2522,8 +2528,7 @@ static MemTxResult subpage_read(void *opaque, hwaddr addr, uint64_t *data, - printf("%s: subpage %p len %u addr " TARGET_FMT_plx "\n", __func__, - subpage, len, addr); - #endif -- res = address_space_read(subpage->as, addr + subpage->base, -- attrs, buf, len); -+ res = flatview_read(subpage->fv, addr + subpage->base, attrs, buf, len); - if (res) { - return res; - } -@@ -2572,8 +2577,7 @@ static MemTxResult subpage_write(void *opaque, hwaddr addr, - default: - abort(); - } -- return address_space_write(subpage->as, addr + subpage->base, -- attrs, buf, len); -+ return flatview_write(subpage->fv, addr + subpage->base, attrs, buf, len); - } - - static bool subpage_accepts(void *opaque, hwaddr addr, -@@ -2585,8 +2589,8 @@ static bool subpage_accepts(void *opaque, hwaddr addr, - __func__, subpage, is_write ? 'w' : 'r', len, addr); - #endif - -- return address_space_access_valid(subpage->as, addr + subpage->base, -- len, is_write); -+ return flatview_access_valid(subpage->fv, addr + subpage->base, -+ len, is_write); - } - - static const MemoryRegionOps subpage_ops = { -@@ -2620,12 +2624,12 @@ static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end, - return 0; - } - --static subpage_t *subpage_init(AddressSpace *as, hwaddr base) -+static subpage_t *subpage_init(FlatView *fv, hwaddr base) - { - subpage_t *mmio; - - mmio = g_malloc0(sizeof(subpage_t) + TARGET_PAGE_SIZE * sizeof(uint16_t)); -- mmio->as = as; -+ mmio->fv = fv; - mmio->base = base; - memory_region_init_io(&mmio->iomem, NULL, &subpage_ops, mmio, - NULL, TARGET_PAGE_SIZE); -@@ -2639,12 +2643,11 @@ static subpage_t *subpage_init(AddressSpace *as, hwaddr base) - return mmio; - } - --static uint16_t dummy_section(PhysPageMap *map, AddressSpace *as, -- MemoryRegion *mr) -+static uint16_t dummy_section(PhysPageMap *map, FlatView *fv, MemoryRegion *mr) - { -- assert(as); -+ assert(fv); - MemoryRegionSection section = { -- .address_space = as, -+ .fv = fv, - .mr = mr, - .offset_within_address_space = 0, - .offset_within_region = 0, -@@ -2683,16 +2686,17 @@ static void io_mem_init(void) - - AddressSpaceDispatch *mem_begin(AddressSpace *as) - { -+ FlatView *fv = address_space_to_flatview(as); - AddressSpaceDispatch *d = g_new0(AddressSpaceDispatch, 1); - uint16_t n; - -- n = dummy_section(&d->map, as, &io_mem_unassigned); -+ n = dummy_section(&d->map, fv, &io_mem_unassigned); - assert(n == PHYS_SECTION_UNASSIGNED); -- n = dummy_section(&d->map, as, &io_mem_notdirty); -+ n = dummy_section(&d->map, fv, &io_mem_notdirty); - assert(n == PHYS_SECTION_NOTDIRTY); -- n = dummy_section(&d->map, as, &io_mem_rom); -+ n = dummy_section(&d->map, fv, &io_mem_rom); - assert(n == PHYS_SECTION_ROM); -- n = dummy_section(&d->map, as, &io_mem_watch); -+ n = dummy_section(&d->map, fv, &io_mem_watch); - assert(n == PHYS_SECTION_WATCH); - - d->phys_map = (PhysPageEntry) { .ptr = PHYS_MAP_NODE_NIL, .skip = 1 }; -@@ -2872,11 +2876,11 @@ static bool prepare_mmio_access(MemoryRegion *mr) - } - - /* Called within RCU critical section. */ --static MemTxResult address_space_write_continue(AddressSpace *as, hwaddr addr, -- MemTxAttrs attrs, -- const uint8_t *buf, -- int len, hwaddr addr1, -- hwaddr l, MemoryRegion *mr) -+static MemTxResult flatview_write_continue(FlatView *fv, hwaddr addr, -+ MemTxAttrs attrs, -+ const uint8_t *buf, -+ int len, hwaddr addr1, -+ hwaddr l, MemoryRegion *mr) - { - uint8_t *ptr; - uint64_t val; -@@ -2938,14 +2942,14 @@ static MemTxResult address_space_write_continue(AddressSpace *as, hwaddr addr, - } - - l = len; -- mr = address_space_translate(as, addr, &addr1, &l, true); -+ mr = flatview_translate(fv, addr, &addr1, &l, true); - } - - return result; - } - --MemTxResult address_space_write(AddressSpace *as, hwaddr addr, MemTxAttrs attrs, -- const uint8_t *buf, int len) -+static MemTxResult flatview_write(FlatView *fv, hwaddr addr, MemTxAttrs attrs, -+ const uint8_t *buf, int len) - { - hwaddr l; - hwaddr addr1; -@@ -2955,20 +2959,27 @@ MemTxResult address_space_write(AddressSpace *as, hwaddr addr, MemTxAttrs attrs, - if (len > 0) { - rcu_read_lock(); - l = len; -- mr = address_space_translate(as, addr, &addr1, &l, true); -- result = address_space_write_continue(as, addr, attrs, buf, len, -- addr1, l, mr); -+ mr = flatview_translate(fv, addr, &addr1, &l, true); -+ result = flatview_write_continue(fv, addr, attrs, buf, len, -+ addr1, l, mr); - rcu_read_unlock(); - } - - return result; - } - -+MemTxResult address_space_write(AddressSpace *as, hwaddr addr, -+ MemTxAttrs attrs, -+ const uint8_t *buf, int len) -+{ -+ return flatview_write(address_space_to_flatview(as), addr, attrs, buf, len); -+} -+ - /* Called within RCU critical section. */ --MemTxResult address_space_read_continue(AddressSpace *as, hwaddr addr, -- MemTxAttrs attrs, uint8_t *buf, -- int len, hwaddr addr1, hwaddr l, -- MemoryRegion *mr) -+MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr, -+ MemTxAttrs attrs, uint8_t *buf, -+ int len, hwaddr addr1, hwaddr l, -+ MemoryRegion *mr) - { - uint8_t *ptr; - uint64_t val; -@@ -3028,14 +3039,14 @@ MemTxResult address_space_read_continue(AddressSpace *as, hwaddr addr, - } - - l = len; -- mr = address_space_translate(as, addr, &addr1, &l, false); -+ mr = flatview_translate(fv, addr, &addr1, &l, false); - } - - return result; - } - --MemTxResult address_space_read_full(AddressSpace *as, hwaddr addr, -- MemTxAttrs attrs, uint8_t *buf, int len) -+MemTxResult flatview_read_full(FlatView *fv, hwaddr addr, -+ MemTxAttrs attrs, uint8_t *buf, int len) - { - hwaddr l; - hwaddr addr1; -@@ -3045,25 +3056,33 @@ MemTxResult address_space_read_full(AddressSpace *as, hwaddr addr, - if (len > 0) { - rcu_read_lock(); - l = len; -- mr = address_space_translate(as, addr, &addr1, &l, false); -- result = address_space_read_continue(as, addr, attrs, buf, len, -- addr1, l, mr); -+ mr = flatview_translate(fv, addr, &addr1, &l, false); -+ result = flatview_read_continue(fv, addr, attrs, buf, len, -+ addr1, l, mr); - rcu_read_unlock(); - } - - return result; - } - --MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, MemTxAttrs attrs, -- uint8_t *buf, int len, bool is_write) -+static MemTxResult flatview_rw(FlatView *fv, hwaddr addr, MemTxAttrs attrs, -+ uint8_t *buf, int len, bool is_write) - { - if (is_write) { -- return address_space_write(as, addr, attrs, (uint8_t *)buf, len); -+ return flatview_write(fv, addr, attrs, (uint8_t *)buf, len); - } else { -- return address_space_read(as, addr, attrs, (uint8_t *)buf, len); -+ return flatview_read(fv, addr, attrs, (uint8_t *)buf, len); - } - } - -+MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, -+ MemTxAttrs attrs, uint8_t *buf, -+ int len, bool is_write) -+{ -+ return flatview_rw(address_space_to_flatview(as), -+ addr, attrs, buf, len, is_write); -+} -+ - void cpu_physical_memory_rw(hwaddr addr, uint8_t *buf, - int len, int is_write) - { -@@ -3221,7 +3240,8 @@ static void cpu_notify_map_clients(void) - qemu_mutex_unlock(&map_client_list_lock); - } - --bool address_space_access_valid(AddressSpace *as, hwaddr addr, int len, bool is_write) -+static bool flatview_access_valid(FlatView *fv, hwaddr addr, int len, -+ bool is_write) - { - MemoryRegion *mr; - hwaddr l, xlat; -@@ -3229,7 +3249,7 @@ bool address_space_access_valid(AddressSpace *as, hwaddr addr, int len, bool is_ - rcu_read_lock(); - while (len > 0) { - l = len; -- mr = address_space_translate(as, addr, &xlat, &l, is_write); -+ mr = flatview_translate(fv, addr, &xlat, &l, is_write); - if (!memory_access_is_direct(mr, is_write)) { - l = memory_access_size(mr, l, addr); - if (!memory_region_access_valid(mr, xlat, l, is_write)) { -@@ -3245,8 +3265,16 @@ bool address_space_access_valid(AddressSpace *as, hwaddr addr, int len, bool is_ - return true; - } - -+bool address_space_access_valid(AddressSpace *as, hwaddr addr, -+ int len, bool is_write) -+{ -+ return flatview_access_valid(address_space_to_flatview(as), -+ addr, len, is_write); -+} -+ - static hwaddr --address_space_extend_translation(AddressSpace *as, hwaddr addr, hwaddr target_len, -+flatview_extend_translation(FlatView *fv, hwaddr addr, -+ hwaddr target_len, - MemoryRegion *mr, hwaddr base, hwaddr len, - bool is_write) - { -@@ -3263,7 +3291,8 @@ address_space_extend_translation(AddressSpace *as, hwaddr addr, hwaddr target_le - } - - len = target_len; -- this_mr = address_space_translate(as, addr, &xlat, &len, is_write); -+ this_mr = flatview_translate(fv, addr, &xlat, -+ &len, is_write); - if (this_mr != mr || xlat != base + done) { - return done; - } -@@ -3286,6 +3315,7 @@ void *address_space_map(AddressSpace *as, - hwaddr l, xlat; - MemoryRegion *mr; - void *ptr; -+ FlatView *fv = address_space_to_flatview(as); - - if (len == 0) { - return NULL; -@@ -3293,7 +3323,7 @@ void *address_space_map(AddressSpace *as, - - l = len; - rcu_read_lock(); -- mr = address_space_translate(as, addr, &xlat, &l, is_write); -+ mr = flatview_translate(fv, addr, &xlat, &l, is_write); - - if (!memory_access_is_direct(mr, is_write)) { - if (atomic_xchg(&bounce.in_use, true)) { -@@ -3309,7 +3339,7 @@ void *address_space_map(AddressSpace *as, - memory_region_ref(mr); - bounce.mr = mr; - if (!is_write) { -- address_space_read(as, addr, MEMTXATTRS_UNSPECIFIED, -+ flatview_read(fv, addr, MEMTXATTRS_UNSPECIFIED, - bounce.buffer, l); - } - -@@ -3320,7 +3350,8 @@ void *address_space_map(AddressSpace *as, - - - memory_region_ref(mr); -- *plen = address_space_extend_translation(as, addr, len, mr, xlat, l, is_write); -+ *plen = flatview_extend_translation(fv, addr, len, mr, xlat, -+ l, is_write); - ptr = qemu_ram_ptr_length(mr->ram_block, xlat, plen, true); - rcu_read_unlock(); - -diff --git a/hw/intc/openpic_kvm.c b/hw/intc/openpic_kvm.c -index 0518e01..fa83420 100644 ---- a/hw/intc/openpic_kvm.c -+++ b/hw/intc/openpic_kvm.c -@@ -124,7 +124,7 @@ static void kvm_openpic_region_add(MemoryListener *listener, - uint64_t reg_base; - int ret; - -- if (section->address_space != &address_space_memory) { -+ if (section->fv != address_space_to_flatview(&address_space_memory)) { - abort(); - } - -diff --git a/include/exec/memory-internal.h b/include/exec/memory-internal.h -index 6e08eda..1cf8ad9 100644 ---- a/include/exec/memory-internal.h -+++ b/include/exec/memory-internal.h -@@ -27,7 +27,7 @@ extern const MemoryRegionOps unassigned_mem_ops; - bool memory_region_access_valid(MemoryRegion *mr, hwaddr addr, - unsigned size, bool is_write); - --void mem_add(AddressSpace *as, FlatView *fv, MemoryRegionSection *section); -+void mem_add(FlatView *fv, MemoryRegionSection *section); - AddressSpaceDispatch *mem_begin(AddressSpace *as); - void mem_commit(AddressSpaceDispatch *d); - -diff --git a/include/exec/memory.h b/include/exec/memory.h -index 8f26d63..6715551 100644 ---- a/include/exec/memory.h -+++ b/include/exec/memory.h -@@ -48,6 +48,7 @@ - - typedef struct MemoryRegionOps MemoryRegionOps; - typedef struct MemoryRegionMmio MemoryRegionMmio; -+typedef struct FlatView FlatView; - - struct MemoryRegionMmio { - CPUReadMemoryFunc *read[3]; -@@ -330,6 +331,8 @@ struct AddressSpace { - QTAILQ_ENTRY(AddressSpace) address_spaces_link; - }; - -+FlatView *address_space_to_flatview(AddressSpace *as); -+ - /** - * MemoryRegionSection: describes a fragment of a #MemoryRegion - * -@@ -343,7 +346,7 @@ struct AddressSpace { - */ - struct MemoryRegionSection { - MemoryRegion *mr; -- AddressSpace *address_space; -+ FlatView *fv; - hwaddr offset_within_region; - Int128 size; - hwaddr offset_within_address_space; -@@ -1852,9 +1855,17 @@ IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr, - * @len: pointer to length - * @is_write: indicates the transfer direction - */ --MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr, -- hwaddr *xlat, hwaddr *len, -- bool is_write); -+MemoryRegion *flatview_translate(FlatView *fv, -+ hwaddr addr, hwaddr *xlat, -+ hwaddr *len, bool is_write); -+ -+static inline MemoryRegion *address_space_translate(AddressSpace *as, -+ hwaddr addr, hwaddr *xlat, -+ hwaddr *len, bool is_write) -+{ -+ return flatview_translate(address_space_to_flatview(as), -+ addr, xlat, len, is_write); -+} - - /* address_space_access_valid: check for validity of accessing an address - * space range -@@ -1905,12 +1916,13 @@ void address_space_unmap(AddressSpace *as, void *buffer, hwaddr len, - - - /* Internal functions, part of the implementation of address_space_read. */ --MemTxResult address_space_read_continue(AddressSpace *as, hwaddr addr, -- MemTxAttrs attrs, uint8_t *buf, -- int len, hwaddr addr1, hwaddr l, -- MemoryRegion *mr); --MemTxResult address_space_read_full(AddressSpace *as, hwaddr addr, -- MemTxAttrs attrs, uint8_t *buf, int len); -+MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr, -+ MemTxAttrs attrs, uint8_t *buf, -+ int len, hwaddr addr1, hwaddr l, -+ MemoryRegion *mr); -+ -+MemTxResult flatview_read_full(FlatView *fv, hwaddr addr, -+ MemTxAttrs attrs, uint8_t *buf, int len); - void *qemu_map_ram_ptr(RAMBlock *ram_block, ram_addr_t addr); - - static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write) -@@ -1937,8 +1949,8 @@ static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write) - * @buf: buffer with the data transferred - */ - static inline __attribute__((__always_inline__)) --MemTxResult address_space_read(AddressSpace *as, hwaddr addr, MemTxAttrs attrs, -- uint8_t *buf, int len) -+MemTxResult flatview_read(FlatView *fv, hwaddr addr, MemTxAttrs attrs, -+ uint8_t *buf, int len) - { - MemTxResult result = MEMTX_OK; - hwaddr l, addr1; -@@ -1949,22 +1961,29 @@ MemTxResult address_space_read(AddressSpace *as, hwaddr addr, MemTxAttrs attrs, - if (len) { - rcu_read_lock(); - l = len; -- mr = address_space_translate(as, addr, &addr1, &l, false); -+ mr = flatview_translate(fv, addr, &addr1, &l, false); - if (len == l && memory_access_is_direct(mr, false)) { - ptr = qemu_map_ram_ptr(mr->ram_block, addr1); - memcpy(buf, ptr, len); - } else { -- result = address_space_read_continue(as, addr, attrs, buf, len, -- addr1, l, mr); -+ result = flatview_read_continue(fv, addr, attrs, buf, len, -+ addr1, l, mr); - } - rcu_read_unlock(); - } - } else { -- result = address_space_read_full(as, addr, attrs, buf, len); -+ result = flatview_read_full(fv, addr, attrs, buf, len); - } - return result; - } - -+static inline MemTxResult address_space_read(AddressSpace *as, hwaddr addr, -+ MemTxAttrs attrs, uint8_t *buf, -+ int len) -+{ -+ return flatview_read(address_space_to_flatview(as), addr, attrs, buf, len); -+} -+ - /** - * address_space_read_cached: read from a cached RAM region - * -diff --git a/memory.c b/memory.c -index 41e2e67..6678a53 100644 ---- a/memory.c -+++ b/memory.c -@@ -154,7 +154,8 @@ enum ListenerDirection { Forward, Reverse }; - /* No need to ref/unref .mr, the FlatRange keeps it alive. */ - #define MEMORY_LISTENER_UPDATE_REGION(fr, as, dir, callback, _args...) \ - do { \ -- MemoryRegionSection mrs = section_from_flat_range(fr, as); \ -+ MemoryRegionSection mrs = section_from_flat_range(fr, \ -+ address_space_to_flatview(as)); \ - MEMORY_LISTENER_CALL(as, callback, dir, &mrs, ##_args); \ - } while(0) - -@@ -208,7 +209,6 @@ static bool memory_region_ioeventfd_equal(MemoryRegionIoeventfd a, - } - - typedef struct FlatRange FlatRange; --typedef struct FlatView FlatView; - - /* Range of memory in the global map. Addresses are absolute. */ - struct FlatRange { -@@ -238,11 +238,11 @@ typedef struct AddressSpaceOps AddressSpaceOps; - for (var = (view)->ranges; var < (view)->ranges + (view)->nr; ++var) - - static inline MemoryRegionSection --section_from_flat_range(FlatRange *fr, AddressSpace *as) -+section_from_flat_range(FlatRange *fr, FlatView *fv) - { - return (MemoryRegionSection) { - .mr = fr->mr, -- .address_space = as, -+ .fv = fv, - .offset_within_region = fr->offset_in_region, - .size = fr->addr.size, - .offset_within_address_space = int128_get64(fr->addr.start), -@@ -312,7 +312,7 @@ static void flatview_unref(FlatView *view) - } - } - --static FlatView *address_space_to_flatview(AddressSpace *as) -+FlatView *address_space_to_flatview(AddressSpace *as) - { - return atomic_rcu_read(&as->current_map); - } -@@ -760,7 +760,7 @@ static void address_space_add_del_ioeventfds(AddressSpace *as, - fds_new[inew]))) { - fd = &fds_old[iold]; - section = (MemoryRegionSection) { -- .address_space = as, -+ .fv = address_space_to_flatview(as), - .offset_within_address_space = int128_get64(fd->addr.start), - .size = fd->addr.size, - }; -@@ -773,7 +773,7 @@ static void address_space_add_del_ioeventfds(AddressSpace *as, - fds_old[iold]))) { - fd = &fds_new[inew]; - section = (MemoryRegionSection) { -- .address_space = as, -+ .fv = address_space_to_flatview(as), - .offset_within_address_space = int128_get64(fd->addr.start), - .size = fd->addr.size, - }; -@@ -793,7 +793,7 @@ static FlatView *address_space_get_flatview(AddressSpace *as) - - rcu_read_lock(); - do { -- view = atomic_rcu_read(&as->current_map); -+ view = address_space_to_flatview(as); - /* If somebody has replaced as->current_map concurrently, - * flatview_ref returns false. - */ -@@ -912,8 +912,8 @@ static void address_space_update_topology(AddressSpace *as) - new_view->dispatch = mem_begin(as); - for (i = 0; i < new_view->nr; i++) { - MemoryRegionSection mrs = -- section_from_flat_range(&new_view->ranges[i], as); -- mem_add(as, new_view, &mrs); -+ section_from_flat_range(&new_view->ranges[i], new_view); -+ mem_add(new_view, &mrs); - } - mem_commit(new_view->dispatch); - -@@ -1869,7 +1869,7 @@ void memory_region_sync_dirty_bitmap(MemoryRegion *mr) - view = address_space_get_flatview(as); - FOR_EACH_FLAT_RANGE(fr, view) { - if (fr->mr == mr) { -- MemoryRegionSection mrs = section_from_flat_range(fr, as); -+ MemoryRegionSection mrs = section_from_flat_range(fr, view); - listener->log_sync(listener, &mrs); - } - } -@@ -1972,7 +1972,7 @@ static void memory_region_update_coalesced_range_as(MemoryRegion *mr, AddressSpa - FOR_EACH_FLAT_RANGE(fr, view) { - if (fr->mr == mr) { - section = (MemoryRegionSection) { -- .address_space = as, -+ .fv = view, - .offset_within_address_space = int128_get64(fr->addr.start), - .size = fr->addr.size, - }; -@@ -2323,7 +2323,7 @@ static MemoryRegionSection memory_region_find_rcu(MemoryRegion *mr, - } - range = addrrange_make(int128_make64(addr), int128_make64(size)); - -- view = atomic_rcu_read(&as->current_map); -+ view = address_space_to_flatview(as); - fr = flatview_lookup(view, range); - if (!fr) { - return ret; -@@ -2334,7 +2334,7 @@ static MemoryRegionSection memory_region_find_rcu(MemoryRegion *mr, - } - - ret.mr = fr->mr; -- ret.address_space = as; -+ ret.fv = view; - range = addrrange_intersection(range, fr->addr); - ret.offset_within_region = fr->offset_in_region; - ret.offset_within_region += int128_get64(int128_sub(range.start, -@@ -2383,7 +2383,8 @@ void memory_global_dirty_log_sync(void) - view = address_space_get_flatview(as); - FOR_EACH_FLAT_RANGE(fr, view) { - if (fr->dirty_log_mask) { -- MemoryRegionSection mrs = section_from_flat_range(fr, as); -+ MemoryRegionSection mrs = section_from_flat_range(fr, view); -+ - listener->log_sync(listener, &mrs); - } - } -@@ -2468,7 +2469,7 @@ static void listener_add_address_space(MemoryListener *listener, - FOR_EACH_FLAT_RANGE(fr, view) { - MemoryRegionSection section = { - .mr = fr->mr, -- .address_space = as, -+ .fv = view, - .offset_within_region = fr->offset_in_region, - .size = fr->addr.size, - .offset_within_address_space = int128_get64(fr->addr.start), --- -1.8.3.1 - diff --git a/SOURCES/kvm-memory-avoid-resurrection-of-dead-FlatViews.patch b/SOURCES/kvm-memory-avoid-resurrection-of-dead-FlatViews.patch deleted file mode 100644 index 3cb4595..0000000 --- a/SOURCES/kvm-memory-avoid-resurrection-of-dead-FlatViews.patch +++ /dev/null @@ -1,115 +0,0 @@ -From 7de5d186bd03511cd5fa4dcd32876efb034f1dd0 Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Thu, 16 Nov 2017 03:07:13 +0100 -Subject: [PATCH 09/30] memory: avoid "resurrection" of dead FlatViews - -RH-Author: David Gibson -Message-id: <20171116030732.8560-4-dgibson@redhat.com> -Patchwork-id: 77691 -O-Subject: [PATCH 03/22] memory: avoid "resurrection" of dead FlatViews -Bugzilla: 1481593 -RH-Acked-by: Thomas Huth -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Eduardo Habkost -RH-Acked-by: Laurent Vivier - -From: Paolo Bonzini - -It's possible for address_space_get_flatview() as it currently stands -to cause a use-after-free for the returned FlatView, if the reference -count is incremented after the FlatView has been replaced by a writer: - - thread 1 thread 2 RCU thread - ------------------------------------------------------------- - rcu_read_lock - read as->current_map - set as->current_map - flatview_unref - '--> call_rcu - flatview_ref - [ref=1] - rcu_read_unlock - flatview_destroy - - -Since FlatViews are not updated very often, we can just detect the -situation using a new atomic op atomic_fetch_inc_nonzero, similar to -Linux's atomic_inc_not_zero, which performs the refcount increment only if -it hasn't already hit zero. This is similar to Linux commit de09a9771a53 -("CRED: Fix get_task_cred() and task_state() to not resurrect dead -credentials", 2010-07-29). - -Signed-off-by: Paolo Bonzini -(cherry picked from commit 447b0d0b9ee8a0ac216c3186e0f3c427a1001f0c) - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - docs/devel/atomics.txt | 1 + - include/qemu/atomic.h | 8 ++++++++ - memory.c | 12 ++++++++---- - 3 files changed, 17 insertions(+), 4 deletions(-) - -diff --git a/docs/devel/atomics.txt b/docs/devel/atomics.txt -index 048e5f2..10c5fa3 100644 ---- a/docs/devel/atomics.txt -+++ b/docs/devel/atomics.txt -@@ -64,6 +64,7 @@ operations: - typeof(*ptr) atomic_fetch_and(ptr, val) - typeof(*ptr) atomic_fetch_or(ptr, val) - typeof(*ptr) atomic_fetch_xor(ptr, val) -+ typeof(*ptr) atomic_fetch_inc_nonzero(ptr) - typeof(*ptr) atomic_xchg(ptr, val) - typeof(*ptr) atomic_cmpxchg(ptr, old, new) - -diff --git a/include/qemu/atomic.h b/include/qemu/atomic.h -index b6b62fb..d73c9e1 100644 ---- a/include/qemu/atomic.h -+++ b/include/qemu/atomic.h -@@ -442,4 +442,12 @@ - } while(0) - #endif - -+#define atomic_fetch_inc_nonzero(ptr) ({ \ -+ typeof_strip_qual(*ptr) _oldn = atomic_read(ptr); \ -+ while (_oldn && atomic_cmpxchg(ptr, _oldn, _oldn + 1) != _oldn) { \ -+ _oldn = atomic_read(ptr); \ -+ } \ -+ _oldn; \ -+}) -+ - #endif /* QEMU_ATOMIC_H */ -diff --git a/memory.c b/memory.c -index c0adc35..ca160de 100644 ---- a/memory.c -+++ b/memory.c -@@ -294,9 +294,9 @@ static void flatview_destroy(FlatView *view) - g_free(view); - } - --static void flatview_ref(FlatView *view) -+static bool flatview_ref(FlatView *view) - { -- atomic_inc(&view->ref); -+ return atomic_fetch_inc_nonzero(&view->ref) > 0; - } - - static void flatview_unref(FlatView *view) -@@ -772,8 +772,12 @@ static FlatView *address_space_get_flatview(AddressSpace *as) - FlatView *view; - - rcu_read_lock(); -- view = atomic_rcu_read(&as->current_map); -- flatview_ref(view); -+ do { -+ view = atomic_rcu_read(&as->current_map); -+ /* If somebody has replaced as->current_map concurrently, -+ * flatview_ref returns false. -+ */ -+ } while (!flatview_ref(view)); - rcu_read_unlock(); - return view; - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-memory-exec-Expose-all-memory-block-related-flags.patch b/SOURCES/kvm-memory-exec-Expose-all-memory-block-related-flags.patch new file mode 100644 index 0000000..27652f7 --- /dev/null +++ b/SOURCES/kvm-memory-exec-Expose-all-memory-block-related-flags.patch @@ -0,0 +1,99 @@ +From dfca592a8a3fb1e781775020961ed16b8aea258e Mon Sep 17 00:00:00 2001 +From: "plai@redhat.com" +Date: Fri, 31 Aug 2018 16:25:53 +0200 +Subject: [PATCH 11/29] memory, exec: Expose all memory block related flags. + +RH-Author: plai@redhat.com +Message-id: <1535732759-22481-4-git-send-email-plai@redhat.com> +Patchwork-id: 82006 +O-Subject: [RHEL7.6 PATCH BZ 1539280 3/9] memory, exec: Expose all memory block related flags. +Bugzilla: 1539280 +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Pankaj Gupta +RH-Acked-by: Miroslav Rezanina + +From: Junyan He + +We need to use these flags in other files rather than just in exec.c, +For example, RAM_SHARED should be used when create a ram block from file. +We expose them the exec/memory.h + +Signed-off-by: Junyan He +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Igor Mammedov +Reviewed-by: Richard Henderson +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit b0e5de93811077254a536c23b713b49e12efb742) +Signed-off-by: Paul Lai +Signed-off-by: Miroslav Rezanina +--- + exec.c | 20 -------------------- + include/exec/memory.h | 20 ++++++++++++++++++++ + 2 files changed, 20 insertions(+), 20 deletions(-) + +diff --git a/exec.c b/exec.c +index 7323d39..f21be9c 100644 +--- a/exec.c ++++ b/exec.c +@@ -87,26 +87,6 @@ AddressSpace address_space_memory; + + MemoryRegion io_mem_rom, io_mem_notdirty; + static MemoryRegion io_mem_unassigned; +- +-/* RAM is pre-allocated and passed into qemu_ram_alloc_from_ptr */ +-#define RAM_PREALLOC (1 << 0) +- +-/* RAM is mmap-ed with MAP_SHARED */ +-#define RAM_SHARED (1 << 1) +- +-/* Only a portion of RAM (used_length) is actually used, and migrated. +- * This used_length size can change across reboots. +- */ +-#define RAM_RESIZEABLE (1 << 2) +- +-/* UFFDIO_ZEROPAGE is available on this RAMBlock to atomically +- * zero the page and wake waiting processes. +- * (Set during postcopy) +- */ +-#define RAM_UF_ZEROPAGE (1 << 3) +- +-/* RAM can be migrated */ +-#define RAM_MIGRATABLE (1 << 4) + #endif + + #ifdef TARGET_PAGE_BITS_VARY +diff --git a/include/exec/memory.h b/include/exec/memory.h +index 31eae0a..db46501 100644 +--- a/include/exec/memory.h ++++ b/include/exec/memory.h +@@ -102,6 +102,26 @@ struct IOMMUNotifier { + }; + typedef struct IOMMUNotifier IOMMUNotifier; + ++/* RAM is pre-allocated and passed into qemu_ram_alloc_from_ptr */ ++#define RAM_PREALLOC (1 << 0) ++ ++/* RAM is mmap-ed with MAP_SHARED */ ++#define RAM_SHARED (1 << 1) ++ ++/* Only a portion of RAM (used_length) is actually used, and migrated. ++ * This used_length size can change across reboots. ++ */ ++#define RAM_RESIZEABLE (1 << 2) ++ ++/* UFFDIO_ZEROPAGE is available on this RAMBlock to atomically ++ * zero the page and wake waiting processes. ++ * (Set during postcopy) ++ */ ++#define RAM_UF_ZEROPAGE (1 << 3) ++ ++/* RAM can be migrated */ ++#define RAM_MIGRATABLE (1 << 4) ++ + static inline void iommu_notifier_init(IOMMUNotifier *n, IOMMUNotify fn, + IOMMUNotifierFlag flags, + hwaddr start, hwaddr end) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-memory-exec-switch-file-ram-allocation-functions-to-.patch b/SOURCES/kvm-memory-exec-switch-file-ram-allocation-functions-to-.patch new file mode 100644 index 0000000..57c895b --- /dev/null +++ b/SOURCES/kvm-memory-exec-switch-file-ram-allocation-functions-to-.patch @@ -0,0 +1,234 @@ +From 754dd8f2bfcfd5c98710e910f6343b32af7cd3af Mon Sep 17 00:00:00 2001 +From: "plai@redhat.com" +Date: Fri, 31 Aug 2018 16:25:54 +0200 +Subject: [PATCH 12/29] memory, exec: switch file ram allocation functions to + 'flags' parameters + +RH-Author: plai@redhat.com +Message-id: <1535732759-22481-5-git-send-email-plai@redhat.com> +Patchwork-id: 82005 +O-Subject: [RHEL7.6 PATCH BZ 1539280 4/9] memory, exec: switch file ram allocation functions to 'flags' parameters +Bugzilla: 1539280 +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Pankaj Gupta +RH-Acked-by: Miroslav Rezanina + +From: Junyan He + +As more flag parameters besides the existing 'share' are going to be +added to following functions +memory_region_init_ram_from_file +qemu_ram_alloc_from_fd +qemu_ram_alloc_from_file +let's switch them to use the 'flags' parameters so as to ease future +flag additions. + +The existing 'share' flag is converted to the RAM_SHARED bit in ram_flags, +and other flag bits are ignored by above functions right now. + +Signed-off-by: Junyan He +Signed-off-by: Haozhong Zhang +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Igor Mammedov +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Richard Henderson +(cherry picked from commit cbfc01710362f3de6fca3010a17b0e1c866fc181) +Signed-off-by: Paul Lai + +Resolved Conflicts: + include/exec/ram_addr.h + +Signed-off-by: Miroslav Rezanina +--- + backends/hostmem-file.c | 3 ++- + exec.c | 10 +++++----- + include/exec/memory.h | 7 +++++-- + include/exec/ram_addr.h | 25 +++++++++++++++++++++++-- + memory.c | 8 +++++--- + numa.c | 2 +- + 6 files changed, 41 insertions(+), 14 deletions(-) + +diff --git a/backends/hostmem-file.c b/backends/hostmem-file.c +index 134b08d..34c68bb 100644 +--- a/backends/hostmem-file.c ++++ b/backends/hostmem-file.c +@@ -58,7 +58,8 @@ file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp) + path = object_get_canonical_path(OBJECT(backend)); + memory_region_init_ram_from_file(&backend->mr, OBJECT(backend), + path, +- backend->size, fb->align, backend->share, ++ backend->size, fb->align, ++ backend->share ? RAM_SHARED : 0, + fb->mem_path, errp); + g_free(path); + } +diff --git a/exec.c b/exec.c +index f21be9c..295142b 100644 +--- a/exec.c ++++ b/exec.c +@@ -2038,7 +2038,7 @@ static void ram_block_add(RAMBlock *new_block, Error **errp, bool shared) + + #ifdef __linux__ + RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr, +- bool share, int fd, ++ uint32_t ram_flags, int fd, + Error **errp) + { + RAMBlock *new_block; +@@ -2080,14 +2080,14 @@ RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr, + new_block->mr = mr; + new_block->used_length = size; + new_block->max_length = size; +- new_block->flags = share ? RAM_SHARED : 0; ++ new_block->flags = ram_flags; + new_block->host = file_ram_alloc(new_block, size, fd, !file_size, errp); + if (!new_block->host) { + g_free(new_block); + return NULL; + } + +- ram_block_add(new_block, &local_err, share); ++ ram_block_add(new_block, &local_err, ram_flags & RAM_SHARED); + if (local_err) { + g_free(new_block); + error_propagate(errp, local_err); +@@ -2099,7 +2099,7 @@ RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr, + + + RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr, +- bool share, const char *mem_path, ++ uint32_t ram_flags, const char *mem_path, + Error **errp) + { + int fd; +@@ -2111,7 +2111,7 @@ RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr, + return NULL; + } + +- block = qemu_ram_alloc_from_fd(size, mr, share, fd, errp); ++ block = qemu_ram_alloc_from_fd(size, mr, ram_flags, fd, errp); + if (!block) { + if (created) { + unlink(mem_path); +diff --git a/include/exec/memory.h b/include/exec/memory.h +index db46501..b3abe61 100644 +--- a/include/exec/memory.h ++++ b/include/exec/memory.h +@@ -527,6 +527,7 @@ void memory_region_init_resizeable_ram(MemoryRegion *mr, + void *host), + Error **errp); + #ifdef __linux__ ++ + /** + * memory_region_init_ram_from_file: Initialize RAM memory region with a + * mmap-ed backend. +@@ -538,7 +539,9 @@ void memory_region_init_resizeable_ram(MemoryRegion *mr, + * @size: size of the region. + * @align: alignment of the region base address; if 0, the default alignment + * (getpagesize()) will be used. +- * @share: %true if memory must be mmaped with the MAP_SHARED flag ++ * @ram_flags: Memory region features: ++ * - RAM_SHARED: memory must be mmaped with the MAP_SHARED flag ++ * Other bits are ignored now. + * @path: the path in which to allocate the RAM. + * @errp: pointer to Error*, to store an error if it happens. + * +@@ -550,7 +553,7 @@ void memory_region_init_ram_from_file(MemoryRegion *mr, + const char *name, + uint64_t size, + uint64_t align, +- bool share, ++ uint32_t ram_flags, + const char *path, + Error **errp); + +diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h +index cf2446a..67e163e 100644 +--- a/include/exec/ram_addr.h ++++ b/include/exec/ram_addr.h +@@ -72,12 +72,33 @@ static inline unsigned long int ramblock_recv_bitmap_offset(void *host_addr, + + long qemu_getrampagesize(void); + unsigned long last_ram_page(void); ++ ++/** ++ * qemu_ram_alloc_from_file, ++ * qemu_ram_alloc_from_fd: Allocate a ram block from the specified backing ++ * file or device ++ * ++ * Parameters: ++ * @size: the size in bytes of the ram block ++ * @mr: the memory region where the ram block is ++ * @ram_flags: specify the properties of the ram block, which can be one ++ * or bit-or of following values ++ * - RAM_SHARED: mmap the backing file or device with MAP_SHARED ++ * Other bits are ignored. ++ * @mem_path or @fd: specify the backing file or device ++ * @errp: pointer to Error*, to store an error if it happens ++ * ++ * Return: ++ * On success, return a pointer to the ram block. ++ * On failure, return NULL. ++ */ + RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr, +- bool share, const char *mem_path, ++ uint32_t ram_flags, const char *mem_path, + Error **errp); + RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr, +- bool share, int fd, ++ uint32_t ram_flags, int fd, + Error **errp); ++ + RAMBlock *qemu_ram_alloc_from_ptr(ram_addr_t size, void *host, + MemoryRegion *mr, Error **errp); + RAMBlock *qemu_ram_alloc(ram_addr_t size, bool share, MemoryRegion *mr, +diff --git a/memory.c b/memory.c +index e70b64b..7b47f53 100644 +--- a/memory.c ++++ b/memory.c +@@ -1552,7 +1552,7 @@ void memory_region_init_ram_from_file(MemoryRegion *mr, + const char *name, + uint64_t size, + uint64_t align, +- bool share, ++ uint32_t ram_flags, + const char *path, + Error **errp) + { +@@ -1561,7 +1561,7 @@ void memory_region_init_ram_from_file(MemoryRegion *mr, + mr->terminates = true; + mr->destructor = memory_region_destructor_ram; + mr->align = align; +- mr->ram_block = qemu_ram_alloc_from_file(size, mr, share, path, errp); ++ mr->ram_block = qemu_ram_alloc_from_file(size, mr, ram_flags, path, errp); + mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0; + } + +@@ -1577,7 +1577,9 @@ void memory_region_init_ram_from_fd(MemoryRegion *mr, + mr->ram = true; + mr->terminates = true; + mr->destructor = memory_region_destructor_ram; +- mr->ram_block = qemu_ram_alloc_from_fd(size, mr, share, fd, errp); ++ mr->ram_block = qemu_ram_alloc_from_fd(size, mr, ++ share ? RAM_SHARED : 0, ++ fd, errp); + mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0; + } + #endif +diff --git a/numa.c b/numa.c +index bb8f773..e78fba5 100644 +--- a/numa.c ++++ b/numa.c +@@ -456,7 +456,7 @@ static void allocate_system_memory_nonnuma(MemoryRegion *mr, Object *owner, + if (mem_path) { + #ifdef __linux__ + Error *err = NULL; +- memory_region_init_ram_from_file(mr, owner, name, ram_size, 0, false, ++ memory_region_init_ram_from_file(mr, owner, name, ram_size, 0, 0, + mem_path, &err); + if (err) { + error_report_err(err); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-memory-inline-some-performance-sensitive-accessors.patch b/SOURCES/kvm-memory-inline-some-performance-sensitive-accessors.patch deleted file mode 100644 index eeff6ac..0000000 --- a/SOURCES/kvm-memory-inline-some-performance-sensitive-accessors.patch +++ /dev/null @@ -1,152 +0,0 @@ -From 30484611dd815207d249e2034b976ac05753487d Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Thu, 8 Mar 2018 15:58:14 +0100 -Subject: [PATCH 01/17] memory: inline some performance-sensitive accessors - -RH-Author: Paolo Bonzini -Message-id: <20180308155819.20598-2-pbonzini@redhat.com> -Patchwork-id: 79193 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 1/6] memory: inline some performance-sensitive accessors -Bugzilla: 1554930 -RH-Acked-by: Cornelia Huck -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier - -These accessors are called from inlined functions, and the call sequence -is much more expensive than just inlining the access. Move the -struct declaration to memory-internal.h so that exec.c and memory.c -can both use an inline function. - -Reviewed-by: Alexey Kardashevskiy -Signed-off-by: Paolo Bonzini -(cherry pick from commit 785a507ec78bbda1c346f3d3593e5a58b62e73ef) - -Signed-off-by: Miroslav Rezanina ---- - include/exec/memory-internal.h | 13 +++++++++---- - include/exec/memory.h | 22 +++++++++++++++++++++- - memory.c | 30 ------------------------------ - 3 files changed, 30 insertions(+), 35 deletions(-) - -diff --git a/include/exec/memory-internal.h b/include/exec/memory-internal.h -index 647e9bd..fca523f 100644 ---- a/include/exec/memory-internal.h -+++ b/include/exec/memory-internal.h -@@ -20,7 +20,15 @@ - #define MEMORY_INTERNAL_H - - #ifndef CONFIG_USER_ONLY --typedef struct AddressSpaceDispatch AddressSpaceDispatch; -+static inline AddressSpaceDispatch *flatview_to_dispatch(FlatView *fv) -+{ -+ return fv->dispatch; -+} -+ -+static inline AddressSpaceDispatch *address_space_to_dispatch(AddressSpace *as) -+{ -+ return flatview_to_dispatch(address_space_to_flatview(as)); -+} - - extern const MemoryRegionOps unassigned_mem_ops; - -@@ -30,9 +38,6 @@ bool memory_region_access_valid(MemoryRegion *mr, hwaddr addr, - void flatview_add_to_dispatch(FlatView *fv, MemoryRegionSection *section); - AddressSpaceDispatch *address_space_dispatch_new(FlatView *fv); - void address_space_dispatch_compact(AddressSpaceDispatch *d); -- --AddressSpaceDispatch *address_space_to_dispatch(AddressSpace *as); --AddressSpaceDispatch *flatview_to_dispatch(FlatView *fv); - void address_space_dispatch_free(AddressSpaceDispatch *d); - - void mtree_print_dispatch(fprintf_function mon, void *f, -diff --git a/include/exec/memory.h b/include/exec/memory.h -index b100df6..3df0dcc 100644 ---- a/include/exec/memory.h -+++ b/include/exec/memory.h -@@ -328,7 +328,27 @@ struct AddressSpace { - QTAILQ_ENTRY(AddressSpace) address_spaces_link; - }; - --FlatView *address_space_to_flatview(AddressSpace *as); -+typedef struct AddressSpaceDispatch AddressSpaceDispatch; -+typedef struct FlatRange FlatRange; -+ -+/* Flattened global view of current active memory hierarchy. Kept in sorted -+ * order. -+ */ -+struct FlatView { -+ struct rcu_head rcu; -+ unsigned ref; -+ FlatRange *ranges; -+ unsigned nr; -+ unsigned nr_allocated; -+ struct AddressSpaceDispatch *dispatch; -+ MemoryRegion *root; -+}; -+ -+static inline FlatView *address_space_to_flatview(AddressSpace *as) -+{ -+ return atomic_rcu_read(&as->current_map); -+} -+ - - /** - * MemoryRegionSection: describes a fragment of a #MemoryRegion -diff --git a/memory.c b/memory.c -index a1f1e68..5a91b9b 100644 ---- a/memory.c -+++ b/memory.c -@@ -210,8 +210,6 @@ static bool memory_region_ioeventfd_equal(MemoryRegionIoeventfd a, - && !memory_region_ioeventfd_before(b, a); - } - --typedef struct FlatRange FlatRange; -- - /* Range of memory in the global map. Addresses are absolute. */ - struct FlatRange { - MemoryRegion *mr; -@@ -222,19 +220,6 @@ struct FlatRange { - bool readonly; - }; - --/* Flattened global view of current active memory hierarchy. Kept in sorted -- * order. -- */ --struct FlatView { -- struct rcu_head rcu; -- unsigned ref; -- FlatRange *ranges; -- unsigned nr; -- unsigned nr_allocated; -- struct AddressSpaceDispatch *dispatch; -- MemoryRegion *root; --}; -- - typedef struct AddressSpaceOps AddressSpaceOps; - - #define FOR_EACH_FLAT_RANGE(var, view) \ -@@ -322,21 +307,6 @@ static void flatview_unref(FlatView *view) - } - } - --FlatView *address_space_to_flatview(AddressSpace *as) --{ -- return atomic_rcu_read(&as->current_map); --} -- --AddressSpaceDispatch *flatview_to_dispatch(FlatView *fv) --{ -- return fv->dispatch; --} -- --AddressSpaceDispatch *address_space_to_dispatch(AddressSpace *as) --{ -- return flatview_to_dispatch(address_space_to_flatview(as)); --} -- - static bool can_merge(FlatRange *r1, FlatRange *r2) - { - return int128_eq(addrrange_end(r1->addr), r2->addr.start) --- -1.8.3.1 - diff --git a/SOURCES/kvm-memory-seek-FlatView-sharing-candidates-among-childr.patch b/SOURCES/kvm-memory-seek-FlatView-sharing-candidates-among-childr.patch deleted file mode 100644 index 357bde5..0000000 --- a/SOURCES/kvm-memory-seek-FlatView-sharing-candidates-among-childr.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 34644299c4e930a16b7e0a7725f69b7b83ca600e Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Thu, 16 Nov 2017 03:07:31 +0100 -Subject: [PATCH 27/30] memory: seek FlatView sharing candidates among children - subregions - -RH-Author: David Gibson -Message-id: <20171116030732.8560-22-dgibson@redhat.com> -Patchwork-id: 77708 -O-Subject: [PATCH 21/22] memory: seek FlatView sharing candidates among children subregions -Bugzilla: 1481593 -RH-Acked-by: Thomas Huth -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Eduardo Habkost -RH-Acked-by: Laurent Vivier - -From: Paolo Bonzini - -A container can be used instead of an alias to allow switching between -multiple subregions. In this case we cannot directly share the -subregions (since they only belong to a single parent), but if the -subregions are aliases we can in turn walk those. - -This is not enough to remove all source of quadratic FlatView creation, -but it enables sharing of the PCI bus master FlatViews (and their -AddressSpaceDispatch structures) across all PCI devices. For 112 -virtio-net-pci devices, boot time is reduced from 25 to 10 seconds and -memory consumption from 1.4 to 1 G. - -Signed-off-by: Paolo Bonzini -(cherry picked from commit e673ba9af9bf8fd8e0f44025ac738b8285b3ed27) - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - memory.c | 40 ++++++++++++++++++++++++++++++++++------ - 1 file changed, 34 insertions(+), 6 deletions(-) - -diff --git a/memory.c b/memory.c -index 8733efc..38eabe7 100644 ---- a/memory.c -+++ b/memory.c -@@ -733,12 +733,40 @@ static void render_memory_region(FlatView *view, - - static MemoryRegion *memory_region_get_flatview_root(MemoryRegion *mr) - { -- while (mr->alias && !mr->alias_offset && -- int128_ge(mr->size, mr->alias->size)) { -- /* The alias is included in its entirety. Use it as -- * the "real" root, so that we can share more FlatViews. -- */ -- mr = mr->alias; -+ while (mr->enabled) { -+ if (mr->alias) { -+ if (!mr->alias_offset && int128_ge(mr->size, mr->alias->size)) { -+ /* The alias is included in its entirety. Use it as -+ * the "real" root, so that we can share more FlatViews. -+ */ -+ mr = mr->alias; -+ continue; -+ } -+ } else if (!mr->terminates) { -+ unsigned int found = 0; -+ MemoryRegion *child, *next = NULL; -+ QTAILQ_FOREACH(child, &mr->subregions, subregions_link) { -+ if (child->enabled) { -+ if (++found > 1) { -+ next = NULL; -+ break; -+ } -+ if (!child->addr && int128_ge(mr->size, child->size)) { -+ /* A child is included in its entirety. If it's the only -+ * enabled one, use it in the hope of finding an alias down the -+ * way. This will also let us share FlatViews. -+ */ -+ next = child; -+ } -+ } -+ } -+ if (next) { -+ mr = next; -+ continue; -+ } -+ } -+ -+ break; - } - - return mr; --- -1.8.3.1 - diff --git a/SOURCES/kvm-memory-trace-FlatView-creation-and-destruction.patch b/SOURCES/kvm-memory-trace-FlatView-creation-and-destruction.patch deleted file mode 100644 index 38233e4..0000000 --- a/SOURCES/kvm-memory-trace-FlatView-creation-and-destruction.patch +++ /dev/null @@ -1,98 +0,0 @@ -From b546f002c27078f5aa7c29d85615e8b0b28a26b1 Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Thu, 16 Nov 2017 03:07:30 +0100 -Subject: [PATCH 26/30] memory: trace FlatView creation and destruction - -RH-Author: David Gibson -Message-id: <20171116030732.8560-21-dgibson@redhat.com> -Patchwork-id: 77706 -O-Subject: [PATCH 20/22] memory: trace FlatView creation and destruction -Bugzilla: 1481593 -RH-Acked-by: Thomas Huth -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Eduardo Habkost -RH-Acked-by: Laurent Vivier - -From: Paolo Bonzini - -Signed-off-by: Paolo Bonzini -(cherry picked from commit 02d9651d6a46479e9d70b72dca34e43605d06cda) - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - include/exec/memory.h | 1 - - include/qemu/typedefs.h | 1 + - memory.c | 3 +++ - trace-events | 3 +++ - 4 files changed, 7 insertions(+), 1 deletion(-) - -diff --git a/include/exec/memory.h b/include/exec/memory.h -index 8d772b9..b100df6 100644 ---- a/include/exec/memory.h -+++ b/include/exec/memory.h -@@ -48,7 +48,6 @@ - - typedef struct MemoryRegionOps MemoryRegionOps; - typedef struct MemoryRegionMmio MemoryRegionMmio; --typedef struct FlatView FlatView; - - struct MemoryRegionMmio { - CPUReadMemoryFunc *read[3]; -diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h -index 39bc835..d44dfc7 100644 ---- a/include/qemu/typedefs.h -+++ b/include/qemu/typedefs.h -@@ -30,6 +30,7 @@ typedef struct DisplaySurface DisplaySurface; - typedef struct DriveInfo DriveInfo; - typedef struct Error Error; - typedef struct EventNotifier EventNotifier; -+typedef struct FlatView FlatView; - typedef struct FWCfgEntry FWCfgEntry; - typedef struct FWCfgIoState FWCfgIoState; - typedef struct FWCfgMemState FWCfgMemState; -diff --git a/memory.c b/memory.c -index 93b4221..8733efc 100644 ---- a/memory.c -+++ b/memory.c -@@ -270,6 +270,7 @@ static FlatView *flatview_new(MemoryRegion *mr_root) - view->ref = 1; - view->root = mr_root; - memory_region_ref(mr_root); -+ trace_flatview_new(view, mr_root); - - return view; - } -@@ -295,6 +296,7 @@ static void flatview_destroy(FlatView *view) - { - int i; - -+ trace_flatview_destroy(view, view->root); - if (view->dispatch) { - address_space_dispatch_free(view->dispatch); - } -@@ -314,6 +316,7 @@ static bool flatview_ref(FlatView *view) - static void flatview_unref(FlatView *view) - { - if (atomic_fetch_dec(&view->ref) == 1) { -+ trace_flatview_destroy_rcu(view, view->root); - call_rcu(view, flatview_destroy, rcu); - } - } -diff --git a/trace-events b/trace-events -index 1f50f56..1d2eb5d 100644 ---- a/trace-events -+++ b/trace-events -@@ -64,6 +64,9 @@ memory_region_tb_read(int cpu_index, uint64_t addr, uint64_t value, unsigned siz - memory_region_tb_write(int cpu_index, uint64_t addr, uint64_t value, unsigned size) "cpu %d addr 0x%"PRIx64" value 0x%"PRIx64" size %u" - memory_region_ram_device_read(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u" - memory_region_ram_device_write(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u" -+flatview_new(FlatView *view, MemoryRegion *root) "%p (root %p)" -+flatview_destroy(FlatView *view, MemoryRegion *root) "%p (root %p)" -+flatview_destroy_rcu(FlatView *view, MemoryRegion *root) "%p (root %p)" - - ### Guest events, keep at bottom - --- -1.8.3.1 - diff --git a/SOURCES/kvm-migrate-HMP-migate_continue.patch b/SOURCES/kvm-migrate-HMP-migate_continue.patch deleted file mode 100644 index 9b97780..0000000 --- a/SOURCES/kvm-migrate-HMP-migate_continue.patch +++ /dev/null @@ -1,98 +0,0 @@ -From ca573248c7d3e8070722316b168f94b79fd75357 Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Wed, 25 Oct 2017 18:28:36 +0200 -Subject: [PATCH 17/19] migrate: HMP migate_continue - -RH-Author: Dr. David Alan Gilbert -Message-id: <20171025182838.31829-6-dgilbert@redhat.com> -Patchwork-id: 77440 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH 5/7] migrate: HMP migate_continue -Bugzilla: 1497120 -RH-Acked-by: Peter Xu -RH-Acked-by: Juan Quintela -RH-Acked-by: Miroslav Rezanina - -From: "Dr. David Alan Gilbert" - -HMP equivalent to the just added migrate-continue -Unpause a migrate paused at a given state. - -Signed-off-by: Dr. David Alan Gilbert -Reviewed-by: Peter Xu -Reviewed-by: Juan Quintela -Signed-off-by: Juan Quintela -(cherry picked from commit 94ae12cba4f18253e3cf5f9a70335e22870053b4) - Conflict: - Change in qapi_enum_parse parameters - -Signed-off-by: Miroslav Rezanina ---- - hmp-commands.hx | 12 ++++++++++++ - hmp.c | 14 ++++++++++++++ - hmp.h | 1 + - 3 files changed, 27 insertions(+) - -diff --git a/hmp-commands.hx b/hmp-commands.hx -index 5b4cf6b..c16d270 100644 ---- a/hmp-commands.hx -+++ b/hmp-commands.hx -@@ -979,7 +979,19 @@ STEXI - @item migrate_cancel - @findex migrate_cancel - Cancel the current VM migration. -+ETEXI - -+ { -+ .name = "migrate_continue", -+ .args_type = "state:s", -+ .params = "state", -+ .help = "Continue migration from the given paused state", -+ .cmd = hmp_migrate_continue, -+ }, -+STEXI -+@item migrate_continue @var{state} -+@findex migrate_continue -+Continue migration from the paused state @var{state} - ETEXI - - { -diff --git a/hmp.c b/hmp.c -index 5b6eeba..261c17b 100644 ---- a/hmp.c -+++ b/hmp.c -@@ -1493,6 +1493,20 @@ void hmp_migrate_cancel(Monitor *mon, const QDict *qdict) - qmp_migrate_cancel(NULL); - } - -+void hmp_migrate_continue(Monitor *mon, const QDict *qdict) -+{ -+ Error *err = NULL; -+ const char *state = qdict_get_str(qdict, "state"); -+ int val = qapi_enum_parse(MigrationStatus_lookup, state, -+ MIGRATION_STATUS__MAX, -1, &err); -+ -+ if (val >= 0) { -+ qmp_migrate_continue(val, &err); -+ } -+ -+ hmp_handle_error(mon, &err); -+} -+ - void hmp_migrate_incoming(Monitor *mon, const QDict *qdict) - { - Error *err = NULL; -diff --git a/hmp.h b/hmp.h -index 8d9cb29..8dc865d 100644 ---- a/hmp.h -+++ b/hmp.h -@@ -68,6 +68,7 @@ void hmp_savevm(Monitor *mon, const QDict *qdict); - void hmp_delvm(Monitor *mon, const QDict *qdict); - void hmp_info_snapshots(Monitor *mon, const QDict *qdict); - void hmp_migrate_cancel(Monitor *mon, const QDict *qdict); -+void hmp_migrate_continue(Monitor *mon, const QDict *qdict); - void hmp_migrate_incoming(Monitor *mon, const QDict *qdict); - void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict); - void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict); --- -1.8.3.1 - diff --git a/SOURCES/kvm-migration-Add-pause-before-switchover-capability.patch b/SOURCES/kvm-migration-Add-pause-before-switchover-capability.patch deleted file mode 100644 index b1aa903..0000000 --- a/SOURCES/kvm-migration-Add-pause-before-switchover-capability.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 13a626395dc1a35e7a7ab0a501a83c5647e3267a Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Wed, 25 Oct 2017 18:28:32 +0200 -Subject: [PATCH 13/19] migration: Add 'pause-before-switchover' capability - -RH-Author: Dr. David Alan Gilbert -Message-id: <20171025182838.31829-2-dgilbert@redhat.com> -Patchwork-id: 77435 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH 1/7] migration: Add 'pause-before-switchover' capability -Bugzilla: 1497120 -RH-Acked-by: Peter Xu -RH-Acked-by: Juan Quintela -RH-Acked-by: Miroslav Rezanina - -From: "Dr. David Alan Gilbert" - -When 'pause-before-switchover' is enabled, the outgoing migration -will pause before invalidating the block devices and serializing -the device state. -At this point the management layer gets the chance to clean up any -device jobs or other device users before the migration completes. - -Signed-off-by: Dr. David Alan Gilbert -Reviewed-by: Peter Xu -Reviewed-by: Juan Quintela -Signed-off-by: Juan Quintela -(cherry picked from commit 93fbd0314ec060ffaf90169a06d5737fa97ffb25) -Signed-off-by: Miroslav Rezanina - -Conflicts: - migration/migration.c - migration/migration.h - Differences with other flags added - qapi/migration.json - Still in qapi-schema.json for us ---- - migration/migration.c | 10 ++++++++++ - migration/migration.h | 1 + - qapi-schema.json | 5 ++++- - 3 files changed, 15 insertions(+), 1 deletion(-) - -diff --git a/migration/migration.c b/migration/migration.c -index c7b4d3d..d4356a4 100644 ---- a/migration/migration.c -+++ b/migration/migration.c -@@ -1426,6 +1426,16 @@ bool migrate_use_events(void) - return s->enabled_capabilities[MIGRATION_CAPABILITY_EVENTS]; - } - -+bool migrate_pause_before_switchover(void) -+{ -+ MigrationState *s; -+ -+ s = migrate_get_current(); -+ -+ return s->enabled_capabilities[ -+ MIGRATION_CAPABILITY_PAUSE_BEFORE_SWITCHOVER]; -+} -+ - int migrate_use_xbzrle(void) - { - MigrationState *s; -diff --git a/migration/migration.h b/migration/migration.h -index 8771ab0..2eebad8 100644 ---- a/migration/migration.h -+++ b/migration/migration.h -@@ -170,6 +170,7 @@ bool migrate_postcopy_ram(void); - bool migrate_zero_blocks(void); - - bool migrate_auto_converge(void); -+bool migrate_pause_before_switchover(void); - - int migrate_use_xbzrle(void); - int64_t migrate_xbzrle_cache_size(void); -diff --git a/qapi-schema.json b/qapi-schema.json -index 0591d9d..9b9ec9a 100644 ---- a/qapi-schema.json -+++ b/qapi-schema.json -@@ -919,12 +919,15 @@ - # @return-path: If enabled, migration will use the return path even - # for precopy. (since 2.10) - # -+# @pause-before-switchover: Pause outgoing migration before serialising device -+# state and before disabling block IO (since 2.11) -+# - # Since: 1.2 - ## - { 'enum': 'MigrationCapability', - 'data': ['xbzrle', 'rdma-pin-all', 'auto-converge', 'zero-blocks', - 'compress', 'events', 'postcopy-ram', 'x-colo', 'release-ram', -- 'block', 'return-path' ] } -+ 'block', 'return-path', 'pause-before-switchover' ] } - - ## - # @MigrationCapabilityStatus: --- -1.8.3.1 - diff --git a/SOURCES/kvm-migration-Add-pre-switchover-and-device-statuses.patch b/SOURCES/kvm-migration-Add-pre-switchover-and-device-statuses.patch deleted file mode 100644 index 20d75a7..0000000 --- a/SOURCES/kvm-migration-Add-pre-switchover-and-device-statuses.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 7d98216efe37db465e3819912a014086e33c3bdd Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Wed, 25 Oct 2017 18:28:33 +0200 -Subject: [PATCH 14/19] migration: Add 'pre-switchover' and 'device' statuses - -RH-Author: Dr. David Alan Gilbert -Message-id: <20171025182838.31829-3-dgilbert@redhat.com> -Patchwork-id: 77436 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH 2/7] migration: Add 'pre-switchover' and 'device' statuses -Bugzilla: 1497120 -RH-Acked-by: Peter Xu -RH-Acked-by: Juan Quintela -RH-Acked-by: Miroslav Rezanina - -From: "Dr. David Alan Gilbert" - -Add two statuses for use when the 'pause-before-switchover' -capability is enabled. - -'pre-switchover' is the state that we wait in for management -to allow us to continue. -'device' is the state we enter while serialising the devices -after management gives us the OK. - -Signed-off-by: Dr. David Alan Gilbert -Reviewed-by: Peter Xu -Reviewed-by: Juan Quintela -Signed-off-by: Juan Quintela -(cherry picked from commit 31e060774cf5c3b9945f6f16d6c18d6eae18e4d9) -Signed-off-by: Miroslav Rezanina - -Conflicts: - qapi/migration.json - still in qapi-schema.json ---- - migration/migration.c | 6 ++++++ - qapi-schema.json | 8 +++++++- - 2 files changed, 13 insertions(+), 1 deletion(-) - -diff --git a/migration/migration.c b/migration/migration.c -index d4356a4..54db29f 100644 ---- a/migration/migration.c -+++ b/migration/migration.c -@@ -473,6 +473,8 @@ static bool migration_is_setup_or_active(int state) - case MIGRATION_STATUS_ACTIVE: - case MIGRATION_STATUS_POSTCOPY_ACTIVE: - case MIGRATION_STATUS_SETUP: -+ case MIGRATION_STATUS_PRE_SWITCHOVER: -+ case MIGRATION_STATUS_DEVICE: - return true; - - default: -@@ -547,6 +549,8 @@ MigrationInfo *qmp_query_migrate(Error **errp) - case MIGRATION_STATUS_ACTIVE: - case MIGRATION_STATUS_CANCELLING: - case MIGRATION_STATUS_POSTCOPY_ACTIVE: -+ case MIGRATION_STATUS_PRE_SWITCHOVER: -+ case MIGRATION_STATUS_DEVICE: - /* TODO add some postcopy stats */ - info->has_status = true; - info->has_total_time = true; -@@ -1102,6 +1106,8 @@ bool migration_is_idle(void) - case MIGRATION_STATUS_ACTIVE: - case MIGRATION_STATUS_POSTCOPY_ACTIVE: - case MIGRATION_STATUS_COLO: -+ case MIGRATION_STATUS_PRE_SWITCHOVER: -+ case MIGRATION_STATUS_DEVICE: - return false; - case MIGRATION_STATUS__MAX: - g_assert_not_reached(); -diff --git a/qapi-schema.json b/qapi-schema.json -index 9b9ec9a..de8c611 100644 ---- a/qapi-schema.json -+++ b/qapi-schema.json -@@ -674,12 +674,18 @@ - # @colo: VM is in the process of fault tolerance, VM can not get into this - # state unless colo capability is enabled for migration. (since 2.8) - # -+# @pre-switchover: Paused before device serialisation. (since 2.11) -+# -+# @device: During device serialisation when pause-before-switchover is enabled -+# (since 2.11) -+# - # Since: 2.3 - # - ## - { 'enum': 'MigrationStatus', - 'data': [ 'none', 'setup', 'cancelling', 'cancelled', -- 'active', 'postcopy-active', 'completed', 'failed', 'colo' ] } -+ 'active', 'postcopy-active', 'completed', 'failed', 'colo', -+ 'pre-switchover', 'device' ] } - - ## - # @MigrationInfo: --- -1.8.3.1 - diff --git a/SOURCES/kvm-migration-Don-t-activate-block-devices-if-using-S.patch b/SOURCES/kvm-migration-Don-t-activate-block-devices-if-using-S.patch new file mode 100644 index 0000000..97b26d2 --- /dev/null +++ b/SOURCES/kvm-migration-Don-t-activate-block-devices-if-using-S.patch @@ -0,0 +1,114 @@ +From 62f7b17e6115df60aa9a54e7530e16e5f4c6d2a0 Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Fri, 22 Jun 2018 19:00:03 +0200 +Subject: [PATCH 24/57] migration: Don't activate block devices if using -S + +RH-Author: Dr. David Alan Gilbert +Message-id: <20180622190005.21297-17-dgilbert@redhat.com> +Patchwork-id: 81002 +O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH 16/18] migration: Don't activate block devices if using -S +Bugzilla: 1560854 +RH-Acked-by: Juan Quintela +RH-Acked-by: Peter Xu +RH-Acked-by: Laurent Vivier + +From: "Dr. David Alan Gilbert" + +Activating the block devices causes the locks to be taken on +the backing file. If we're running with -S and the destination libvirt +hasn't started the destination with 'cont', it's expecting the locks are +still untaken. + +Don't activate the block devices if we're not going to autostart the VM; +'cont' already will do that anyway. This change is tied to the new +migration capability 'late-block-activate' that defaults to off, keeping +the old behaviour by default. + +bz: https://bugzilla.redhat.com/show_bug.cgi?id=1560854 +Signed-off-by: Dr. David Alan Gilbert +Reviewed-by: Juan Quintela +Signed-off-by: Juan Quintela +(cherry picked from commit 0f073f44df109ea0910d67caede70dec95956ff6) +Signed-off-by: Miroslav Rezanina +--- + migration/migration.c | 34 +++++++++++++++++++++++++++------- + qapi/migration.json | 5 ++++- + 2 files changed, 31 insertions(+), 8 deletions(-) + +diff --git a/migration/migration.c b/migration/migration.c +index b6294f6..edf1c06 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -199,6 +199,16 @@ static void migrate_generate_event(int new_state) + } + } + ++static bool migrate_late_block_activate(void) ++{ ++ MigrationState *s; ++ ++ s = migrate_get_current(); ++ ++ return s->enabled_capabilities[ ++ MIGRATION_CAPABILITY_LATE_BLOCK_ACTIVATE]; ++} ++ + /* + * Called on -incoming with a defer: uri. + * The migration can be started later after any parameters have been +@@ -308,13 +318,23 @@ static void process_incoming_migration_bh(void *opaque) + Error *local_err = NULL; + MigrationIncomingState *mis = opaque; + +- /* Make sure all file formats flush their mutable metadata. +- * If we get an error here, just don't restart the VM yet. */ +- bdrv_invalidate_cache_all(&local_err); +- if (local_err) { +- error_report_err(local_err); +- local_err = NULL; +- autostart = false; ++ /* If capability late_block_activate is set: ++ * Only fire up the block code now if we're going to restart the ++ * VM, else 'cont' will do it. ++ * This causes file locking to happen; so we don't want it to happen ++ * unless we really are starting the VM. ++ */ ++ if (!migrate_late_block_activate() || ++ (autostart && (!global_state_received() || ++ global_state_get_runstate() == RUN_STATE_RUNNING))) { ++ /* Make sure all file formats flush their mutable metadata. ++ * If we get an error here, just don't restart the VM yet. */ ++ bdrv_invalidate_cache_all(&local_err); ++ if (local_err) { ++ error_report_err(local_err); ++ local_err = NULL; ++ autostart = false; ++ } + } + + /* +diff --git a/qapi/migration.json b/qapi/migration.json +index 9d0bf82..618d2de 100644 +--- a/qapi/migration.json ++++ b/qapi/migration.json +@@ -357,13 +357,16 @@ + # @dirty-bitmaps: If enabled, QEMU will migrate named dirty bitmaps. + # (since 2.12) + # ++# @late-block-activate: If enabled, the destination will not activate block ++# devices (and thus take locks) immediately at the end of migration. ++# (since 3.0) + # Since: 1.2 + ## + { 'enum': 'MigrationCapability', + 'data': ['xbzrle', 'rdma-pin-all', 'auto-converge', 'zero-blocks', + 'compress', 'events', 'postcopy-ram', 'x-colo', 'release-ram', + 'block', 'return-path', 'pause-before-switchover', 'x-multifd', +- 'dirty-bitmaps' ] } ++ 'dirty-bitmaps', 'late-block-activate' ] } + + ## + # @MigrationCapabilityStatus: +-- +1.8.3.1 + diff --git a/SOURCES/kvm-migration-Recover-block-devices-if-failure-in-device.patch b/SOURCES/kvm-migration-Recover-block-devices-if-failure-in-device.patch deleted file mode 100644 index 2bfd130..0000000 --- a/SOURCES/kvm-migration-Recover-block-devices-if-failure-in-device.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 2b263ba2282ac34afa1f9fd1892db868d8b91dba Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Wed, 7 Feb 2018 12:24:49 +0100 -Subject: [PATCH 01/15] migration: Recover block devices if failure in device - state - -RH-Author: Dr. David Alan Gilbert -Message-id: <20180207122449.11675-2-dgilbert@redhat.com> -Patchwork-id: 78915 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 1/1] migration: Recover block devices if failure in device state -Bugzilla: 1538494 -RH-Acked-by: Peter Xu -RH-Acked-by: Laurent Vivier -RH-Acked-by: Kevin Wolf - -From: "Dr. David Alan Gilbert" - -In e91d895 I added the new pause-before-switchover mechanism -to allow migration completion to be delayed; this changes the -last state prior to completion to MIGRATE_STATUS_DEVICE rather -than MIGRATE_STATUS_ACTIVE. - -Fix the failure path in migration_completion to recover the block -devices if it fails in MIGRATE_STATUS_DEVICE, not just the -MIGRATE_STATUS_ACTIVE that it previously had. - -This corresponds to rh bz: - https://bugzilla.redhat.com/show_bug.cgi?id=1538494 -whose symptom is an occasional source crash on a failed migration. - -Fixes: e91d8951d59d483f085f -Signed-off-by: Dr. David Alan Gilbert -Reviewed-by: Peter Xu -Signed-off-by: Dr. David Alan Gilbert -(cherry picked from commit 6039dd5b1c45d76403b9dcadd2afd7efd8f42330) -Signed-off-by: Miroslav Rezanina ---- - migration/migration.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/migration/migration.c b/migration/migration.c -index cd33718..38d4d9f 100644 ---- a/migration/migration.c -+++ b/migration/migration.c -@@ -1990,7 +1990,8 @@ fail_invalidate: - /* If not doing postcopy, vm_start() will be called: let's regain - * control on images. - */ -- if (s->state == MIGRATION_STATUS_ACTIVE) { -+ if (s->state == MIGRATION_STATUS_ACTIVE || -+ s->state == MIGRATION_STATUS_DEVICE) { - Error *local_err = NULL; - - qemu_mutex_lock_iothread(); --- -1.8.3.1 - diff --git a/SOURCES/kvm-migration-Reenable-incoming-live-block-migration.patch b/SOURCES/kvm-migration-Reenable-incoming-live-block-migration.patch deleted file mode 100644 index d846bb8..0000000 --- a/SOURCES/kvm-migration-Reenable-incoming-live-block-migration.patch +++ /dev/null @@ -1,87 +0,0 @@ -From e6f62c7eb81f164ad5aef99a4f7ff48200928938 Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Wed, 22 Nov 2017 15:41:32 +0100 -Subject: [PATCH 2/7] migration: Reenable incoming live-block-migration - -RH-Author: Dr. David Alan Gilbert -Message-id: <20171122154132.15363-1-dgilbert@redhat.com> -Patchwork-id: 77779 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 1/1] migration: Reenable incoming live-block-migration -Bugzilla: 1515173 -RH-Acked-by: Laurent Vivier -RH-Acked-by: Fam Zheng -RH-Acked-by: Juan Quintela - -From: "Dr. David Alan Gilbert" - -rhel7 has always disabled outgoing old-style live block migration -(but in -rhev enabled nbd block migration); however it allows -incoming old-style live block migration to allow reception of a stream -from rhel6. - -I added --disable-live-block-migration to upstream in ed1701c6a5a, -however that really did disable it completely. - -In the 7.5 world we've inherited the upstream version and lost the -incoming support. - -Reenable incoming support even when outgoing is disabled. - -Signed-off-by: Dr. David Alan Gilbert -Signed-off-by: Miroslav Rezanina ---- - include/migration/misc.h | 7 +++---- - migration/Makefile.objs | 2 +- - migration/block.h | 6 +++++- - 3 files changed, 9 insertions(+), 6 deletions(-) - -diff --git a/include/migration/misc.h b/include/migration/misc.h -index c079b77..1d060df 100644 ---- a/include/migration/misc.h -+++ b/include/migration/misc.h -@@ -22,11 +22,10 @@ void ram_mig_init(void); - - /* migration/block.c */ - --#ifdef CONFIG_LIVE_BLOCK_MIGRATION -+/* RHEL7 allows incoming block migration even with -+ * --disable-live-block-migration to allow RHEL6->7 migration. -+ */ - void blk_mig_init(void); --#else --static inline void blk_mig_init(void) {} --#endif - - #define SELF_ANNOUNCE_ROUNDS 5 - -diff --git a/migration/Makefile.objs b/migration/Makefile.objs -index 1c7770d..4277c88 100644 ---- a/migration/Makefile.objs -+++ b/migration/Makefile.objs -@@ -9,5 +9,5 @@ common-obj-y += qjson.o - - common-obj-$(CONFIG_RDMA) += rdma.o - --common-obj-$(CONFIG_LIVE_BLOCK_MIGRATION) += block.o -+common-obj-y += block.o - -diff --git a/migration/block.h b/migration/block.h -index 22ebe94..c4ab848 100644 ---- a/migration/block.h -+++ b/migration/block.h -@@ -14,7 +14,11 @@ - #ifndef MIGRATION_BLOCK_H - #define MIGRATION_BLOCK_H - --#ifdef CONFIG_LIVE_BLOCK_MIGRATION -+/* RHEL7: live block migration is still compiled in even -+ * with --disable-live-block-migration since we must -+ * allow inbound migration from RHEL6. -+ */ -+#if 1 /* CONFIG_LIVE_BLOCK_MIGRATION */ - int blk_mig_active(void); - uint64_t blk_mig_bytes_transferred(void); - uint64_t blk_mig_bytes_remaining(void); --- -1.8.3.1 - diff --git a/SOURCES/kvm-migration-Reset-rather-than-destroy-main_thread_load.patch b/SOURCES/kvm-migration-Reset-rather-than-destroy-main_thread_load.patch deleted file mode 100644 index bba3547..0000000 --- a/SOURCES/kvm-migration-Reset-rather-than-destroy-main_thread_load.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 21133ce1a56f6490a7ea9dd107013088c1fc05ed Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Thu, 2 Nov 2017 15:36:56 +0100 -Subject: [PATCH 3/9] migration: Reset rather than destroy - main_thread_load_event - -RH-Author: Dr. David Alan Gilbert -Message-id: <20171102153657.13452-2-dgilbert@redhat.com> -Patchwork-id: 77481 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 1/2] migration: Reset rather than destroy main_thread_load_event -Bugzilla: 1508799 -RH-Acked-by: Peter Xu -RH-Acked-by: Thomas Huth -RH-Acked-by: Stefan Hajnoczi - -From: "Dr. David Alan Gilbert" - -migration_incoming_state_destroy doesn't really destroy, it cleans up. -After a loadvm it's called, but the loadvm command can be run twice, -and so destroying an init-once mutex breaks on the second loadvm. - -Reported-by: Stafford Horne -Signed-off-by: Dr. David Alan Gilbert -Message-Id: <20170825141940.20740-2-dgilbert@redhat.com> -Reviewed-by: Peter Xu -Tested-by: Stafford Horne -Signed-off-by: Dr. David Alan Gilbert -(cherry picked from commit 5089e1862fe80b6f23ba4c494e2902cbe3d9d48e) -Signed-off-by: Miroslav Rezanina ---- - migration/migration.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/migration/migration.c b/migration/migration.c -index 1288697..cd33718 100644 ---- a/migration/migration.c -+++ b/migration/migration.c -@@ -172,7 +172,7 @@ void migration_incoming_state_destroy(void) - mis->from_src_file = NULL; - } - -- qemu_event_destroy(&mis->main_thread_load_event); -+ qemu_event_reset(&mis->main_thread_load_event); - } - - static void migrate_generate_event(int new_state) --- -1.8.3.1 - diff --git a/SOURCES/kvm-migration-Wait-for-semaphore-before-completing-migra.patch b/SOURCES/kvm-migration-Wait-for-semaphore-before-completing-migra.patch deleted file mode 100644 index c53f246..0000000 --- a/SOURCES/kvm-migration-Wait-for-semaphore-before-completing-migra.patch +++ /dev/null @@ -1,118 +0,0 @@ -From 926144680056dd6773d9ef8ad64c4a593dd597a9 Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Wed, 25 Oct 2017 18:28:34 +0200 -Subject: [PATCH 15/19] migration: Wait for semaphore before completing - migration - -RH-Author: Dr. David Alan Gilbert -Message-id: <20171025182838.31829-4-dgilbert@redhat.com> -Patchwork-id: 77439 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH 3/7] migration: Wait for semaphore before completing migration -Bugzilla: 1497120 -RH-Acked-by: Peter Xu -RH-Acked-by: Juan Quintela -RH-Acked-by: Miroslav Rezanina - -From: "Dr. David Alan Gilbert" - -Wait for a semaphore before completing the migration, -if the previously added capability was enabled. - -Signed-off-by: Dr. David Alan Gilbert -Reviewed-by: Peter Xu -Reviewed-by: Juan Quintela -Signed-off-by: Juan Quintela -(cherry picked from commit e91d8951d59d483f085f7650381b8e55a1a55e4c) -Signed-off-by: Miroslav Rezanina ---- - migration/migration.c | 38 ++++++++++++++++++++++++++++++++++++++ - migration/migration.h | 3 +++ - 2 files changed, 41 insertions(+) - -diff --git a/migration/migration.c b/migration/migration.c -index 54db29f..436e122 100644 ---- a/migration/migration.c -+++ b/migration/migration.c -@@ -1847,6 +1847,39 @@ fail: - } - - /** -+ * migration_maybe_pause: Pause if required to by -+ * migrate_pause_before_switchover called with the iothread locked -+ * Returns: 0 on success -+ */ -+static int migration_maybe_pause(MigrationState *s, int *current_active_state) -+{ -+ if (!migrate_pause_before_switchover()) { -+ return 0; -+ } -+ -+ /* Since leaving this state is not atomic with posting the semaphore -+ * it's possible that someone could have issued multiple migrate_continue -+ * and the semaphore is incorrectly positive at this point; -+ * the docs say it's undefined to reinit a semaphore that's already -+ * init'd, so use timedwait to eat up any existing posts. -+ */ -+ while (qemu_sem_timedwait(&s->pause_sem, 1) == 0) { -+ /* This block intentionally left blank */ -+ } -+ -+ qemu_mutex_unlock_iothread(); -+ migrate_set_state(&s->state, *current_active_state, -+ MIGRATION_STATUS_PRE_SWITCHOVER); -+ qemu_sem_wait(&s->pause_sem); -+ migrate_set_state(&s->state, MIGRATION_STATUS_PRE_SWITCHOVER, -+ MIGRATION_STATUS_DEVICE); -+ *current_active_state = MIGRATION_STATUS_DEVICE; -+ qemu_mutex_lock_iothread(); -+ -+ return s->state == MIGRATION_STATUS_DEVICE ? 0 : -EINVAL; -+} -+ -+/** - * migration_completion: Used by migration_thread when there's not much left. - * The caller 'breaks' the loop when this returns. - * -@@ -1872,6 +1905,9 @@ static void migration_completion(MigrationState *s, int current_active_state, - bool inactivate = !migrate_colo_enabled(); - ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); - if (ret >= 0) { -+ ret = migration_maybe_pause(s, ¤t_active_state); -+ } -+ if (ret >= 0) { - qemu_file_set_rate_limit(s->to_dst_file, INT64_MAX); - ret = qemu_savevm_state_complete_precopy(s->to_dst_file, false, - inactivate); -@@ -2239,6 +2275,7 @@ static void migration_instance_finalize(Object *obj) - - g_free(params->tls_hostname); - g_free(params->tls_creds); -+ qemu_sem_destroy(&ms->pause_sem); - } - - static void migration_instance_init(Object *obj) -@@ -2249,6 +2286,7 @@ static void migration_instance_init(Object *obj) - ms->state = MIGRATION_STATUS_NONE; - ms->xbzrle_cache_size = DEFAULT_MIGRATE_CACHE_SIZE; - ms->mbps = -1; -+ qemu_sem_init(&ms->pause_sem, 0); - - params->tls_hostname = g_strdup(""); - params->tls_creds = g_strdup(""); -diff --git a/migration/migration.h b/migration/migration.h -index 2eebad8..895cc34 100644 ---- a/migration/migration.h -+++ b/migration/migration.h -@@ -120,6 +120,9 @@ struct MigrationState - /* Flag set once the migration thread called bdrv_inactivate_all */ - bool block_inactive; - -+ /* Migration is paused due to pause-before-switchover */ -+ QemuSemaphore pause_sem; -+ - /* The semaphore is used to notify COLO thread that failover is finished */ - QemuSemaphore colo_exit_sem; - --- -1.8.3.1 - diff --git a/SOURCES/kvm-migration-allow-cancel-to-unpause.patch b/SOURCES/kvm-migration-allow-cancel-to-unpause.patch deleted file mode 100644 index 562a714..0000000 --- a/SOURCES/kvm-migration-allow-cancel-to-unpause.patch +++ /dev/null @@ -1,47 +0,0 @@ -From a25e94a891b4633f6039e39f5c63041f4a0b6722 Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Wed, 25 Oct 2017 18:28:37 +0200 -Subject: [PATCH 18/19] migration: allow cancel to unpause - -RH-Author: Dr. David Alan Gilbert -Message-id: <20171025182838.31829-7-dgilbert@redhat.com> -Patchwork-id: 77438 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH 6/7] migration: allow cancel to unpause -Bugzilla: 1497120 -RH-Acked-by: Peter Xu -RH-Acked-by: Juan Quintela -RH-Acked-by: Miroslav Rezanina - -From: "Dr. David Alan Gilbert" - -If a migration_cancel is issued during the new paused state, -kick the pause_sem to get to unpause so it can cancel. - -Signed-off-by: Dr. David Alan Gilbert -Reviewed-by: Peter Xu -Reviewed-by: Juan Quintela -Signed-off-by: Juan Quintela -(cherry picked from commit a7b36b486dd58d8f44f788a2a2efa6a4fa3b1223) -Signed-off-by: Miroslav Rezanina ---- - migration/migration.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/migration/migration.c b/migration/migration.c -index 3a1dabb..3f23ed0 100644 ---- a/migration/migration.c -+++ b/migration/migration.c -@@ -1027,6 +1027,10 @@ static void migrate_fd_cancel(MigrationState *s) - if (!migration_is_setup_or_active(old_state)) { - break; - } -+ /* If the migration is paused, kick it out of the pause */ -+ if (old_state == MIGRATION_STATUS_PRE_SWITCHOVER) { -+ qemu_sem_post(&s->pause_sem); -+ } - migrate_set_state(&s->state, old_state, MIGRATION_STATUS_CANCELLING); - } while (s->state != MIGRATION_STATUS_CANCELLING); - --- -1.8.3.1 - diff --git a/SOURCES/kvm-migration-block-dirty-bitmap-fix-dirty_bitmap_load.patch b/SOURCES/kvm-migration-block-dirty-bitmap-fix-dirty_bitmap_load.patch new file mode 100644 index 0000000..b9f6f38 --- /dev/null +++ b/SOURCES/kvm-migration-block-dirty-bitmap-fix-dirty_bitmap_load.patch @@ -0,0 +1,51 @@ +From 91c5845da64dbe85892770609c1b04dee3718506 Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Fri, 22 Jun 2018 19:00:05 +0200 +Subject: [PATCH 26/57] migration/block-dirty-bitmap: fix dirty_bitmap_load + +RH-Author: Dr. David Alan Gilbert +Message-id: <20180622190005.21297-19-dgilbert@redhat.com> +Patchwork-id: 81012 +O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH 18/18] migration/block-dirty-bitmap: fix dirty_bitmap_load +Bugzilla: 1584139 +RH-Acked-by: Juan Quintela +RH-Acked-by: Peter Xu +RH-Acked-by: Laurent Vivier + +From: Vladimir Sementsov-Ogievskiy + +dirty_bitmap_load_header return code is obtained but not handled. Fix +this. + +Bug was introduced in b35ebdf076d697bc +"migration: add postcopy migration of dirty bitmaps" with the whole +function. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20180530112424.204835-1-vsementsov@virtuozzo.com> +Reviewed-by: Eric Blake +Reviewed-by: John Snow +Signed-off-by: Dr. David Alan Gilbert +(cherry picked from commit a36f6ff46f115672cf86d0e1e7cdb1c2fa4d304b) +Signed-off-by: Miroslav Rezanina +--- + migration/block-dirty-bitmap.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c +index 8819aab..2c541c9 100644 +--- a/migration/block-dirty-bitmap.c ++++ b/migration/block-dirty-bitmap.c +@@ -672,6 +672,9 @@ static int dirty_bitmap_load(QEMUFile *f, void *opaque, int version_id) + + do { + ret = dirty_bitmap_load_header(f, &s); ++ if (ret < 0) { ++ return ret; ++ } + + if (s.flags & DIRTY_BITMAP_MIG_FLAG_START) { + ret = dirty_bitmap_load_start(f, &s); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-migration-block-dirty-bitmap-fix-memory-leak-in-dirt.patch b/SOURCES/kvm-migration-block-dirty-bitmap-fix-memory-leak-in-dirt.patch new file mode 100644 index 0000000..2bdba63 --- /dev/null +++ b/SOURCES/kvm-migration-block-dirty-bitmap-fix-memory-leak-in-dirt.patch @@ -0,0 +1,48 @@ +From b03c385c6eee5999f6aadcc516aa0f9fc882df47 Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Fri, 22 Jun 2018 18:59:58 +0200 +Subject: [PATCH 19/57] migration/block-dirty-bitmap: fix memory leak in + dirty_bitmap_load_bits + +RH-Author: Dr. David Alan Gilbert +Message-id: <20180622190005.21297-12-dgilbert@redhat.com> +Patchwork-id: 81009 +O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH 11/18] migration/block-dirty-bitmap: fix memory leak in dirty_bitmap_load_bits +Bugzilla: 1584139 +RH-Acked-by: Peter Xu +RH-Acked-by: Juan Quintela +RH-Acked-by: Laurent Vivier + +From: Vladimir Sementsov-Ogievskiy + +Release buf on error path too. + +Bug was introduced in b35ebdf076d697bc "migration: add postcopy +migration of dirty bitmaps" with the whole function. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20180427142002.21930-3-vsementsov@virtuozzo.com> +Reviewed-by: Eric Blake +CC: qemu-stable@nongnu.org +Signed-off-by: Eric Blake +(cherry picked from commit 16a2227893dc1d5cad78ed376ad1d7e300978fbe) +Signed-off-by: Miroslav Rezanina +--- + migration/block-dirty-bitmap.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c +index dd04f10..8819aab 100644 +--- a/migration/block-dirty-bitmap.c ++++ b/migration/block-dirty-bitmap.c +@@ -600,6 +600,7 @@ static int dirty_bitmap_load_bits(QEMUFile *f, DirtyBitmapLoadState *s) + ret = qemu_get_buffer(f, buf, buf_size); + if (ret != buf_size) { + error_report("Failed to read bitmap bits"); ++ g_free(buf); + return -EIO; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-migration-calculate-expected_downtime-with-ram_bytes.patch b/SOURCES/kvm-migration-calculate-expected_downtime-with-ram_bytes.patch new file mode 100644 index 0000000..f40fa84 --- /dev/null +++ b/SOURCES/kvm-migration-calculate-expected_downtime-with-ram_bytes.patch @@ -0,0 +1,68 @@ +From 4d7902d7277992139d575552f09c2ff6827e9794 Mon Sep 17 00:00:00 2001 +From: Laurent Vivier +Date: Thu, 21 Jun 2018 09:45:26 +0200 +Subject: [PATCH 14/89] migration: calculate expected_downtime with + ram_bytes_remaining() + +RH-Author: Laurent Vivier +Message-id: <20180621094526.5714-1-lvivier@redhat.com> +Patchwork-id: 80931 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH] migration: calculate expected_downtime with ram_bytes_remaining() +Bugzilla: 1564576 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Thomas Huth +RH-Acked-by: David Gibson + +From: Balamuruhan S + +expected_downtime value is not accurate with dirty_pages_rate * page_size, +using ram_bytes_remaining() would yeild it resonable. + +consider to read the remaining ram just after having updated the dirty +pages count later migration_bitmap_sync_range() in migration_bitmap_sync() +and reuse the `remaining` field in ram_counters to hold ram_bytes_remaining() +for calculating expected_downtime. + +Reported-by: Michael Roth +Signed-off-by: Balamuruhan S +Signed-off-by: Laurent Vivier +Message-Id: <20180612085009.17594-2-bala24@linux.vnet.ibm.com> +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Dr. David Alan Gilbert +(cherry picked from commit 650af8907bd567db914b7ce3a7e9df4c323f4619) +Signed-off-by: Laurent Vivier +Signed-off-by: Miroslav Rezanina +--- + migration/migration.c | 3 +-- + migration/ram.c | 1 + + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/migration/migration.c b/migration/migration.c +index ef4bb42..43d8a64 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -2239,8 +2239,7 @@ static void migration_update_counters(MigrationState *s, + * recalculate. 10000 is a small enough number for our purposes + */ + if (ram_counters.dirty_pages_rate && transferred > 10000) { +- s->expected_downtime = ram_counters.dirty_pages_rate * +- qemu_target_page_size() / bandwidth; ++ s->expected_downtime = ram_counters.remaining / bandwidth; + } + + qemu_file_reset_rate_limit(s->to_dst_file); +diff --git a/migration/ram.c b/migration/ram.c +index 0e90efa..00c06b5 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -852,6 +852,7 @@ static void migration_bitmap_sync(RAMState *rs) + RAMBLOCK_FOREACH(block) { + migration_bitmap_sync_range(rs, block, 0, block->used_length); + } ++ ram_counters.remaining = ram_bytes_remaining(); + rcu_read_unlock(); + qemu_mutex_unlock(&rs->bitmap_mutex); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-migration-detect-compression-and-decompression-error.patch b/SOURCES/kvm-migration-detect-compression-and-decompression-error.patch new file mode 100644 index 0000000..4107b2d --- /dev/null +++ b/SOURCES/kvm-migration-detect-compression-and-decompression-error.patch @@ -0,0 +1,235 @@ +From 231178d9b06a3d2bba1e7695071957671d7c08a1 Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Fri, 22 Jun 2018 18:59:51 +0200 +Subject: [PATCH 12/57] migration: detect compression and decompression errors + +RH-Author: Dr. David Alan Gilbert +Message-id: <20180622190005.21297-5-dgilbert@redhat.com> +Patchwork-id: 80996 +O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH 04/18] migration: detect compression and decompression errors +Bugzilla: 1584139 +RH-Acked-by: Peter Xu +RH-Acked-by: Juan Quintela +RH-Acked-by: Laurent Vivier + +From: Xiao Guangrong + +Currently the page being compressed is allowed to be updated by +the VM on the source QEMU, correspondingly the destination QEMU +just ignores the decompression error. However, we completely miss +the chance to catch real errors, then the VM is corrupted silently + +To make the migration more robuster, we copy the page to a buffer +first to avoid it being written by VM, then detect and handle the +errors of both compression and decompression errors properly + +Reviewed-by: Peter Xu +Signed-off-by: Xiao Guangrong +Message-Id: <20180330075128.26919-5-xiaoguangrong@tencent.com> +Signed-off-by: Dr. David Alan Gilbert +(cherry picked from commit 34ab9e9743aeaf265929d930747f101fa5c76fea) +Signed-off-by: Miroslav Rezanina +--- + migration/qemu-file.c | 4 ++-- + migration/ram.c | 56 +++++++++++++++++++++++++++++++++++---------------- + 2 files changed, 41 insertions(+), 19 deletions(-) + +diff --git a/migration/qemu-file.c b/migration/qemu-file.c +index bafe3a0..0463f4c 100644 +--- a/migration/qemu-file.c ++++ b/migration/qemu-file.c +@@ -710,9 +710,9 @@ ssize_t qemu_put_compression_data(QEMUFile *f, z_stream *stream, + blen = qemu_compress_data(stream, f->buf + f->buf_index + sizeof(int32_t), + blen, p, size); + if (blen < 0) { +- error_report("Compress Failed!"); +- return 0; ++ return -1; + } ++ + qemu_put_be32(f, blen); + if (f->ops->writev_buffer) { + add_to_iovec(f, f->buf + f->buf_index, blen, false); +diff --git a/migration/ram.c b/migration/ram.c +index be89cd8..cd6d98a 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -269,7 +269,10 @@ struct CompressParam { + QemuCond cond; + RAMBlock *block; + ram_addr_t offset; ++ ++ /* internally used fields */ + z_stream stream; ++ uint8_t *originbuf; + }; + typedef struct CompressParam CompressParam; + +@@ -296,13 +299,14 @@ static QemuCond comp_done_cond; + /* The empty QEMUFileOps will be used by file in CompressParam */ + static const QEMUFileOps empty_ops = { }; + ++static QEMUFile *decomp_file; + static DecompressParam *decomp_param; + static QemuThread *decompress_threads; + static QemuMutex decomp_done_lock; + static QemuCond decomp_done_cond; + + static int do_compress_ram_page(QEMUFile *f, z_stream *stream, RAMBlock *block, +- ram_addr_t offset); ++ ram_addr_t offset, uint8_t *source_buf); + + static void *do_data_compress(void *opaque) + { +@@ -318,7 +322,8 @@ static void *do_data_compress(void *opaque) + param->block = NULL; + qemu_mutex_unlock(¶m->mutex); + +- do_compress_ram_page(param->file, ¶m->stream, block, offset); ++ do_compress_ram_page(param->file, ¶m->stream, block, offset, ++ param->originbuf); + + qemu_mutex_lock(&comp_done_lock); + param->done = true; +@@ -370,6 +375,7 @@ static void compress_threads_save_cleanup(void) + qemu_mutex_destroy(&comp_param[i].mutex); + qemu_cond_destroy(&comp_param[i].cond); + deflateEnd(&comp_param[i].stream); ++ g_free(comp_param[i].originbuf); + qemu_fclose(comp_param[i].file); + comp_param[i].file = NULL; + } +@@ -394,8 +400,14 @@ static int compress_threads_save_setup(void) + qemu_cond_init(&comp_done_cond); + qemu_mutex_init(&comp_done_lock); + for (i = 0; i < thread_count; i++) { ++ comp_param[i].originbuf = g_try_malloc(TARGET_PAGE_SIZE); ++ if (!comp_param[i].originbuf) { ++ goto exit; ++ } ++ + if (deflateInit(&comp_param[i].stream, + migrate_compress_level()) != Z_OK) { ++ g_free(comp_param[i].originbuf); + goto exit; + } + +@@ -1054,7 +1066,7 @@ static int ram_save_page(RAMState *rs, PageSearchStatus *pss, bool last_stage) + } + + static int do_compress_ram_page(QEMUFile *f, z_stream *stream, RAMBlock *block, +- ram_addr_t offset) ++ ram_addr_t offset, uint8_t *source_buf) + { + RAMState *rs = ram_state; + int bytes_sent, blen; +@@ -1062,7 +1074,14 @@ static int do_compress_ram_page(QEMUFile *f, z_stream *stream, RAMBlock *block, + + bytes_sent = save_page_header(rs, f, block, offset | + RAM_SAVE_FLAG_COMPRESS_PAGE); +- blen = qemu_put_compression_data(f, stream, p, TARGET_PAGE_SIZE); ++ ++ /* ++ * copy it to a internal buffer to avoid it being modified by VM ++ * so that we can catch up the error during compression and ++ * decompression ++ */ ++ memcpy(source_buf, p, TARGET_PAGE_SIZE); ++ blen = qemu_put_compression_data(f, stream, source_buf, TARGET_PAGE_SIZE); + if (blen < 0) { + bytes_sent = 0; + qemu_file_set_error(migrate_get_current()->to_dst_file, blen); +@@ -2556,7 +2575,7 @@ static void *do_data_decompress(void *opaque) + DecompressParam *param = opaque; + unsigned long pagesize; + uint8_t *des; +- int len; ++ int len, ret; + + qemu_mutex_lock(¶m->mutex); + while (!param->quit) { +@@ -2567,13 +2586,13 @@ static void *do_data_decompress(void *opaque) + qemu_mutex_unlock(¶m->mutex); + + pagesize = TARGET_PAGE_SIZE; +- /* qemu_uncompress_data() will return failed in some case, +- * especially when the page is dirtied when doing the compression, +- * it's not a problem because the dirty page will be retransferred +- * and uncompress() won't break the data in other pages. +- */ +- qemu_uncompress_data(¶m->stream, des, pagesize, param->compbuf, +- len); ++ ++ ret = qemu_uncompress_data(¶m->stream, des, pagesize, ++ param->compbuf, len); ++ if (ret < 0) { ++ error_report("decompress data failed"); ++ qemu_file_set_error(decomp_file, ret); ++ } + + qemu_mutex_lock(&decomp_done_lock); + param->done = true; +@@ -2590,12 +2609,12 @@ static void *do_data_decompress(void *opaque) + return NULL; + } + +-static void wait_for_decompress_done(void) ++static int wait_for_decompress_done(void) + { + int idx, thread_count; + + if (!migrate_use_compression()) { +- return; ++ return 0; + } + + thread_count = migrate_decompress_threads(); +@@ -2606,6 +2625,7 @@ static void wait_for_decompress_done(void) + } + } + qemu_mutex_unlock(&decomp_done_lock); ++ return qemu_file_get_error(decomp_file); + } + + static void compress_threads_load_cleanup(void) +@@ -2646,9 +2666,10 @@ static void compress_threads_load_cleanup(void) + g_free(decomp_param); + decompress_threads = NULL; + decomp_param = NULL; ++ decomp_file = NULL; + } + +-static int compress_threads_load_setup(void) ++static int compress_threads_load_setup(QEMUFile *f) + { + int i, thread_count; + +@@ -2661,6 +2682,7 @@ static int compress_threads_load_setup(void) + decomp_param = g_new0(DecompressParam, thread_count); + qemu_mutex_init(&decomp_done_lock); + qemu_cond_init(&decomp_done_cond); ++ decomp_file = f; + for (i = 0; i < thread_count; i++) { + if (inflateInit(&decomp_param[i].stream) != Z_OK) { + goto exit; +@@ -2720,7 +2742,7 @@ static void decompress_data_with_multi_threads(QEMUFile *f, + */ + static int ram_load_setup(QEMUFile *f, void *opaque) + { +- if (compress_threads_load_setup()) { ++ if (compress_threads_load_setup(f)) { + return -1; + } + +@@ -3075,7 +3097,7 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) + } + } + +- wait_for_decompress_done(); ++ ret |= wait_for_decompress_done(); + rcu_read_unlock(); + trace_ram_load_complete(ret, seq_iter); + return ret; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-migration-discard-non-migratable-RAMBlocks.patch b/SOURCES/kvm-migration-discard-non-migratable-RAMBlocks.patch new file mode 100644 index 0000000..9578900 --- /dev/null +++ b/SOURCES/kvm-migration-discard-non-migratable-RAMBlocks.patch @@ -0,0 +1,381 @@ +From 0319afed69c1b3206fce51fd286c3351c6fd6958 Mon Sep 17 00:00:00 2001 +From: "plai@redhat.com" +Date: Fri, 31 Aug 2018 16:25:51 +0200 +Subject: [PATCH 09/29] migration: discard non-migratable RAMBlocks +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: plai@redhat.com +Message-id: <1535732759-22481-2-git-send-email-plai@redhat.com> +Patchwork-id: 82012 +O-Subject: [RHEL7.6 PATCH BZ 1539280 1/9] migration: discard non-migratable RAMBlocks +Bugzilla: 1539280 +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Pankaj Gupta +RH-Acked-by: Miroslav Rezanina + +From: Cédric Le Goater + +On the POWER9 processor, the XIVE interrupt controller can control +interrupt sources using MMIO to trigger events, to EOI or to turn off +the sources. Priority management and interrupt acknowledgment is also +controlled by MMIO in the presenter sub-engine. + +These MMIO regions are exposed to guests in QEMU with a set of 'ram +device' memory mappings, similarly to VFIO, and the VMAs are populated +dynamically with the appropriate pages using a fault handler. + +But, these regions are an issue for migration. We need to discard the +associated RAMBlocks from the RAM state on the source VM and let the +destination VM rebuild the memory mappings on the new host in the +post_load() operation just before resuming the system. + +To achieve this goal, the following introduces a new RAMBlock flag +RAM_MIGRATABLE which is updated in the vmstate_register_ram() and +vmstate_unregister_ram() routines. This flag is then used by the +migration to identify RAMBlocks to discard on the source. Some checks +are also performed on the destination to make sure nothing invalid was +sent. + +This change impacts the boston, malta and jazz mips boards for which +migration compatibility is broken. + +Signed-off-by: Cédric Le Goater +Reviewed-by: Juan Quintela +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Juan Quintela +(cherry picked from commit b895de502717b83b4e5f089df617cb23530c4d2d) +Signed-off-by: Paul Lai +Signed-off-by: Miroslav Rezanina +--- + exec.c | 38 ++++++++++++++++++++++++++++++++++++++ + include/exec/cpu-common.h | 4 ++++ + migration/postcopy-ram.c | 12 ++++++------ + migration/ram.c | 46 ++++++++++++++++++++++++++++++++++------------ + migration/savevm.c | 2 ++ + 5 files changed, 84 insertions(+), 18 deletions(-) + +diff --git a/exec.c b/exec.c +index 02b1efe..7323d39 100644 +--- a/exec.c ++++ b/exec.c +@@ -104,6 +104,9 @@ static MemoryRegion io_mem_unassigned; + * (Set during postcopy) + */ + #define RAM_UF_ZEROPAGE (1 << 3) ++ ++/* RAM can be migrated */ ++#define RAM_MIGRATABLE (1 << 4) + #endif + + #ifdef TARGET_PAGE_BITS_VARY +@@ -1807,6 +1810,21 @@ void qemu_ram_set_uf_zeroable(RAMBlock *rb) + rb->flags |= RAM_UF_ZEROPAGE; + } + ++bool qemu_ram_is_migratable(RAMBlock *rb) ++{ ++ return rb->flags & RAM_MIGRATABLE; ++} ++ ++void qemu_ram_set_migratable(RAMBlock *rb) ++{ ++ rb->flags |= RAM_MIGRATABLE; ++} ++ ++void qemu_ram_unset_migratable(RAMBlock *rb) ++{ ++ rb->flags &= ~RAM_MIGRATABLE; ++} ++ + /* Called with iothread lock held. */ + void qemu_ram_set_idstr(RAMBlock *new_block, const char *name, DeviceState *dev) + { +@@ -3750,6 +3768,26 @@ int qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque) + return ret; + } + ++int qemu_ram_foreach_migratable_block(RAMBlockIterFunc func, void *opaque) ++{ ++ RAMBlock *block; ++ int ret = 0; ++ ++ rcu_read_lock(); ++ RAMBLOCK_FOREACH(block) { ++ if (!qemu_ram_is_migratable(block)) { ++ continue; ++ } ++ ret = func(block->idstr, block->host, block->offset, ++ block->used_length, opaque); ++ if (ret) { ++ break; ++ } ++ } ++ rcu_read_unlock(); ++ return ret; ++} ++ + /* + * Unmap pages of memory from start to start+length such that + * they a) read as 0, b) Trigger whatever fault mechanism +diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h +index 24d335f..0b58e26 100644 +--- a/include/exec/cpu-common.h ++++ b/include/exec/cpu-common.h +@@ -75,6 +75,9 @@ const char *qemu_ram_get_idstr(RAMBlock *rb); + bool qemu_ram_is_shared(RAMBlock *rb); + bool qemu_ram_is_uf_zeroable(RAMBlock *rb); + void qemu_ram_set_uf_zeroable(RAMBlock *rb); ++bool qemu_ram_is_migratable(RAMBlock *rb); ++void qemu_ram_set_migratable(RAMBlock *rb); ++void qemu_ram_unset_migratable(RAMBlock *rb); + + size_t qemu_ram_pagesize(RAMBlock *block); + size_t qemu_ram_pagesize_largest(void); +@@ -119,6 +122,7 @@ typedef int (RAMBlockIterFunc)(const char *block_name, void *host_addr, + ram_addr_t offset, ram_addr_t length, void *opaque); + + int qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque); ++int qemu_ram_foreach_migratable_block(RAMBlockIterFunc func, void *opaque); + int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length); + + #endif +diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c +index 4a0b33b..001b041 100644 +--- a/migration/postcopy-ram.c ++++ b/migration/postcopy-ram.c +@@ -264,7 +264,7 @@ bool postcopy_ram_supported_by_host(MigrationIncomingState *mis) + } + + /* We don't support postcopy with shared RAM yet */ +- if (qemu_ram_foreach_block(test_ramblock_postcopiable, NULL)) { ++ if (qemu_ram_foreach_migratable_block(test_ramblock_postcopiable, NULL)) { + goto out; + } + +@@ -392,7 +392,7 @@ static int cleanup_range(const char *block_name, void *host_addr, + */ + int postcopy_ram_incoming_init(MigrationIncomingState *mis, size_t ram_pages) + { +- if (qemu_ram_foreach_block(init_range, NULL)) { ++ if (qemu_ram_foreach_migratable_block(init_range, NULL)) { + return -1; + } + +@@ -414,7 +414,7 @@ int postcopy_ram_incoming_cleanup(MigrationIncomingState *mis) + return -1; + } + +- if (qemu_ram_foreach_block(cleanup_range, mis)) { ++ if (qemu_ram_foreach_migratable_block(cleanup_range, mis)) { + return -1; + } + /* Let the fault thread quit */ +@@ -480,7 +480,7 @@ static int nhp_range(const char *block_name, void *host_addr, + */ + int postcopy_ram_prepare_discard(MigrationIncomingState *mis) + { +- if (qemu_ram_foreach_block(nhp_range, mis)) { ++ if (qemu_ram_foreach_migratable_block(nhp_range, mis)) { + return -1; + } + +@@ -491,7 +491,7 @@ int postcopy_ram_prepare_discard(MigrationIncomingState *mis) + + /* + * Mark the given area of RAM as requiring notification to unwritten areas +- * Used as a callback on qemu_ram_foreach_block. ++ * Used as a callback on qemu_ram_foreach_migratable_block. + * host_addr: Base of area to mark + * offset: Offset in the whole ram arena + * length: Length of the section +@@ -793,7 +793,7 @@ int postcopy_ram_enable_notify(MigrationIncomingState *mis) + mis->have_fault_thread = true; + + /* Mark so that we get notified of accesses to unwritten areas */ +- if (qemu_ram_foreach_block(ram_block_enable_notify, mis)) { ++ if (qemu_ram_foreach_migratable_block(ram_block_enable_notify, mis)) { + return -1; + } + +diff --git a/migration/ram.c b/migration/ram.c +index bd563b5..04b5df5 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -153,11 +153,16 @@ out: + return ret; + } + ++/* Should be holding either ram_list.mutex, or the RCU lock. */ ++#define RAMBLOCK_FOREACH_MIGRATABLE(block) \ ++ RAMBLOCK_FOREACH(block) \ ++ if (!qemu_ram_is_migratable(block)) {} else ++ + static void ramblock_recv_map_init(void) + { + RAMBlock *rb; + +- RAMBLOCK_FOREACH(rb) { ++ RAMBLOCK_FOREACH_MIGRATABLE(rb) { + assert(!rb->receivedmap); + rb->receivedmap = bitmap_new(rb->max_length >> qemu_target_page_bits()); + } +@@ -813,6 +818,10 @@ unsigned long migration_bitmap_find_dirty(RAMState *rs, RAMBlock *rb, + unsigned long *bitmap = rb->bmap; + unsigned long next; + ++ if (!qemu_ram_is_migratable(rb)) { ++ return size; ++ } ++ + if (rs->ram_bulk_stage && start > 0) { + next = start + 1; + } else { +@@ -858,7 +867,7 @@ uint64_t ram_pagesize_summary(void) + RAMBlock *block; + uint64_t summary = 0; + +- RAMBLOCK_FOREACH(block) { ++ RAMBLOCK_FOREACH_MIGRATABLE(block) { + summary |= block->page_size; + } + +@@ -882,7 +891,7 @@ static void migration_bitmap_sync(RAMState *rs) + + qemu_mutex_lock(&rs->bitmap_mutex); + rcu_read_lock(); +- RAMBLOCK_FOREACH(block) { ++ RAMBLOCK_FOREACH_MIGRATABLE(block) { + migration_bitmap_sync_range(rs, block, 0, block->used_length); + } + ram_counters.remaining = ram_bytes_remaining(); +@@ -1522,6 +1531,11 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss, + size_t pagesize_bits = + qemu_ram_pagesize(pss->block) >> TARGET_PAGE_BITS; + ++ if (!qemu_ram_is_migratable(pss->block)) { ++ error_report("block %s should not be migrated !", pss->block->idstr); ++ return 0; ++ } ++ + do { + /* Check the pages is dirty and if it is send it */ + if (!migration_bitmap_clear_dirty(rs, pss->block, pss->page)) { +@@ -1620,7 +1634,7 @@ uint64_t ram_bytes_total(void) + uint64_t total = 0; + + rcu_read_lock(); +- RAMBLOCK_FOREACH(block) { ++ RAMBLOCK_FOREACH_MIGRATABLE(block) { + total += block->used_length; + } + rcu_read_unlock(); +@@ -1675,7 +1689,7 @@ static void ram_save_cleanup(void *opaque) + */ + memory_global_dirty_log_stop(); + +- QLIST_FOREACH_RCU(block, &ram_list.blocks, next) { ++ RAMBLOCK_FOREACH_MIGRATABLE(block) { + g_free(block->bmap); + block->bmap = NULL; + g_free(block->unsentmap); +@@ -1738,7 +1752,7 @@ void ram_postcopy_migrated_memory_release(MigrationState *ms) + { + struct RAMBlock *block; + +- RAMBLOCK_FOREACH(block) { ++ RAMBLOCK_FOREACH_MIGRATABLE(block) { + unsigned long *bitmap = block->bmap; + unsigned long range = block->used_length >> TARGET_PAGE_BITS; + unsigned long run_start = find_next_zero_bit(bitmap, range, 0); +@@ -1816,7 +1830,7 @@ static int postcopy_each_ram_send_discard(MigrationState *ms) + struct RAMBlock *block; + int ret; + +- RAMBLOCK_FOREACH(block) { ++ RAMBLOCK_FOREACH_MIGRATABLE(block) { + PostcopyDiscardState *pds = + postcopy_discard_send_init(ms, block->idstr); + +@@ -2024,7 +2038,7 @@ int ram_postcopy_send_discard_bitmap(MigrationState *ms) + rs->last_sent_block = NULL; + rs->last_page = 0; + +- QLIST_FOREACH_RCU(block, &ram_list.blocks, next) { ++ RAMBLOCK_FOREACH_MIGRATABLE(block) { + unsigned long pages = block->used_length >> TARGET_PAGE_BITS; + unsigned long *bitmap = block->bmap; + unsigned long *unsentmap = block->unsentmap; +@@ -2183,7 +2197,7 @@ static void ram_list_init_bitmaps(void) + + /* Skip setting bitmap if there is no RAM */ + if (ram_bytes_total()) { +- QLIST_FOREACH_RCU(block, &ram_list.blocks, next) { ++ RAMBLOCK_FOREACH_MIGRATABLE(block) { + pages = block->max_length >> TARGET_PAGE_BITS; + block->bmap = bitmap_new(pages); + bitmap_set(block->bmap, 0, pages); +@@ -2264,7 +2278,7 @@ static int ram_save_setup(QEMUFile *f, void *opaque) + + qemu_put_be64(f, ram_bytes_total() | RAM_SAVE_FLAG_MEM_SIZE); + +- RAMBLOCK_FOREACH(block) { ++ RAMBLOCK_FOREACH_MIGRATABLE(block) { + qemu_put_byte(f, strlen(block->idstr)); + qemu_put_buffer(f, (uint8_t *)block->idstr, strlen(block->idstr)); + qemu_put_be64(f, block->used_length); +@@ -2508,6 +2522,11 @@ static inline RAMBlock *ram_block_from_stream(QEMUFile *f, int flags) + return NULL; + } + ++ if (!qemu_ram_is_migratable(block)) { ++ error_report("block %s should not be migrated !", id); ++ return NULL; ++ } ++ + return block; + } + +@@ -2750,7 +2769,7 @@ static int ram_load_cleanup(void *opaque) + xbzrle_load_cleanup(); + compress_threads_load_cleanup(); + +- RAMBLOCK_FOREACH(rb) { ++ RAMBLOCK_FOREACH_MIGRATABLE(rb) { + g_free(rb->receivedmap); + rb->receivedmap = NULL; + } +@@ -3012,7 +3031,10 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) + length = qemu_get_be64(f); + + block = qemu_ram_block_by_name(id); +- if (block) { ++ if (block && !qemu_ram_is_migratable(block)) { ++ error_report("block %s should not be migrated !", id); ++ ret = -EINVAL; ++ } else if (block) { + if (length != block->used_length) { + Error *local_err = NULL; + +diff --git a/migration/savevm.c b/migration/savevm.c +index 56c9feb..b975d3a 100644 +--- a/migration/savevm.c ++++ b/migration/savevm.c +@@ -2510,11 +2510,13 @@ void vmstate_register_ram(MemoryRegion *mr, DeviceState *dev) + { + qemu_ram_set_idstr(mr->ram_block, + memory_region_name(mr), dev); ++ qemu_ram_set_migratable(mr->ram_block); + } + + void vmstate_unregister_ram(MemoryRegion *mr, DeviceState *dev) + { + qemu_ram_unset_idstr(mr->ram_block); ++ qemu_ram_unset_migratable(mr->ram_block); + } + + void vmstate_register_ram_global(MemoryRegion *mr) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-migration-fix-saving-normal-page-even-if-it-s-been-c.patch b/SOURCES/kvm-migration-fix-saving-normal-page-even-if-it-s-been-c.patch new file mode 100644 index 0000000..2c62e11 --- /dev/null +++ b/SOURCES/kvm-migration-fix-saving-normal-page-even-if-it-s-been-c.patch @@ -0,0 +1,48 @@ +From 156eb2b86b1383e639106650be32ca7d1a004f09 Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Fri, 22 Jun 2018 18:59:59 +0200 +Subject: [PATCH 20/57] migration: fix saving normal page even if it's been + compressed + +RH-Author: Dr. David Alan Gilbert +Message-id: <20180622190005.21297-13-dgilbert@redhat.com> +Patchwork-id: 80997 +O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH 12/18] migration: fix saving normal page even if it's been compressed +Bugzilla: 1584139 +RH-Acked-by: Juan Quintela +RH-Acked-by: Peter Xu +RH-Acked-by: Laurent Vivier + +From: Xiao Guangrong + +Fix the bug introduced by da3f56cb2e767016 (migration: remove +ram_save_compressed_page()), It should be 'return' rather than +'res' + +Sorry for this stupid mistake :( + +Signed-off-by: Xiao Guangrong +Message-Id: <20180428081045.8878-1-xiaoguangrong@tencent.com> +Signed-off-by: Juan Quintela +(cherry picked from commit 701b1876c0fc0c583e4aff300ace5d33a1b97ed6) +Signed-off-by: Miroslav Rezanina +--- + migration/ram.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/migration/ram.c b/migration/ram.c +index 466609f..c982201 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -1491,7 +1491,7 @@ static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss, + * CPU resource. + */ + if (block == rs->last_sent_block && save_page_use_compression(rs)) { +- res = compress_page_with_multi_thread(rs, block, offset); ++ return compress_page_with_multi_thread(rs, block, offset); + } + + return ram_save_page(rs, pss, last_stage); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-migration-introduce-control_save_page.patch b/SOURCES/kvm-migration-introduce-control_save_page.patch new file mode 100644 index 0000000..250975e --- /dev/null +++ b/SOURCES/kvm-migration-introduce-control_save_page.patch @@ -0,0 +1,254 @@ +From 63c9f44c51353c54e84e4601a87401ac14247207 Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Fri, 22 Jun 2018 18:59:52 +0200 +Subject: [PATCH 13/57] migration: introduce control_save_page() + +RH-Author: Dr. David Alan Gilbert +Message-id: <20180622190005.21297-6-dgilbert@redhat.com> +Patchwork-id: 81001 +O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH 05/18] migration: introduce control_save_page() +Bugzilla: 1584139 +RH-Acked-by: Peter Xu +RH-Acked-by: Juan Quintela +RH-Acked-by: Laurent Vivier + +From: Xiao Guangrong + +Abstract the common function control_save_page() to cleanup the code, +no logic is changed + +Reviewed-by: Peter Xu +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Xiao Guangrong +Message-Id: <20180330075128.26919-6-xiaoguangrong@tencent.com> +Signed-off-by: Dr. David Alan Gilbert +(cherry picked from commit 059ff0fb29dd3a56ac2843676915efc279938c6b) +Signed-off-by: Miroslav Rezanina +--- + migration/ram.c | 174 +++++++++++++++++++++++++++++--------------------------- + 1 file changed, 89 insertions(+), 85 deletions(-) + +diff --git a/migration/ram.c b/migration/ram.c +index cd6d98a..8dc98a5 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -975,6 +975,44 @@ static void ram_release_pages(const char *rbname, uint64_t offset, int pages) + ram_discard_range(rbname, offset, pages << TARGET_PAGE_BITS); + } + ++/* ++ * @pages: the number of pages written by the control path, ++ * < 0 - error ++ * > 0 - number of pages written ++ * ++ * Return true if the pages has been saved, otherwise false is returned. ++ */ ++static bool control_save_page(RAMState *rs, RAMBlock *block, ram_addr_t offset, ++ int *pages) ++{ ++ uint64_t bytes_xmit = 0; ++ int ret; ++ ++ *pages = -1; ++ ret = ram_control_save_page(rs->f, block->offset, offset, TARGET_PAGE_SIZE, ++ &bytes_xmit); ++ if (ret == RAM_SAVE_CONTROL_NOT_SUPP) { ++ return false; ++ } ++ ++ if (bytes_xmit) { ++ ram_counters.transferred += bytes_xmit; ++ *pages = 1; ++ } ++ ++ if (ret == RAM_SAVE_CONTROL_DELAYED) { ++ return true; ++ } ++ ++ if (bytes_xmit > 0) { ++ ram_counters.normal++; ++ } else if (bytes_xmit == 0) { ++ ram_counters.duplicate++; ++ } ++ ++ return true; ++} ++ + /** + * ram_save_page: send the given page to the stream + * +@@ -991,56 +1029,36 @@ static void ram_release_pages(const char *rbname, uint64_t offset, int pages) + static int ram_save_page(RAMState *rs, PageSearchStatus *pss, bool last_stage) + { + int pages = -1; +- uint64_t bytes_xmit; +- ram_addr_t current_addr; + uint8_t *p; +- int ret; + bool send_async = true; + RAMBlock *block = pss->block; + ram_addr_t offset = pss->page << TARGET_PAGE_BITS; ++ ram_addr_t current_addr = block->offset + offset; + + p = block->host + offset; + trace_ram_save_page(block->idstr, (uint64_t)offset, p); + +- /* In doubt sent page as normal */ +- bytes_xmit = 0; +- ret = ram_control_save_page(rs->f, block->offset, +- offset, TARGET_PAGE_SIZE, &bytes_xmit); +- if (bytes_xmit) { +- ram_counters.transferred += bytes_xmit; +- pages = 1; ++ if (control_save_page(rs, block, offset, &pages)) { ++ return pages; + } + + XBZRLE_cache_lock(); +- +- current_addr = block->offset + offset; +- +- if (ret != RAM_SAVE_CONTROL_NOT_SUPP) { +- if (ret != RAM_SAVE_CONTROL_DELAYED) { +- if (bytes_xmit > 0) { +- ram_counters.normal++; +- } else if (bytes_xmit == 0) { +- ram_counters.duplicate++; +- } +- } +- } else { +- pages = save_zero_page(rs, block, offset); +- if (pages > 0) { +- /* Must let xbzrle know, otherwise a previous (now 0'd) cached +- * page would be stale ++ pages = save_zero_page(rs, block, offset); ++ if (pages > 0) { ++ /* Must let xbzrle know, otherwise a previous (now 0'd) cached ++ * page would be stale ++ */ ++ xbzrle_cache_zero_page(rs, current_addr); ++ ram_release_pages(block->idstr, offset, pages); ++ } else if (!rs->ram_bulk_stage && ++ !migration_in_postcopy() && migrate_use_xbzrle()) { ++ pages = save_xbzrle_page(rs, &p, current_addr, block, ++ offset, last_stage); ++ if (!last_stage) { ++ /* Can't send this cached data async, since the cache page ++ * might get updated before it gets to the wire + */ +- xbzrle_cache_zero_page(rs, current_addr); +- ram_release_pages(block->idstr, offset, pages); +- } else if (!rs->ram_bulk_stage && +- !migration_in_postcopy() && migrate_use_xbzrle()) { +- pages = save_xbzrle_page(rs, &p, current_addr, block, +- offset, last_stage); +- if (!last_stage) { +- /* Can't send this cached data async, since the cache page +- * might get updated before it gets to the wire +- */ +- send_async = false; +- } ++ send_async = false; + } + } + +@@ -1175,63 +1193,49 @@ static int ram_save_compressed_page(RAMState *rs, PageSearchStatus *pss, + bool last_stage) + { + int pages = -1; +- uint64_t bytes_xmit = 0; + uint8_t *p; +- int ret; + RAMBlock *block = pss->block; + ram_addr_t offset = pss->page << TARGET_PAGE_BITS; + + p = block->host + offset; + +- ret = ram_control_save_page(rs->f, block->offset, +- offset, TARGET_PAGE_SIZE, &bytes_xmit); +- if (bytes_xmit) { +- ram_counters.transferred += bytes_xmit; +- pages = 1; ++ if (control_save_page(rs, block, offset, &pages)) { ++ return pages; + } +- if (ret != RAM_SAVE_CONTROL_NOT_SUPP) { +- if (ret != RAM_SAVE_CONTROL_DELAYED) { +- if (bytes_xmit > 0) { +- ram_counters.normal++; +- } else if (bytes_xmit == 0) { +- ram_counters.duplicate++; +- } ++ ++ /* When starting the process of a new block, the first page of ++ * the block should be sent out before other pages in the same ++ * block, and all the pages in last block should have been sent ++ * out, keeping this order is important, because the 'cont' flag ++ * is used to avoid resending the block name. ++ */ ++ if (block != rs->last_sent_block) { ++ flush_compressed_data(rs); ++ pages = save_zero_page(rs, block, offset); ++ if (pages > 0) { ++ ram_release_pages(block->idstr, offset, pages); ++ } else { ++ /* ++ * Make sure the first page is sent out before other pages. ++ * ++ * we post it as normal page as compression will take much ++ * CPU resource. ++ */ ++ ram_counters.transferred += save_page_header(rs, rs->f, block, ++ offset | RAM_SAVE_FLAG_PAGE); ++ qemu_put_buffer_async(rs->f, p, TARGET_PAGE_SIZE, ++ migrate_release_ram() & ++ migration_in_postcopy()); ++ ram_counters.transferred += TARGET_PAGE_SIZE; ++ ram_counters.normal++; ++ pages = 1; + } + } else { +- /* When starting the process of a new block, the first page of +- * the block should be sent out before other pages in the same +- * block, and all the pages in last block should have been sent +- * out, keeping this order is important, because the 'cont' flag +- * is used to avoid resending the block name. +- */ +- if (block != rs->last_sent_block) { +- flush_compressed_data(rs); +- pages = save_zero_page(rs, block, offset); +- if (pages > 0) { +- ram_release_pages(block->idstr, offset, pages); +- } else { +- /* +- * Make sure the first page is sent out before other pages. +- * +- * we post it as normal page as compression will take much +- * CPU resource. +- */ +- ram_counters.transferred += save_page_header(rs, rs->f, block, +- offset | RAM_SAVE_FLAG_PAGE); +- qemu_put_buffer_async(rs->f, p, TARGET_PAGE_SIZE, +- migrate_release_ram() & +- migration_in_postcopy()); +- ram_counters.transferred += TARGET_PAGE_SIZE; +- ram_counters.normal++; +- pages = 1; +- } ++ pages = save_zero_page(rs, block, offset); ++ if (pages == -1) { ++ pages = compress_page_with_multi_thread(rs, block, offset); + } else { +- pages = save_zero_page(rs, block, offset); +- if (pages == -1) { +- pages = compress_page_with_multi_thread(rs, block, offset); +- } else { +- ram_release_pages(block->idstr, offset, pages); +- } ++ ram_release_pages(block->idstr, offset, pages); + } + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-migration-introduce-decompress-error-check.patch b/SOURCES/kvm-migration-introduce-decompress-error-check.patch new file mode 100644 index 0000000..dc39e3b --- /dev/null +++ b/SOURCES/kvm-migration-introduce-decompress-error-check.patch @@ -0,0 +1,164 @@ +From 79faa485281ca351111a0461bbffe10a17f30c64 Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Fri, 22 Jun 2018 19:00:02 +0200 +Subject: [PATCH 23/57] migration: introduce decompress-error-check + +RH-Author: Dr. David Alan Gilbert +Message-id: <20180622190005.21297-16-dgilbert@redhat.com> +Patchwork-id: 81013 +O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH 15/18] migration: introduce decompress-error-check +Bugzilla: 1584139 +RH-Acked-by: Juan Quintela +RH-Acked-by: Peter Xu +RH-Acked-by: Laurent Vivier + +From: Xiao Guangrong + +QEMU 3.0 enables strict check for compression & decompression to +make the migration more robust, that depends on the source to fix +the internal design which triggers the unexpected error conditions + +To make it work for migrating old version QEMU to 2.13 QEMU, we +introduce this parameter to disable the error check on the +destination which is the default behavior of the machine type +which is older than 2.13, alternately, the strict check can be +enabled explicitly as followings: + -M pc-q35-2.11 -global migration.decompress-error-check=true + +Signed-off-by: Xiao Guangrong +Reviewed-by: Juan Quintela +Signed-off-by: Juan Quintela +(cherry picked from commit f548222c24342ca74689de7794f9006b43f86a54) + added compat entry to HW_COMPAT_RHEL7_5 +Signed-off-by: Dr. David Alan Gilbert + +Signed-off-by: Miroslav Rezanina +--- + hw/arm/virt.c | 4 ++++ + hw/i386/pc_piix.c | 1 + + hw/i386/pc_q35.c | 1 + + include/hw/compat.h | 5 +++++ + migration/migration.c | 4 ++++ + migration/migration.h | 8 ++++++++ + migration/ram.c | 2 +- + 7 files changed, 24 insertions(+), 1 deletion(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index a4d0f52..751a93c 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -1607,6 +1607,9 @@ static void machvirt_machine_init(void) + } + type_init(machvirt_machine_init); + ++#define VIRT_COMPAT_2_12 \ ++ HW_COMPAT_2_12 ++ + static void virt_2_12_instance_init(Object *obj) + { + VirtMachineState *vms = VIRT_MACHINE(obj); +@@ -1669,6 +1672,7 @@ static void virt_2_12_instance_init(Object *obj) + + static void virt_machine_2_12_options(MachineClass *mc) + { ++ SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_12); + } + DEFINE_VIRT_MACHINE_AS_LATEST(2, 12) + +diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c +index 7b87ef6..9991650 100644 +--- a/hw/i386/pc_piix.c ++++ b/hw/i386/pc_piix.c +@@ -432,6 +432,7 @@ static void pc_i440fx_2_12_machine_options(MachineClass *m) + pc_i440fx_machine_options(m); + m->alias = "pc"; + m->is_default = 1; ++ SET_MACHINE_COMPAT(m, PC_COMPAT_2_12); + } + + DEFINE_I440FX_MACHINE(v2_12, "pc-i440fx-2.12", NULL, +diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c +index 1805f55..a4387e0 100644 +--- a/hw/i386/pc_q35.c ++++ b/hw/i386/pc_q35.c +@@ -313,6 +313,7 @@ static void pc_q35_2_12_machine_options(MachineClass *m) + { + pc_q35_machine_options(m); + m->alias = "q35"; ++ SET_MACHINE_COMPAT(m, PC_COMPAT_2_12); + } + + DEFINE_Q35_MACHINE(v2_12, "pc-q35-2.12", NULL, +diff --git a/include/hw/compat.h b/include/hw/compat.h +index 9e659e9..5802e61 100644 +--- a/include/hw/compat.h ++++ b/include/hw/compat.h +@@ -480,6 +480,11 @@ + .driver = "cirrus-vga",\ + .property = "vgamem_mb",\ + .value = "16",\ ++ },{ /* HW_COMPAT_RHEL7_5 */ \ ++ .driver = "migration",\ ++ .property = "decompress-error-check",\ ++ .value = "off",\ + }, + ++ + #endif /* HW_COMPAT_H */ +diff --git a/migration/migration.c b/migration/migration.c +index 43d8a64..b6294f6 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -2483,6 +2483,8 @@ void migration_global_dump(Monitor *mon) + ms->send_configuration ? "on" : "off"); + monitor_printf(mon, "send-section-footer: %s\n", + ms->send_section_footer ? "on" : "off"); ++ monitor_printf(mon, "decompress-error-check: %s\n", ++ ms->decompress_error_check ? "on" : "off"); + } + + #define DEFINE_PROP_MIG_CAP(name, x) \ +@@ -2496,6 +2498,8 @@ static Property migration_properties[] = { + send_configuration, true), + DEFINE_PROP_BOOL("send-section-footer", MigrationState, + send_section_footer, true), ++ DEFINE_PROP_BOOL("decompress-error-check", MigrationState, ++ decompress_error_check, true), + + /* Migration parameters */ + DEFINE_PROP_UINT8("x-compress-level", MigrationState, +diff --git a/migration/migration.h b/migration/migration.h +index 06833d7..a9c5c7f 100644 +--- a/migration/migration.h ++++ b/migration/migration.h +@@ -182,6 +182,14 @@ struct MigrationState + bool send_configuration; + /* Whether we send section footer during migration */ + bool send_section_footer; ++ ++ /* ++ * Whether we abort the migration if decompression errors are ++ * detected at the destination. It is left at false for qemu ++ * older than 3.0, since only newer qemu sends streams that ++ * do not trigger spurious decompression errors. ++ */ ++ bool decompress_error_check; + }; + + void migrate_set_state(int *state, int old_state, int new_state); +diff --git a/migration/ram.c b/migration/ram.c +index c982201..bd563b5 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -2582,7 +2582,7 @@ static void *do_data_decompress(void *opaque) + + ret = qemu_uncompress_data(¶m->stream, des, pagesize, + param->compbuf, len); +- if (ret < 0) { ++ if (ret < 0 && migrate_get_current()->decompress_error_check) { + error_report("decompress data failed"); + qemu_file_set_error(decomp_file, ret); + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-migration-introduce-save_normal_page.patch b/SOURCES/kvm-migration-introduce-save_normal_page.patch new file mode 100644 index 0000000..06a302f --- /dev/null +++ b/SOURCES/kvm-migration-introduce-save_normal_page.patch @@ -0,0 +1,108 @@ +From 45b68ea328fbac00681b1c2eec1eb1499005020a Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Fri, 22 Jun 2018 18:59:56 +0200 +Subject: [PATCH 17/57] migration: introduce save_normal_page() + +RH-Author: Dr. David Alan Gilbert +Message-id: <20180622190005.21297-10-dgilbert@redhat.com> +Patchwork-id: 81003 +O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH 09/18] migration: introduce save_normal_page() +Bugzilla: 1584139 +RH-Acked-by: Peter Xu +RH-Acked-by: Juan Quintela +RH-Acked-by: Laurent Vivier + +From: Xiao Guangrong + +It directly sends the page to the stream neither checking zero nor +using xbzrle or compression + +Reviewed-by: Peter Xu +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Xiao Guangrong +Message-Id: <20180330075128.26919-10-xiaoguangrong@tencent.com> +Signed-off-by: Dr. David Alan Gilbert +(cherry picked from commit 65dacaa04fa7e6104cbcee9251c7845355769a10) +Signed-off-by: Miroslav Rezanina +--- + migration/ram.c | 50 ++++++++++++++++++++++++++++++-------------------- + 1 file changed, 30 insertions(+), 20 deletions(-) + +diff --git a/migration/ram.c b/migration/ram.c +index 6e8a7e2..908879f 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -1013,6 +1013,34 @@ static bool control_save_page(RAMState *rs, RAMBlock *block, ram_addr_t offset, + return true; + } + ++/* ++ * directly send the page to the stream ++ * ++ * Returns the number of pages written. ++ * ++ * @rs: current RAM state ++ * @block: block that contains the page we want to send ++ * @offset: offset inside the block for the page ++ * @buf: the page to be sent ++ * @async: send to page asyncly ++ */ ++static int save_normal_page(RAMState *rs, RAMBlock *block, ram_addr_t offset, ++ uint8_t *buf, bool async) ++{ ++ ram_counters.transferred += save_page_header(rs, rs->f, block, ++ offset | RAM_SAVE_FLAG_PAGE); ++ if (async) { ++ qemu_put_buffer_async(rs->f, buf, TARGET_PAGE_SIZE, ++ migrate_release_ram() & ++ migration_in_postcopy()); ++ } else { ++ qemu_put_buffer(rs->f, buf, TARGET_PAGE_SIZE); ++ } ++ ram_counters.transferred += TARGET_PAGE_SIZE; ++ ram_counters.normal++; ++ return 1; ++} ++ + /** + * ram_save_page: send the given page to the stream + * +@@ -1053,18 +1081,7 @@ static int ram_save_page(RAMState *rs, PageSearchStatus *pss, bool last_stage) + + /* XBZRLE overflow or normal page */ + if (pages == -1) { +- ram_counters.transferred += +- save_page_header(rs, rs->f, block, offset | RAM_SAVE_FLAG_PAGE); +- if (send_async) { +- qemu_put_buffer_async(rs->f, p, TARGET_PAGE_SIZE, +- migrate_release_ram() & +- migration_in_postcopy()); +- } else { +- qemu_put_buffer(rs->f, p, TARGET_PAGE_SIZE); +- } +- ram_counters.transferred += TARGET_PAGE_SIZE; +- pages = 1; +- ram_counters.normal++; ++ pages = save_normal_page(rs, block, offset, p, send_async); + } + + XBZRLE_cache_unlock(); +@@ -1195,14 +1212,7 @@ static int ram_save_compressed_page(RAMState *rs, PageSearchStatus *pss, + * we post it as normal page as compression will take much + * CPU resource. + */ +- ram_counters.transferred += save_page_header(rs, rs->f, block, +- offset | RAM_SAVE_FLAG_PAGE); +- qemu_put_buffer_async(rs->f, p, TARGET_PAGE_SIZE, +- migrate_release_ram() & +- migration_in_postcopy()); +- ram_counters.transferred += TARGET_PAGE_SIZE; +- ram_counters.normal++; +- pages = 1; ++ pages = save_normal_page(rs, block, offset, p, true); + } else { + pages = compress_page_with_multi_thread(rs, block, offset); + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-migration-migrate-continue.patch b/SOURCES/kvm-migration-migrate-continue.patch deleted file mode 100644 index 91fe7f8..0000000 --- a/SOURCES/kvm-migration-migrate-continue.patch +++ /dev/null @@ -1,89 +0,0 @@ -From d6a77c209ff177aef13b9a52277a80c855b72c27 Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Wed, 25 Oct 2017 18:28:35 +0200 -Subject: [PATCH 16/19] migration: migrate-continue - -RH-Author: Dr. David Alan Gilbert -Message-id: <20171025182838.31829-5-dgilbert@redhat.com> -Patchwork-id: 77437 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH 4/7] migration: migrate-continue -Bugzilla: 1497120 -RH-Acked-by: Peter Xu -RH-Acked-by: Juan Quintela -RH-Acked-by: Miroslav Rezanina - -From: "Dr. David Alan Gilbert" - -A new qmp command allows the caller to continue from a given -paused state. - -Signed-off-by: Dr. David Alan Gilbert -Reviewed-by: Peter Xu -Reviewed-by: Juan Quintela -Signed-off-by: Juan Quintela -(cherry picked from commit 89cfc02cb6e3fdaf8ae246493ea51e75be2818c1) -Signed-off-by: Miroslav Rezanina - -Conflicts: - qapi/migration.json - still in qapi-schema.json - migration/migration.c - use MigrationState_lookup[] rather than new _str() function ---- - migration/migration.c | 11 +++++++++++ - qapi-schema.json | 17 +++++++++++++++++ - 2 files changed, 28 insertions(+) - -diff --git a/migration/migration.c b/migration/migration.c -index 436e122..3a1dabb 100644 ---- a/migration/migration.c -+++ b/migration/migration.c -@@ -1287,6 +1287,17 @@ void qmp_migrate_cancel(Error **errp) - migrate_fd_cancel(migrate_get_current()); - } - -+void qmp_migrate_continue(MigrationStatus state, Error **errp) -+{ -+ MigrationState *s = migrate_get_current(); -+ if (s->state != state) { -+ error_setg(errp, "Migration not in expected state: %s", -+ MigrationStatus_lookup[s->state]); -+ return; -+ } -+ qemu_sem_post(&s->pause_sem); -+} -+ - void qmp_migrate_set_cache_size(int64_t value, Error **errp) - { - MigrationState *s = migrate_get_current(); -diff --git a/qapi-schema.json b/qapi-schema.json -index de8c611..cd528c8 100644 ---- a/qapi-schema.json -+++ b/qapi-schema.json -@@ -2837,6 +2837,23 @@ - { 'command': 'migrate_cancel' } - - ## -+# @migrate-continue: -+# -+# Continue migration when it's in a paused state. -+# -+# @state: The state the migration is currently expected to be in -+# -+# Returns: nothing on success -+# Since: 2.11 -+# Example: -+# -+# -> { "execute": "migrate-continue" , "arguments": -+# { "state": "pre-switchover" } } -+# <- { "return": {} } -+## -+{ 'command': 'migrate-continue', 'data': {'state': 'MigrationStatus'} } -+ -+## - # @migrate_set_downtime: - # - # Set maximum tolerated downtime for migration. --- -1.8.3.1 - diff --git a/SOURCES/kvm-migration-move-calling-control_save_page-to-the-comm.patch b/SOURCES/kvm-migration-move-calling-control_save_page-to-the-comm.patch new file mode 100644 index 0000000..cd8f72e --- /dev/null +++ b/SOURCES/kvm-migration-move-calling-control_save_page-to-the-comm.patch @@ -0,0 +1,74 @@ +From 5233d49067a64ecb2c6ab2c91f4345a254f832f2 Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Fri, 22 Jun 2018 18:59:54 +0200 +Subject: [PATCH 15/57] migration: move calling control_save_page to the common + place + +RH-Author: Dr. David Alan Gilbert +Message-id: <20180622190005.21297-8-dgilbert@redhat.com> +Patchwork-id: 81000 +O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH 07/18] migration: move calling control_save_page to the common place +Bugzilla: 1584139 +RH-Acked-by: Peter Xu +RH-Acked-by: Juan Quintela +RH-Acked-by: Laurent Vivier + +From: Xiao Guangrong + +The function is called by both ram_save_page and ram_save_target_page, +so move it to the common caller to cleanup the code + +Reviewed-by: Peter Xu +Signed-off-by: Xiao Guangrong +Message-Id: <20180330075128.26919-8-xiaoguangrong@tencent.com> +Signed-off-by: Dr. David Alan Gilbert +(cherry picked from commit a8ec91f941c5f83123796331c09333d3557eb5fc) +Signed-off-by: Miroslav Rezanina +--- + migration/ram.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/migration/ram.c b/migration/ram.c +index 106fcf1..9d6c41c 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -1038,10 +1038,6 @@ static int ram_save_page(RAMState *rs, PageSearchStatus *pss, bool last_stage) + p = block->host + offset; + trace_ram_save_page(block->idstr, (uint64_t)offset, p); + +- if (control_save_page(rs, block, offset, &pages)) { +- return pages; +- } +- + XBZRLE_cache_lock(); + pages = save_zero_page(rs, block, offset); + if (pages > 0) { +@@ -1199,10 +1195,6 @@ static int ram_save_compressed_page(RAMState *rs, PageSearchStatus *pss, + + p = block->host + offset; + +- if (control_save_page(rs, block, offset, &pages)) { +- return pages; +- } +- + /* When starting the process of a new block, the first page of + * the block should be sent out before other pages in the same + * block, and all the pages in last block should have been sent +@@ -1490,6 +1482,14 @@ err: + static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss, + bool last_stage) + { ++ RAMBlock *block = pss->block; ++ ram_addr_t offset = pss->page << TARGET_PAGE_BITS; ++ int res; ++ ++ if (control_save_page(rs, block, offset, &res)) { ++ return res; ++ } ++ + /* + * If xbzrle is on, stop using the data compression after first + * round of migration even if compression is enabled. In theory, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-migration-move-calling-save_zero_page-to-the-common-.patch b/SOURCES/kvm-migration-move-calling-save_zero_page-to-the-common-.patch new file mode 100644 index 0000000..7a3a726 --- /dev/null +++ b/SOURCES/kvm-migration-move-calling-save_zero_page-to-the-common-.patch @@ -0,0 +1,175 @@ +From 81bfa8602be9c36955c451db641e66546732c59a Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Fri, 22 Jun 2018 18:59:55 +0200 +Subject: [PATCH 16/57] migration: move calling save_zero_page to the common + place + +RH-Author: Dr. David Alan Gilbert +Message-id: <20180622190005.21297-9-dgilbert@redhat.com> +Patchwork-id: 81006 +O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH 08/18] migration: move calling save_zero_page to the common place +Bugzilla: 1584139 +RH-Acked-by: Peter Xu +RH-Acked-by: Juan Quintela +RH-Acked-by: Laurent Vivier + +From: Xiao Guangrong + +save_zero_page() is always our first approach to try, move it to +the common place before calling ram_save_compressed_page +and ram_save_page + +Reviewed-by: Peter Xu +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Xiao Guangrong +Message-Id: <20180330075128.26919-9-xiaoguangrong@tencent.com> +Signed-off-by: Dr. David Alan Gilbert +(cherry picked from commit d7400a3409982a52ac451cd3ca9caee9db670ca7) +Signed-off-by: Miroslav Rezanina +--- + migration/ram.c | 105 +++++++++++++++++++++++++++++++------------------------- + 1 file changed, 59 insertions(+), 46 deletions(-) + +diff --git a/migration/ram.c b/migration/ram.c +index 9d6c41c..6e8a7e2 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -1039,15 +1039,8 @@ static int ram_save_page(RAMState *rs, PageSearchStatus *pss, bool last_stage) + trace_ram_save_page(block->idstr, (uint64_t)offset, p); + + XBZRLE_cache_lock(); +- pages = save_zero_page(rs, block, offset); +- if (pages > 0) { +- /* Must let xbzrle know, otherwise a previous (now 0'd) cached +- * page would be stale +- */ +- xbzrle_cache_zero_page(rs, current_addr); +- ram_release_pages(block->idstr, offset, pages); +- } else if (!rs->ram_bulk_stage && +- !migration_in_postcopy() && migrate_use_xbzrle()) { ++ if (!rs->ram_bulk_stage && !migration_in_postcopy() && ++ migrate_use_xbzrle()) { + pages = save_xbzrle_page(rs, &p, current_addr, block, + offset, last_stage); + if (!last_stage) { +@@ -1195,40 +1188,23 @@ static int ram_save_compressed_page(RAMState *rs, PageSearchStatus *pss, + + p = block->host + offset; + +- /* When starting the process of a new block, the first page of +- * the block should be sent out before other pages in the same +- * block, and all the pages in last block should have been sent +- * out, keeping this order is important, because the 'cont' flag +- * is used to avoid resending the block name. +- */ + if (block != rs->last_sent_block) { +- flush_compressed_data(rs); +- pages = save_zero_page(rs, block, offset); +- if (pages > 0) { +- ram_release_pages(block->idstr, offset, pages); +- } else { +- /* +- * Make sure the first page is sent out before other pages. +- * +- * we post it as normal page as compression will take much +- * CPU resource. +- */ +- ram_counters.transferred += save_page_header(rs, rs->f, block, +- offset | RAM_SAVE_FLAG_PAGE); +- qemu_put_buffer_async(rs->f, p, TARGET_PAGE_SIZE, +- migrate_release_ram() & +- migration_in_postcopy()); +- ram_counters.transferred += TARGET_PAGE_SIZE; +- ram_counters.normal++; +- pages = 1; +- } ++ /* ++ * Make sure the first page is sent out before other pages. ++ * ++ * we post it as normal page as compression will take much ++ * CPU resource. ++ */ ++ ram_counters.transferred += save_page_header(rs, rs->f, block, ++ offset | RAM_SAVE_FLAG_PAGE); ++ qemu_put_buffer_async(rs->f, p, TARGET_PAGE_SIZE, ++ migrate_release_ram() & ++ migration_in_postcopy()); ++ ram_counters.transferred += TARGET_PAGE_SIZE; ++ ram_counters.normal++; ++ pages = 1; + } else { +- pages = save_zero_page(rs, block, offset); +- if (pages == -1) { +- pages = compress_page_with_multi_thread(rs, block, offset); +- } else { +- ram_release_pages(block->idstr, offset, pages); +- } ++ pages = compress_page_with_multi_thread(rs, block, offset); + } + + return pages; +@@ -1470,6 +1446,24 @@ err: + return -1; + } + ++static bool save_page_use_compression(RAMState *rs) ++{ ++ if (!migrate_use_compression()) { ++ return false; ++ } ++ ++ /* ++ * If xbzrle is on, stop using the data compression after first ++ * round of migration even if compression is enabled. In theory, ++ * xbzrle can do better than compression. ++ */ ++ if (rs->ram_bulk_stage || !migrate_use_xbzrle()) { ++ return true; ++ } ++ ++ return false; ++} ++ + /** + * ram_save_target_page: save one target page + * +@@ -1491,12 +1485,31 @@ static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss, + } + + /* +- * If xbzrle is on, stop using the data compression after first +- * round of migration even if compression is enabled. In theory, +- * xbzrle can do better than compression. ++ * When starting the process of a new block, the first page of ++ * the block should be sent out before other pages in the same ++ * block, and all the pages in last block should have been sent ++ * out, keeping this order is important, because the 'cont' flag ++ * is used to avoid resending the block name. + */ +- if (migrate_use_compression() && +- (rs->ram_bulk_stage || !migrate_use_xbzrle())) { ++ if (block != rs->last_sent_block && save_page_use_compression(rs)) { ++ flush_compressed_data(rs); ++ } ++ ++ res = save_zero_page(rs, block, offset); ++ if (res > 0) { ++ /* Must let xbzrle know, otherwise a previous (now 0'd) cached ++ * page would be stale ++ */ ++ if (!save_page_use_compression(rs)) { ++ XBZRLE_cache_lock(); ++ xbzrle_cache_zero_page(rs, block->offset + offset); ++ XBZRLE_cache_unlock(); ++ } ++ ram_release_pages(block->idstr, offset, res); ++ return res; ++ } ++ ++ if (save_page_use_compression(rs)) { + return ram_save_compressed_page(rs, pss, last_stage); + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-migration-move-some-code-to-ram_save_host_page.patch b/SOURCES/kvm-migration-move-some-code-to-ram_save_host_page.patch new file mode 100644 index 0000000..2bb7c69 --- /dev/null +++ b/SOURCES/kvm-migration-move-some-code-to-ram_save_host_page.patch @@ -0,0 +1,108 @@ +From cb638b3d14fb19db26f6108a08f1a3b62a96b6c3 Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Fri, 22 Jun 2018 18:59:53 +0200 +Subject: [PATCH 14/57] migration: move some code to ram_save_host_page + +RH-Author: Dr. David Alan Gilbert +Message-id: <20180622190005.21297-7-dgilbert@redhat.com> +Patchwork-id: 81007 +O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH 06/18] migration: move some code to ram_save_host_page +Bugzilla: 1584139 +RH-Acked-by: Peter Xu +RH-Acked-by: Juan Quintela +RH-Acked-by: Laurent Vivier + +From: Xiao Guangrong + +Move some code from ram_save_target_page() to ram_save_host_page() +to make it be more readable for latter patches that dramatically +clean ram_save_target_page() up + +Reviewed-by: Peter Xu +Signed-off-by: Xiao Guangrong +Message-Id: <20180330075128.26919-7-xiaoguangrong@tencent.com> +Signed-off-by: Dr. David Alan Gilbert +(cherry picked from commit 1faa5665c0f1df2eff291454a3a85625a3bc93dd) +Signed-off-by: Miroslav Rezanina +--- + migration/ram.c | 43 +++++++++++++++++++------------------------ + 1 file changed, 19 insertions(+), 24 deletions(-) + +diff --git a/migration/ram.c b/migration/ram.c +index 8dc98a5..106fcf1 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -1484,38 +1484,23 @@ err: + * Returns the number of pages written + * + * @rs: current RAM state +- * @ms: current migration state + * @pss: data about the page we want to send + * @last_stage: if we are at the completion stage + */ + static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss, + bool last_stage) + { +- int res = 0; +- +- /* Check the pages is dirty and if it is send it */ +- if (migration_bitmap_clear_dirty(rs, pss->block, pss->page)) { +- /* +- * If xbzrle is on, stop using the data compression after first +- * round of migration even if compression is enabled. In theory, +- * xbzrle can do better than compression. +- */ +- if (migrate_use_compression() && +- (rs->ram_bulk_stage || !migrate_use_xbzrle())) { +- res = ram_save_compressed_page(rs, pss, last_stage); +- } else { +- res = ram_save_page(rs, pss, last_stage); +- } +- +- if (res < 0) { +- return res; +- } +- if (pss->block->unsentmap) { +- clear_bit(pss->page, pss->block->unsentmap); +- } ++ /* ++ * If xbzrle is on, stop using the data compression after first ++ * round of migration even if compression is enabled. In theory, ++ * xbzrle can do better than compression. ++ */ ++ if (migrate_use_compression() && ++ (rs->ram_bulk_stage || !migrate_use_xbzrle())) { ++ return ram_save_compressed_page(rs, pss, last_stage); + } + +- return res; ++ return ram_save_page(rs, pss, last_stage); + } + + /** +@@ -1544,12 +1529,22 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss, + qemu_ram_pagesize(pss->block) >> TARGET_PAGE_BITS; + + do { ++ /* Check the pages is dirty and if it is send it */ ++ if (!migration_bitmap_clear_dirty(rs, pss->block, pss->page)) { ++ pss->page++; ++ continue; ++ } ++ + tmppages = ram_save_target_page(rs, pss, last_stage); + if (tmppages < 0) { + return tmppages; + } + + pages += tmppages; ++ if (pss->block->unsentmap) { ++ clear_bit(pss->page, pss->block->unsentmap); ++ } ++ + pss->page++; + } while ((pss->page & (pagesize_bits - 1)) && + offset_in_ramblock(pss->block, pss->page << TARGET_PAGE_BITS)); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-migration-not-wait-RDMA_CM_EVENT_DISCONNECTED-event-.patch b/SOURCES/kvm-migration-not-wait-RDMA_CM_EVENT_DISCONNECTED-event-.patch new file mode 100644 index 0000000..18acc71 --- /dev/null +++ b/SOURCES/kvm-migration-not-wait-RDMA_CM_EVENT_DISCONNECTED-event-.patch @@ -0,0 +1,110 @@ +From 1465b08194e396304b2425d86bcfda85f3b98b9f Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Fri, 22 Jun 2018 19:00:04 +0200 +Subject: [PATCH 25/57] migration: not wait RDMA_CM_EVENT_DISCONNECTED event + after rdma_disconnect + +RH-Author: Dr. David Alan Gilbert +Message-id: <20180622190005.21297-18-dgilbert@redhat.com> +Patchwork-id: 81008 +O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH 17/18] migration: not wait RDMA_CM_EVENT_DISCONNECTED event after rdma_disconnect +Bugzilla: 1584139 +RH-Acked-by: Juan Quintela +RH-Acked-by: Peter Xu +RH-Acked-by: Laurent Vivier + +From: Lidong Chen + +When cancel migration during RDMA precopy, the source qemu main thread hangs sometime. + +The backtrace is: + (gdb) bt + #0 0x00007f249eabd43d in write () from /lib64/libpthread.so.0 + #1 0x00007f24a1ce98e4 in rdma_get_cm_event (channel=0x4675d10, event=0x7ffe2f643dd0) at src/cma.c:2189 + #2 0x00000000007b6166 in qemu_rdma_cleanup (rdma=0x6784000) at migration/rdma.c:2296 + #3 0x00000000007b7cae in qio_channel_rdma_close (ioc=0x3bfcc30, errp=0x0) at migration/rdma.c:2999 + #4 0x00000000008db60e in qio_channel_close (ioc=0x3bfcc30, errp=0x0) at io/channel.c:273 + #5 0x00000000007a8765 in channel_close (opaque=0x3bfcc30) at migration/qemu-file-channel.c:98 + #6 0x00000000007a71f9 in qemu_fclose (f=0x527c000) at migration/qemu-file.c:334 + #7 0x0000000000795b96 in migrate_fd_cleanup (opaque=0x3b46280) at migration/migration.c:1162 + #8 0x000000000093a71b in aio_bh_call (bh=0x3db7a20) at util/async.c:90 + #9 0x000000000093a7b2 in aio_bh_poll (ctx=0x3b121c0) at util/async.c:118 + #10 0x000000000093f2ad in aio_dispatch (ctx=0x3b121c0) at util/aio-posix.c:436 + #11 0x000000000093ab41 in aio_ctx_dispatch (source=0x3b121c0, callback=0x0, user_data=0x0) + at util/async.c:261 + #12 0x00007f249f73c7aa in g_main_context_dispatch () from /lib64/libglib-2.0.so.0 + #13 0x000000000093dc5e in glib_pollfds_poll () at util/main-loop.c:215 + #14 0x000000000093dd4e in os_host_main_loop_wait (timeout=28000000) at util/main-loop.c:263 + #15 0x000000000093de05 in main_loop_wait (nonblocking=0) at util/main-loop.c:522 + #16 0x00000000005bc6a5 in main_loop () at vl.c:1944 + #17 0x00000000005c39b5 in main (argc=56, argv=0x7ffe2f6443f8, envp=0x3ad0030) at vl.c:4752 + +It does not get the RDMA_CM_EVENT_DISCONNECTED event after rdma_disconnect sometime. + +According to IB Spec once active side send DREQ message, it should wait for DREP message +and only once it arrived it should trigger a DISCONNECT event. DREP message can be dropped +due to network issues. +For that case the spec defines a DREP_timeout state in the CM state machine, if the DREP is +dropped we should get a timeout and a TIMEWAIT_EXIT event will be trigger. +Unfortunately the current kernel CM implementation doesn't include the DREP_timeout state +and in above scenario we will not get DISCONNECT or TIMEWAIT_EXIT events. + +So it should not invoke rdma_get_cm_event which may hang forever, and the event channel +is also destroyed in qemu_rdma_cleanup. + +Signed-off-by: Lidong Chen +Reviewed-by: Juan Quintela +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Juan Quintela +(cherry picked from commit c5e76115ccb4979cec795a8ae38becd07c2fde9f) +Signed-off-by: Miroslav Rezanina +--- + migration/rdma.c | 12 ++---------- + migration/trace-events | 1 - + 2 files changed, 2 insertions(+), 11 deletions(-) + +diff --git a/migration/rdma.c b/migration/rdma.c +index 7d233b0..6e29ebf 100644 +--- a/migration/rdma.c ++++ b/migration/rdma.c +@@ -2268,8 +2268,7 @@ static int qemu_rdma_write(QEMUFile *f, RDMAContext *rdma, + + static void qemu_rdma_cleanup(RDMAContext *rdma) + { +- struct rdma_cm_event *cm_event; +- int ret, idx; ++ int idx; + + if (rdma->cm_id && rdma->connected) { + if ((rdma->error_state || +@@ -2283,14 +2282,7 @@ static void qemu_rdma_cleanup(RDMAContext *rdma) + qemu_rdma_post_send_control(rdma, NULL, &head); + } + +- ret = rdma_disconnect(rdma->cm_id); +- if (!ret) { +- trace_qemu_rdma_cleanup_waiting_for_disconnect(); +- ret = rdma_get_cm_event(rdma->channel, &cm_event); +- if (!ret) { +- rdma_ack_cm_event(cm_event); +- } +- } ++ rdma_disconnect(rdma->cm_id); + trace_qemu_rdma_cleanup_disconnect(); + rdma->connected = false; + } +diff --git a/migration/trace-events b/migration/trace-events +index a180d7b..92b3179 100644 +--- a/migration/trace-events ++++ b/migration/trace-events +@@ -123,7 +123,6 @@ qemu_rdma_accept_pin_state(bool pin) "%d" + qemu_rdma_accept_pin_verbsc(void *verbs) "Verbs context after listen: %p" + qemu_rdma_block_for_wrid_miss(const char *wcompstr, int wcomp, const char *gcompstr, uint64_t req) "A Wanted wrid %s (%d) but got %s (%" PRIu64 ")" + qemu_rdma_cleanup_disconnect(void) "" +-qemu_rdma_cleanup_waiting_for_disconnect(void) "" + qemu_rdma_close(void) "" + qemu_rdma_connect_pin_all_requested(void) "" + qemu_rdma_connect_pin_all_outcome(bool pin) "%d" +-- +1.8.3.1 + diff --git a/SOURCES/kvm-migration-pause-before-switchover-for-postcopy.patch b/SOURCES/kvm-migration-pause-before-switchover-for-postcopy.patch deleted file mode 100644 index 8e699af..0000000 --- a/SOURCES/kvm-migration-pause-before-switchover-for-postcopy.patch +++ /dev/null @@ -1,110 +0,0 @@ -From 2dc02b39b051394ddbd01aec19bf2f0658d9b56c Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Wed, 25 Oct 2017 18:28:38 +0200 -Subject: [PATCH 19/19] migration: pause-before-switchover for postcopy - -RH-Author: Dr. David Alan Gilbert -Message-id: <20171025182838.31829-8-dgilbert@redhat.com> -Patchwork-id: 77441 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH 7/7] migration: pause-before-switchover for postcopy -Bugzilla: 1497120 -RH-Acked-by: Peter Xu -RH-Acked-by: Juan Quintela -RH-Acked-by: Miroslav Rezanina - -From: "Dr. David Alan Gilbert" - -Add pause-before-switchover support for postcopy. -After starting postcopy it will transition - active->pre-switchover->postcopy_active - -Signed-off-by: Dr. David Alan Gilbert -Reviewed-by: Peter Xu -Reviewed-by: Juan Quintela -Signed-off-by: Juan Quintela -(cherry picked from commit 0331c8cabf6168aa263aa0b25f5e135b328606ac) -Signed-off-by: Miroslav Rezanina ---- - migration/migration.c | 29 ++++++++++++++++++++++------- - 1 file changed, 22 insertions(+), 7 deletions(-) - -diff --git a/migration/migration.c b/migration/migration.c -index 3f23ed0..1288697 100644 ---- a/migration/migration.c -+++ b/migration/migration.c -@@ -105,6 +105,9 @@ bool migrate_pre_2_2; - static MigrationState *current_migration; - - static bool migration_object_check(MigrationState *ms, Error **errp); -+static int migration_maybe_pause(MigrationState *s, -+ int *current_active_state, -+ int new_state); - - void migration_object_init(void) - { -@@ -1717,8 +1720,11 @@ static int postcopy_start(MigrationState *ms, bool *old_vm_running) - QEMUFile *fb; - int64_t time_at_stop = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); - bool restart_block = false; -- migrate_set_state(&ms->state, MIGRATION_STATUS_ACTIVE, -- MIGRATION_STATUS_POSTCOPY_ACTIVE); -+ int cur_state = MIGRATION_STATUS_ACTIVE; -+ if (!migrate_pause_before_switchover()) { -+ migrate_set_state(&ms->state, MIGRATION_STATUS_ACTIVE, -+ MIGRATION_STATUS_POSTCOPY_ACTIVE); -+ } - - trace_postcopy_start(); - qemu_mutex_lock_iothread(); -@@ -1732,6 +1738,12 @@ static int postcopy_start(MigrationState *ms, bool *old_vm_running) - goto fail; - } - -+ ret = migration_maybe_pause(ms, &cur_state, -+ MIGRATION_STATUS_POSTCOPY_ACTIVE); -+ if (ret < 0) { -+ goto fail; -+ } -+ - ret = bdrv_inactivate_all(); - if (ret < 0) { - goto fail; -@@ -1866,7 +1878,9 @@ fail: - * migrate_pause_before_switchover called with the iothread locked - * Returns: 0 on success - */ --static int migration_maybe_pause(MigrationState *s, int *current_active_state) -+static int migration_maybe_pause(MigrationState *s, -+ int *current_active_state, -+ int new_state) - { - if (!migrate_pause_before_switchover()) { - return 0; -@@ -1887,11 +1901,11 @@ static int migration_maybe_pause(MigrationState *s, int *current_active_state) - MIGRATION_STATUS_PRE_SWITCHOVER); - qemu_sem_wait(&s->pause_sem); - migrate_set_state(&s->state, MIGRATION_STATUS_PRE_SWITCHOVER, -- MIGRATION_STATUS_DEVICE); -- *current_active_state = MIGRATION_STATUS_DEVICE; -+ new_state); -+ *current_active_state = new_state; - qemu_mutex_lock_iothread(); - -- return s->state == MIGRATION_STATUS_DEVICE ? 0 : -EINVAL; -+ return s->state == new_state ? 0 : -EINVAL; - } - - /** -@@ -1920,7 +1934,8 @@ static void migration_completion(MigrationState *s, int current_active_state, - bool inactivate = !migrate_colo_enabled(); - ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); - if (ret >= 0) { -- ret = migration_maybe_pause(s, ¤t_active_state); -+ ret = migration_maybe_pause(s, ¤t_active_state, -+ MIGRATION_STATUS_DEVICE); - } - if (ret >= 0) { - qemu_file_set_rate_limit(s->to_dst_file, INT64_MAX); --- -1.8.3.1 - diff --git a/SOURCES/kvm-migration-ram-Add-check-and-info-message-to-nvdimm-p.patch b/SOURCES/kvm-migration-ram-Add-check-and-info-message-to-nvdimm-p.patch new file mode 100644 index 0000000..e3eff46 --- /dev/null +++ b/SOURCES/kvm-migration-ram-Add-check-and-info-message-to-nvdimm-p.patch @@ -0,0 +1,56 @@ +From 4251549eca8b113b508f6bf6a7aaca2541acda61 Mon Sep 17 00:00:00 2001 +From: "plai@redhat.com" +Date: Fri, 31 Aug 2018 16:25:58 +0200 +Subject: [PATCH 16/29] migration/ram: Add check and info message to nvdimm + post copy. + +RH-Author: plai@redhat.com +Message-id: <1535732759-22481-9-git-send-email-plai@redhat.com> +Patchwork-id: 82009 +O-Subject: [RHEL7.6 PATCH BZ 1539280 8/9] migration/ram: Add check and info message to nvdimm post copy. +Bugzilla: 1539280 +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Pankaj Gupta +RH-Acked-by: Miroslav Rezanina + +From: Junyan He + +The nvdimm kind memory does not support post copy now. +We disable post copy if we have nvdimm memory and print some +log hint to user. + +Signed-off-by: Junyan He +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Igor Mammedov +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 469dd51bc664979f159d47885997d482991394b8) +Signed-off-by: Paul Lai +Signed-off-by: Miroslav Rezanina +--- + migration/ram.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/migration/ram.c b/migration/ram.c +index 04b5df5..f850fd0 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -3120,6 +3120,15 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) + + static bool ram_has_postcopy(void *opaque) + { ++ RAMBlock *rb; ++ RAMBLOCK_FOREACH_MIGRATABLE(rb) { ++ if (ramblock_is_pmem(rb)) { ++ info_report("Block: %s, host: %p is a nvdimm memory, postcopy" ++ "is not supported now!", rb->idstr, rb->host); ++ return false; ++ } ++ } ++ + return migrate_postcopy_ram(); + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-migration-ram-ensure-write-persistence-on-loading-al.patch b/SOURCES/kvm-migration-ram-ensure-write-persistence-on-loading-al.patch new file mode 100644 index 0000000..afa614b --- /dev/null +++ b/SOURCES/kvm-migration-ram-ensure-write-persistence-on-loading-al.patch @@ -0,0 +1,81 @@ +From 3d60cee570db578cc7589cac9844129e9ac9d460 Mon Sep 17 00:00:00 2001 +From: "plai@redhat.com" +Date: Fri, 31 Aug 2018 16:25:59 +0200 +Subject: [PATCH 17/29] migration/ram: ensure write persistence on loading all + data to PMEM. + +RH-Author: plai@redhat.com +Message-id: <1535732759-22481-10-git-send-email-plai@redhat.com> +Patchwork-id: 82008 +O-Subject: [RHEL7.6 PATCH BZ 1539280 9/9] migration/ram: ensure write persistence on loading all data to PMEM. +Bugzilla: 1539280 +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Pankaj Gupta +RH-Acked-by: Miroslav Rezanina + +From: Junyan He + +Because we need to make sure the pmem kind memory data is synced +after migration, we choose to call pmem_persist() when the migration +finish. This will make sure the data of pmem is safe and will not +lose if power is off. + +Signed-off-by: Junyan He +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Igor Mammedov +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 56eb90af39abf66c0e80588a9f50c31e7df7320b) +Signed-off-by: Paul Lai +Signed-off-by: Miroslav Rezanina +--- + include/qemu/pmem.h | 6 ++++++ + migration/ram.c | 8 ++++++++ + 2 files changed, 14 insertions(+) + +diff --git a/include/qemu/pmem.h b/include/qemu/pmem.h +index ebdb070..dfb6d0d 100644 +--- a/include/qemu/pmem.h ++++ b/include/qemu/pmem.h +@@ -25,6 +25,12 @@ pmem_memcpy_persist(void *pmemdest, const void *src, size_t len) + return NULL; + } + ++static inline void ++pmem_persist(const void *addr, size_t len) ++{ ++ g_assert_not_reached(); ++} ++ + #endif /* CONFIG_LIBPMEM */ + + #endif /* !QEMU_PMEM_H */ +diff --git a/migration/ram.c b/migration/ram.c +index f850fd0..aba0f70 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -33,6 +33,7 @@ + #include "qemu/bitops.h" + #include "qemu/bitmap.h" + #include "qemu/main-loop.h" ++#include "qemu/pmem.h" + #include "xbzrle.h" + #include "ram.h" + #include "migration.h" +@@ -2766,6 +2767,13 @@ static int ram_load_setup(QEMUFile *f, void *opaque) + static int ram_load_cleanup(void *opaque) + { + RAMBlock *rb; ++ ++ RAMBLOCK_FOREACH_MIGRATABLE(rb) { ++ if (ramblock_is_pmem(rb)) { ++ pmem_persist(rb->host, rb->used_length); ++ } ++ } ++ + xbzrle_load_cleanup(); + compress_threads_load_cleanup(); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-migration-ram.c-do-not-set-postcopy_running-in-POSTC.patch b/SOURCES/kvm-migration-ram.c-do-not-set-postcopy_running-in-POSTC.patch deleted file mode 100644 index 69fbee4..0000000 --- a/SOURCES/kvm-migration-ram.c-do-not-set-postcopy_running-in-POSTC.patch +++ /dev/null @@ -1,124 +0,0 @@ -From 50f063769cf74d2d37adbc5b568b545d2562af65 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Tue, 28 Nov 2017 10:30:08 +0100 -Subject: [PATCH 15/21] migration/ram.c: do not set 'postcopy_running' in - POSTCOPY_INCOMING_END - -RH-Author: Laurent Vivier -Message-id: <20171128103008.1150-1-lvivier@redhat.com> -Patchwork-id: 77931 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH] migration/ram.c: do not set 'postcopy_running' in POSTCOPY_INCOMING_END -Bugzilla: 1516956 -RH-Acked-by: Peter Xu -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Juan Quintela -RH-Acked-by: David Gibson - -From: Daniel Henrique Barboza - -When migrating a VM with 'migrate_set_capability postcopy-ram on' -a postcopy_state is set during the process, ending up with the -state POSTCOPY_INCOMING_END when the migration is over. This -postcopy_state is taken into account inside ram_load to check -how it will load the memory pages. This same ram_load is called when -in a loadvm command. - -Inside ram_load, the logic to see if we're at postcopy_running state -is: - -postcopy_running = postcopy_state_get() >= POSTCOPY_INCOMING_LISTENING - -postcopy_state_get() returns this enum type: - -typedef enum { - POSTCOPY_INCOMING_NONE = 0, - POSTCOPY_INCOMING_ADVISE, - POSTCOPY_INCOMING_DISCARD, - POSTCOPY_INCOMING_LISTENING, - POSTCOPY_INCOMING_RUNNING, - POSTCOPY_INCOMING_END -} PostcopyState; - -In the case where ram_load is executed and postcopy_state is -POSTCOPY_INCOMING_END, postcopy_running will be set to 'true' and -ram_load will behave like a postcopy is in progress. This scenario isn't -achievable in a migration but it is reproducible when executing -savevm/loadvm after migrating with 'postcopy-ram on', causing loadvm -to fail with Error -22: - -Source: - -(qemu) migrate_set_capability postcopy-ram on -(qemu) migrate tcp:127.0.0.1:4444 - -Dest: - -(qemu) migrate_set_capability postcopy-ram on -(qemu) -ubuntu1704-intel login: -Ubuntu 17.04 ubuntu1704-intel ttyS0 - -ubuntu1704-intel login: (qemu) -(qemu) savevm test1 -(qemu) loadvm test1 -Unknown combination of migration flags: 0x4 (postcopy mode) -error while loading state for instance 0x0 of device 'ram' -Error -22 while loading VM state -(qemu) - -This patch fixes this problem by changing the existing logic for -postcopy_advised and postcopy_running in ram_load, making them -'false' if we're at POSTCOPY_INCOMING_END state. - -Signed-off-by: Daniel Henrique Barboza -CC: Juan Quintela -CC: Dr. David Alan Gilbert -Reviewed-by: Peter Xu -Reviewed-by: Juan Quintela -Reported-by: Balamuruhan S -Signed-off-by: Juan Quintela -(cherry picked from commit acab30b85db0885ab161aff4c83c550628f6d8ca) -Signed-off-by: Laurent Vivier -Signed-off-by: Miroslav Rezanina ---- - migration/ram.c | 16 ++++++++++++++-- - 1 file changed, 14 insertions(+), 2 deletions(-) - -diff --git a/migration/ram.c b/migration/ram.c -index e18b3e2..fef80fd 100644 ---- a/migration/ram.c -+++ b/migration/ram.c -@@ -2484,6 +2484,18 @@ static int ram_load_postcopy(QEMUFile *f) - return ret; - } - -+static bool postcopy_is_advised(void) -+{ -+ PostcopyState ps = postcopy_state_get(); -+ return ps >= POSTCOPY_INCOMING_ADVISE && ps < POSTCOPY_INCOMING_END; -+} -+ -+static bool postcopy_is_running(void) -+{ -+ PostcopyState ps = postcopy_state_get(); -+ return ps >= POSTCOPY_INCOMING_LISTENING && ps < POSTCOPY_INCOMING_END; -+} -+ - static int ram_load(QEMUFile *f, void *opaque, int version_id) - { - int flags = 0, ret = 0, invalid_flags = 0; -@@ -2493,9 +2505,9 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) - * If system is running in postcopy mode, page inserts to host memory must - * be atomic - */ -- bool postcopy_running = postcopy_state_get() >= POSTCOPY_INCOMING_LISTENING; -+ bool postcopy_running = postcopy_is_running(); - /* ADVISE is earlier, it shows the source has the postcopy capability on */ -- bool postcopy_advised = postcopy_state_get() >= POSTCOPY_INCOMING_ADVISE; -+ bool postcopy_advised = postcopy_is_advised(); - - seq_iter++; - --- -1.8.3.1 - diff --git a/SOURCES/kvm-migration-remove-ram_save_compressed_page.patch b/SOURCES/kvm-migration-remove-ram_save_compressed_page.patch new file mode 100644 index 0000000..e703fc3 --- /dev/null +++ b/SOURCES/kvm-migration-remove-ram_save_compressed_page.patch @@ -0,0 +1,97 @@ +From 5c9d6d50076df3032b1d09196e36c33004eb52fb Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Fri, 22 Jun 2018 18:59:57 +0200 +Subject: [PATCH 18/57] migration: remove ram_save_compressed_page() + +RH-Author: Dr. David Alan Gilbert +Message-id: <20180622190005.21297-11-dgilbert@redhat.com> +Patchwork-id: 81011 +O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH 10/18] migration: remove ram_save_compressed_page() +Bugzilla: 1584139 +RH-Acked-by: Juan Quintela +RH-Acked-by: Peter Xu +RH-Acked-by: Laurent Vivier + +From: Xiao Guangrong + +Now, we can reuse the path in ram_save_page() to post the page out +as normal, then the only thing remained in ram_save_compressed_page() +is compression that we can move it out to the caller + +Reviewed-by: Peter Xu +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Xiao Guangrong +Message-Id: <20180330075128.26919-11-xiaoguangrong@tencent.com> +Signed-off-by: Dr. David Alan Gilbert +(cherry picked from commit da3f56cb2e767016d3f204837a77caf35b463f90) +Signed-off-by: Miroslav Rezanina +--- + migration/ram.c | 45 ++++++++------------------------------------- + 1 file changed, 8 insertions(+), 37 deletions(-) + +diff --git a/migration/ram.c b/migration/ram.c +index 908879f..466609f 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -1186,41 +1186,6 @@ static int compress_page_with_multi_thread(RAMState *rs, RAMBlock *block, + } + + /** +- * ram_save_compressed_page: compress the given page and send it to the stream +- * +- * Returns the number of pages written. +- * +- * @rs: current RAM state +- * @block: block that contains the page we want to send +- * @offset: offset inside the block for the page +- * @last_stage: if we are at the completion stage +- */ +-static int ram_save_compressed_page(RAMState *rs, PageSearchStatus *pss, +- bool last_stage) +-{ +- int pages = -1; +- uint8_t *p; +- RAMBlock *block = pss->block; +- ram_addr_t offset = pss->page << TARGET_PAGE_BITS; +- +- p = block->host + offset; +- +- if (block != rs->last_sent_block) { +- /* +- * Make sure the first page is sent out before other pages. +- * +- * we post it as normal page as compression will take much +- * CPU resource. +- */ +- pages = save_normal_page(rs, block, offset, p, true); +- } else { +- pages = compress_page_with_multi_thread(rs, block, offset); +- } +- +- return pages; +-} +- +-/** + * find_dirty_block: find the next dirty page and update any state + * associated with the search process. + * +@@ -1519,8 +1484,14 @@ static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss, + return res; + } + +- if (save_page_use_compression(rs)) { +- return ram_save_compressed_page(rs, pss, last_stage); ++ /* ++ * Make sure the first page is sent out before other pages. ++ * ++ * we post it as normal page as compression will take much ++ * CPU resource. ++ */ ++ if (block == rs->last_sent_block && save_page_use_compression(rs)) { ++ res = compress_page_with_multi_thread(rs, block, offset); + } + + return ram_save_page(rs, pss, last_stage); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-migration-savevm.c-set-MAX_VM_CMD_PACKAGED_SIZE-to-1.patch b/SOURCES/kvm-migration-savevm.c-set-MAX_VM_CMD_PACKAGED_SIZE-to-1.patch deleted file mode 100644 index 76f29f3..0000000 --- a/SOURCES/kvm-migration-savevm.c-set-MAX_VM_CMD_PACKAGED_SIZE-to-1.patch +++ /dev/null @@ -1,79 +0,0 @@ -From a3df1677bfe1f2ae0a6bcb54f745b08b211369ce Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Wed, 7 Feb 2018 15:47:54 +0100 -Subject: [PATCH 02/15] migration/savevm.c: set MAX_VM_CMD_PACKAGED_SIZE to 1ul - << 32 - -RH-Author: Laurent Vivier -Message-id: <20180207154754.9064-1-lvivier@redhat.com> -Patchwork-id: 78921 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH] migration/savevm.c: set MAX_VM_CMD_PACKAGED_SIZE to 1ul << 32 -Bugzilla: 1540003 -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: David Gibson -RH-Acked-by: Thomas Huth - -From: Daniel Henrique Barboza - -MAX_VM_CMD_PACKAGED_SIZE is a constant used in qemu_savevm_send_packaged -and loadvm_handle_cmd_packaged to determine whether a package is too -big to be sent or received. qemu_savevm_send_packaged is called inside -postcopy_start (migration/migration.c) to send the MigrationState -in a single blob to the destination, using the MIG_CMD_PACKAGED subcommand, -which will read it up using loadvm_handle_cmd_packaged. If the blob is -larger than MAX_VM_CMD_PACKAGED_SIZE, an error is thrown and the postcopy -migration is aborted. Both MAX_VM_CMD_PACKAGED_SIZE and MIG_CMD_PACKAGED -were introduced by commit 11cf1d984b ("MIG_CMD_PACKAGED: Send a packaged -chunk ..."). The constant has its original value of 1ul << 24 (16MB). - -The current MAX_VM_CMD_PACKAGED_SIZE value is not enough to support postcopy -migration of bigger pseries guests. The blob size for a postcopy migration of -a pseries guest with the following setup: - -qemu-system-ppc64 --nographic -vga none -machine pseries,accel=kvm -m 64G \ --smp 1,maxcpus=32 -device virtio-blk-pci,drive=rootdisk \ --drive file=f27.qcow2,if=none,cache=none,format=qcow2,id=rootdisk \ --netdev user,id=u1 -net nic,netdev=u1 - -Goes around 12MB. Bumping the RAM to 128G makes the blob sizes goes to 20MB. -With 256G the blob goes to 37MB - more than twice the current maximum size. -At this moment the pseries machine can handle guests with up to 1TB of RAM, -making this postcopy blob goes to 128MB of size approximately. - -Following the discussions made in [1], there is a need to understand what -devices are aggressively consuming the blob in that manner and see if that -can be mitigated. Until then, we can set MAX_VM_CMD_PACKAGED_SIZE to the -maximum value allowed. Since the size is a 32 bit int variable, we can set -it as 1ul << 32, giving a maximum blob size of 4G that is enough to support -postcopy migration of 32TB RAM guests given the above constraints. - -[1] https://lists.nongnu.org/archive/html/qemu-devel/2018-01/msg06313.html - -Signed-off-by: Daniel Henrique Barboza -Reported-by: Balamuruhan S -Reviewed-by: Juan Quintela -Signed-off-by: Juan Quintela -Signed-off-by: Dr. David Alan Gilbert -(cherry picked from commit ee555cdf4d495ddd83633406e3099c5d1ef22e0a) -Signed-off-by: Laurent Vivier -Signed-off-by: Miroslav Rezanina ---- - migration/savevm.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/migration/savevm.c b/migration/savevm.c -index 5eb3504..c466921 100644 ---- a/migration/savevm.c -+++ b/migration/savevm.c -@@ -83,7 +83,7 @@ enum qemu_vm_cmd { - }; - bool shadow_bios_after_incoming; - --#define MAX_VM_CMD_PACKAGED_SIZE (1ul << 24) -+#define MAX_VM_CMD_PACKAGED_SIZE UINT32_MAX - static struct mig_cmd_args { - ssize_t len; /* -1 = variable */ - const char *name; --- -1.8.3.1 - diff --git a/SOURCES/kvm-migration-stop-compressing-page-in-migration-thread.patch b/SOURCES/kvm-migration-stop-compressing-page-in-migration-thread.patch new file mode 100644 index 0000000..1b17689 --- /dev/null +++ b/SOURCES/kvm-migration-stop-compressing-page-in-migration-thread.patch @@ -0,0 +1,86 @@ +From 991ad76f13534cd2f22b30ba8b556f284f28c5c6 Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Fri, 22 Jun 2018 18:59:48 +0200 +Subject: [PATCH 09/57] migration: stop compressing page in migration thread + +RH-Author: Dr. David Alan Gilbert +Message-id: <20180622190005.21297-2-dgilbert@redhat.com> +Patchwork-id: 81005 +O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH 01/18] migration: stop compressing page in migration thread +Bugzilla: 1584139 +RH-Acked-by: Juan Quintela +RH-Acked-by: Peter Xu +RH-Acked-by: Laurent Vivier + +From: Xiao Guangrong + +As compression is a heavy work, do not do it in migration thread, +instead, we post it out as a normal page + +Reviewed-by: Wei Wang +Reviewed-by: Peter Xu +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Xiao Guangrong +Message-Id: <20180330075128.26919-2-xiaoguangrong@tencent.com> +Signed-off-by: Dr. David Alan Gilbert +(cherry picked from commit 263a289ae61c8344a417a95b0142650fdff3af56) +Signed-off-by: Miroslav Rezanina +--- + migration/ram.c | 32 ++++++++++++++++---------------- + 1 file changed, 16 insertions(+), 16 deletions(-) + +diff --git a/migration/ram.c b/migration/ram.c +index 00c06b5..f27038a 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -1138,7 +1138,7 @@ static int ram_save_compressed_page(RAMState *rs, PageSearchStatus *pss, + int pages = -1; + uint64_t bytes_xmit = 0; + uint8_t *p; +- int ret, blen; ++ int ret; + RAMBlock *block = pss->block; + ram_addr_t offset = pss->page << TARGET_PAGE_BITS; + +@@ -1168,23 +1168,23 @@ static int ram_save_compressed_page(RAMState *rs, PageSearchStatus *pss, + if (block != rs->last_sent_block) { + flush_compressed_data(rs); + pages = save_zero_page(rs, block, offset); +- if (pages == -1) { +- /* Make sure the first page is sent out before other pages */ +- bytes_xmit = save_page_header(rs, rs->f, block, offset | +- RAM_SAVE_FLAG_COMPRESS_PAGE); +- blen = qemu_put_compression_data(rs->f, p, TARGET_PAGE_SIZE, +- migrate_compress_level()); +- if (blen > 0) { +- ram_counters.transferred += bytes_xmit + blen; +- ram_counters.normal++; +- pages = 1; +- } else { +- qemu_file_set_error(rs->f, blen); +- error_report("compressed data failed!"); +- } +- } + if (pages > 0) { + ram_release_pages(block->idstr, offset, pages); ++ } else { ++ /* ++ * Make sure the first page is sent out before other pages. ++ * ++ * we post it as normal page as compression will take much ++ * CPU resource. ++ */ ++ ram_counters.transferred += save_page_header(rs, rs->f, block, ++ offset | RAM_SAVE_FLAG_PAGE); ++ qemu_put_buffer_async(rs->f, p, TARGET_PAGE_SIZE, ++ migrate_release_ram() & ++ migration_in_postcopy()); ++ ram_counters.transferred += TARGET_PAGE_SIZE; ++ ram_counters.normal++; ++ pages = 1; + } + } else { + pages = save_zero_page(rs, block, offset); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-migration-stop-compression-to-allocate-and-free-memo.patch b/SOURCES/kvm-migration-stop-compression-to-allocate-and-free-memo.patch new file mode 100644 index 0000000..609e340 --- /dev/null +++ b/SOURCES/kvm-migration-stop-compression-to-allocate-and-free-memo.patch @@ -0,0 +1,265 @@ +From 6a6e25b0dff81b5a6dc4272a176f5987b7474a93 Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Fri, 22 Jun 2018 18:59:49 +0200 +Subject: [PATCH 10/57] migration: stop compression to allocate and free memory + frequently + +RH-Author: Dr. David Alan Gilbert +Message-id: <20180622190005.21297-3-dgilbert@redhat.com> +Patchwork-id: 80998 +O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH 02/18] migration: stop compression to allocate and free memory frequently +Bugzilla: 1584139 +RH-Acked-by: Juan Quintela +RH-Acked-by: Peter Xu +RH-Acked-by: Laurent Vivier + +From: Xiao Guangrong + +Current code uses compress2() to compress memory which manages memory +internally, that causes huge memory is allocated and freed very +frequently + +More worse, frequently returning memory to kernel will flush TLBs +and trigger invalidation callbacks on mmu-notification which +interacts with KVM MMU, that dramatically reduce the performance +of VM + +So, we maintain the memory by ourselves and reuse it for each +compression + +Reviewed-by: Peter Xu +Reviewed-by: Jiang Biao +Signed-off-by: Xiao Guangrong +Message-Id: <20180330075128.26919-3-xiaoguangrong@tencent.com> +Signed-off-by: Dr. David Alan Gilbert +(cherry picked from commit dcaf446ebda5d87e05eb41cdbafb7ae4a7cc4a62) +Signed-off-by: Miroslav Rezanina +--- + migration/qemu-file.c | 39 ++++++++++++++++++++++++++++++++------- + migration/qemu-file.h | 6 ++++-- + migration/ram.c | 41 ++++++++++++++++++++++++++++++++--------- + 3 files changed, 68 insertions(+), 18 deletions(-) + +diff --git a/migration/qemu-file.c b/migration/qemu-file.c +index bb63c77..bafe3a0 100644 +--- a/migration/qemu-file.c ++++ b/migration/qemu-file.c +@@ -658,8 +658,32 @@ uint64_t qemu_get_be64(QEMUFile *f) + return v; + } + +-/* Compress size bytes of data start at p with specific compression +- * level and store the compressed data to the buffer of f. ++/* return the size after compression, or negative value on error */ ++static int qemu_compress_data(z_stream *stream, uint8_t *dest, size_t dest_len, ++ const uint8_t *source, size_t source_len) ++{ ++ int err; ++ ++ err = deflateReset(stream); ++ if (err != Z_OK) { ++ return -1; ++ } ++ ++ stream->avail_in = source_len; ++ stream->next_in = (uint8_t *)source; ++ stream->avail_out = dest_len; ++ stream->next_out = dest; ++ ++ err = deflate(stream, Z_FINISH); ++ if (err != Z_STREAM_END) { ++ return -1; ++ } ++ ++ return stream->next_out - dest; ++} ++ ++/* Compress size bytes of data start at p and store the compressed ++ * data to the buffer of f. + * + * When f is not writable, return -1 if f has no space to save the + * compressed data. +@@ -667,9 +691,8 @@ uint64_t qemu_get_be64(QEMUFile *f) + * do fflush first, if f still has no space to save the compressed + * data, return -1. + */ +- +-ssize_t qemu_put_compression_data(QEMUFile *f, const uint8_t *p, size_t size, +- int level) ++ssize_t qemu_put_compression_data(QEMUFile *f, z_stream *stream, ++ const uint8_t *p, size_t size) + { + ssize_t blen = IO_BUF_SIZE - f->buf_index - sizeof(int32_t); + +@@ -683,8 +706,10 @@ ssize_t qemu_put_compression_data(QEMUFile *f, const uint8_t *p, size_t size, + return -1; + } + } +- if (compress2(f->buf + f->buf_index + sizeof(int32_t), (uLongf *)&blen, +- (Bytef *)p, size, level) != Z_OK) { ++ ++ blen = qemu_compress_data(stream, f->buf + f->buf_index + sizeof(int32_t), ++ blen, p, size); ++ if (blen < 0) { + error_report("Compress Failed!"); + return 0; + } +diff --git a/migration/qemu-file.h b/migration/qemu-file.h +index f4f356a..2ccfcfb 100644 +--- a/migration/qemu-file.h ++++ b/migration/qemu-file.h +@@ -25,6 +25,8 @@ + #ifndef MIGRATION_QEMU_FILE_H + #define MIGRATION_QEMU_FILE_H + ++#include ++ + /* Read a chunk of data from a file at the given position. The pos argument + * can be ignored if the file is only be used for streaming. The number of + * bytes actually read should be returned. +@@ -132,8 +134,8 @@ bool qemu_file_is_writable(QEMUFile *f); + + size_t qemu_peek_buffer(QEMUFile *f, uint8_t **buf, size_t size, size_t offset); + size_t qemu_get_buffer_in_place(QEMUFile *f, uint8_t **buf, size_t size); +-ssize_t qemu_put_compression_data(QEMUFile *f, const uint8_t *p, size_t size, +- int level); ++ssize_t qemu_put_compression_data(QEMUFile *f, z_stream *stream, ++ const uint8_t *p, size_t size); + int qemu_put_qemu_file(QEMUFile *f_des, QEMUFile *f_src); + + /* +diff --git a/migration/ram.c b/migration/ram.c +index f27038a..7d3b1da 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -269,6 +269,7 @@ struct CompressParam { + QemuCond cond; + RAMBlock *block; + ram_addr_t offset; ++ z_stream stream; + }; + typedef struct CompressParam CompressParam; + +@@ -299,7 +300,7 @@ static QemuThread *decompress_threads; + static QemuMutex decomp_done_lock; + static QemuCond decomp_done_cond; + +-static int do_compress_ram_page(QEMUFile *f, RAMBlock *block, ++static int do_compress_ram_page(QEMUFile *f, z_stream *stream, RAMBlock *block, + ram_addr_t offset); + + static void *do_data_compress(void *opaque) +@@ -316,7 +317,7 @@ static void *do_data_compress(void *opaque) + param->block = NULL; + qemu_mutex_unlock(¶m->mutex); + +- do_compress_ram_page(param->file, block, offset); ++ do_compress_ram_page(param->file, ¶m->stream, block, offset); + + qemu_mutex_lock(&comp_done_lock); + param->done = true; +@@ -357,10 +358,19 @@ static void compress_threads_save_cleanup(void) + terminate_compression_threads(); + thread_count = migrate_compress_threads(); + for (i = 0; i < thread_count; i++) { ++ /* ++ * we use it as a indicator which shows if the thread is ++ * properly init'd or not ++ */ ++ if (!comp_param[i].file) { ++ break; ++ } + qemu_thread_join(compress_threads + i); +- qemu_fclose(comp_param[i].file); + qemu_mutex_destroy(&comp_param[i].mutex); + qemu_cond_destroy(&comp_param[i].cond); ++ deflateEnd(&comp_param[i].stream); ++ qemu_fclose(comp_param[i].file); ++ comp_param[i].file = NULL; + } + qemu_mutex_destroy(&comp_done_lock); + qemu_cond_destroy(&comp_done_cond); +@@ -370,12 +380,12 @@ static void compress_threads_save_cleanup(void) + comp_param = NULL; + } + +-static void compress_threads_save_setup(void) ++static int compress_threads_save_setup(void) + { + int i, thread_count; + + if (!migrate_use_compression()) { +- return; ++ return 0; + } + thread_count = migrate_compress_threads(); + compress_threads = g_new0(QemuThread, thread_count); +@@ -383,6 +393,11 @@ static void compress_threads_save_setup(void) + qemu_cond_init(&comp_done_cond); + qemu_mutex_init(&comp_done_lock); + for (i = 0; i < thread_count; i++) { ++ if (deflateInit(&comp_param[i].stream, ++ migrate_compress_level()) != Z_OK) { ++ goto exit; ++ } ++ + /* comp_param[i].file is just used as a dummy buffer to save data, + * set its ops to empty. + */ +@@ -395,6 +410,11 @@ static void compress_threads_save_setup(void) + do_data_compress, comp_param + i, + QEMU_THREAD_JOINABLE); + } ++ return 0; ++ ++exit: ++ compress_threads_save_cleanup(); ++ return -1; + } + + /* Multiple fd's */ +@@ -1032,7 +1052,7 @@ static int ram_save_page(RAMState *rs, PageSearchStatus *pss, bool last_stage) + return pages; + } + +-static int do_compress_ram_page(QEMUFile *f, RAMBlock *block, ++static int do_compress_ram_page(QEMUFile *f, z_stream *stream, RAMBlock *block, + ram_addr_t offset) + { + RAMState *rs = ram_state; +@@ -1041,8 +1061,7 @@ static int do_compress_ram_page(QEMUFile *f, RAMBlock *block, + + bytes_sent = save_page_header(rs, f, block, offset | + RAM_SAVE_FLAG_COMPRESS_PAGE); +- blen = qemu_put_compression_data(f, p, TARGET_PAGE_SIZE, +- migrate_compress_level()); ++ blen = qemu_put_compression_data(f, stream, p, TARGET_PAGE_SIZE); + if (blen < 0) { + bytes_sent = 0; + qemu_file_set_error(migrate_get_current()->to_dst_file, blen); +@@ -2215,9 +2234,14 @@ static int ram_save_setup(QEMUFile *f, void *opaque) + RAMState **rsp = opaque; + RAMBlock *block; + ++ if (compress_threads_save_setup()) { ++ return -1; ++ } ++ + /* migration has already setup the bitmap, reuse it. */ + if (!migration_in_colo_state()) { + if (ram_init_all(rsp) != 0) { ++ compress_threads_save_cleanup(); + return -1; + } + } +@@ -2237,7 +2261,6 @@ static int ram_save_setup(QEMUFile *f, void *opaque) + } + + rcu_read_unlock(); +- compress_threads_save_setup(); + + ram_control_before_iterate(f, RAM_CONTROL_SETUP); + ram_control_after_iterate(f, RAM_CONTROL_SETUP); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-migration-stop-decompression-to-allocate-and-free-me.patch b/SOURCES/kvm-migration-stop-decompression-to-allocate-and-free-me.patch new file mode 100644 index 0000000..832a40e --- /dev/null +++ b/SOURCES/kvm-migration-stop-decompression-to-allocate-and-free-me.patch @@ -0,0 +1,217 @@ +From b835044f9cbe56874b199c6091784cc9c51c7dd5 Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Fri, 22 Jun 2018 18:59:50 +0200 +Subject: [PATCH 11/57] migration: stop decompression to allocate and free + memory frequently + +RH-Author: Dr. David Alan Gilbert +Message-id: <20180622190005.21297-4-dgilbert@redhat.com> +Patchwork-id: 80995 +O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH 03/18] migration: stop decompression to allocate and free memory frequently +Bugzilla: 1584139 +RH-Acked-by: Juan Quintela +RH-Acked-by: Peter Xu +RH-Acked-by: Laurent Vivier + +From: Xiao Guangrong + +Current code uses uncompress() to decompress memory which manages +memory internally, that causes huge memory is allocated and freed +very frequently, more worse, frequently returning memory to kernel +will flush TLBs + +So, we maintain the memory by ourselves and reuse it for each +decompression + +Reviewed-by: Peter Xu +Reviewed-by: Jiang Biao +Signed-off-by: Xiao Guangrong +Message-Id: <20180330075128.26919-4-xiaoguangrong@tencent.com> +Signed-off-by: Dr. David Alan Gilbert +(cherry picked from commit 797ca154b4c68dbd8e93382f714388ab311f672d) +Signed-off-by: Miroslav Rezanina +--- + migration/ram.c | 112 +++++++++++++++++++++++++++++++++++++++++--------------- + 1 file changed, 82 insertions(+), 30 deletions(-) + +diff --git a/migration/ram.c b/migration/ram.c +index 7d3b1da..be89cd8 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -281,6 +281,7 @@ struct DecompressParam { + void *des; + uint8_t *compbuf; + int len; ++ z_stream stream; + }; + typedef struct DecompressParam DecompressParam; + +@@ -2525,6 +2526,31 @@ void ram_handle_compressed(void *host, uint8_t ch, uint64_t size) + } + } + ++/* return the size after decompression, or negative value on error */ ++static int ++qemu_uncompress_data(z_stream *stream, uint8_t *dest, size_t dest_len, ++ const uint8_t *source, size_t source_len) ++{ ++ int err; ++ ++ err = inflateReset(stream); ++ if (err != Z_OK) { ++ return -1; ++ } ++ ++ stream->avail_in = source_len; ++ stream->next_in = (uint8_t *)source; ++ stream->avail_out = dest_len; ++ stream->next_out = dest; ++ ++ err = inflate(stream, Z_NO_FLUSH); ++ if (err != Z_STREAM_END) { ++ return -1; ++ } ++ ++ return stream->total_out; ++} ++ + static void *do_data_decompress(void *opaque) + { + DecompressParam *param = opaque; +@@ -2541,13 +2567,13 @@ static void *do_data_decompress(void *opaque) + qemu_mutex_unlock(¶m->mutex); + + pagesize = TARGET_PAGE_SIZE; +- /* uncompress() will return failed in some case, especially +- * when the page is dirted when doing the compression, it's +- * not a problem because the dirty page will be retransferred ++ /* qemu_uncompress_data() will return failed in some case, ++ * especially when the page is dirtied when doing the compression, ++ * it's not a problem because the dirty page will be retransferred + * and uncompress() won't break the data in other pages. + */ +- uncompress((Bytef *)des, &pagesize, +- (const Bytef *)param->compbuf, len); ++ qemu_uncompress_data(¶m->stream, des, pagesize, param->compbuf, ++ len); + + qemu_mutex_lock(&decomp_done_lock); + param->done = true; +@@ -2582,30 +2608,6 @@ static void wait_for_decompress_done(void) + qemu_mutex_unlock(&decomp_done_lock); + } + +-static void compress_threads_load_setup(void) +-{ +- int i, thread_count; +- +- if (!migrate_use_compression()) { +- return; +- } +- thread_count = migrate_decompress_threads(); +- decompress_threads = g_new0(QemuThread, thread_count); +- decomp_param = g_new0(DecompressParam, thread_count); +- qemu_mutex_init(&decomp_done_lock); +- qemu_cond_init(&decomp_done_cond); +- for (i = 0; i < thread_count; i++) { +- qemu_mutex_init(&decomp_param[i].mutex); +- qemu_cond_init(&decomp_param[i].cond); +- decomp_param[i].compbuf = g_malloc0(compressBound(TARGET_PAGE_SIZE)); +- decomp_param[i].done = true; +- decomp_param[i].quit = false; +- qemu_thread_create(decompress_threads + i, "decompress", +- do_data_decompress, decomp_param + i, +- QEMU_THREAD_JOINABLE); +- } +-} +- + static void compress_threads_load_cleanup(void) + { + int i, thread_count; +@@ -2615,16 +2617,30 @@ static void compress_threads_load_cleanup(void) + } + thread_count = migrate_decompress_threads(); + for (i = 0; i < thread_count; i++) { ++ /* ++ * we use it as a indicator which shows if the thread is ++ * properly init'd or not ++ */ ++ if (!decomp_param[i].compbuf) { ++ break; ++ } ++ + qemu_mutex_lock(&decomp_param[i].mutex); + decomp_param[i].quit = true; + qemu_cond_signal(&decomp_param[i].cond); + qemu_mutex_unlock(&decomp_param[i].mutex); + } + for (i = 0; i < thread_count; i++) { ++ if (!decomp_param[i].compbuf) { ++ break; ++ } ++ + qemu_thread_join(decompress_threads + i); + qemu_mutex_destroy(&decomp_param[i].mutex); + qemu_cond_destroy(&decomp_param[i].cond); ++ inflateEnd(&decomp_param[i].stream); + g_free(decomp_param[i].compbuf); ++ decomp_param[i].compbuf = NULL; + } + g_free(decompress_threads); + g_free(decomp_param); +@@ -2632,6 +2648,39 @@ static void compress_threads_load_cleanup(void) + decomp_param = NULL; + } + ++static int compress_threads_load_setup(void) ++{ ++ int i, thread_count; ++ ++ if (!migrate_use_compression()) { ++ return 0; ++ } ++ ++ thread_count = migrate_decompress_threads(); ++ decompress_threads = g_new0(QemuThread, thread_count); ++ decomp_param = g_new0(DecompressParam, thread_count); ++ qemu_mutex_init(&decomp_done_lock); ++ qemu_cond_init(&decomp_done_cond); ++ for (i = 0; i < thread_count; i++) { ++ if (inflateInit(&decomp_param[i].stream) != Z_OK) { ++ goto exit; ++ } ++ ++ decomp_param[i].compbuf = g_malloc0(compressBound(TARGET_PAGE_SIZE)); ++ qemu_mutex_init(&decomp_param[i].mutex); ++ qemu_cond_init(&decomp_param[i].cond); ++ decomp_param[i].done = true; ++ decomp_param[i].quit = false; ++ qemu_thread_create(decompress_threads + i, "decompress", ++ do_data_decompress, decomp_param + i, ++ QEMU_THREAD_JOINABLE); ++ } ++ return 0; ++exit: ++ compress_threads_load_cleanup(); ++ return -1; ++} ++ + static void decompress_data_with_multi_threads(QEMUFile *f, + void *host, int len) + { +@@ -2671,8 +2720,11 @@ static void decompress_data_with_multi_threads(QEMUFile *f, + */ + static int ram_load_setup(QEMUFile *f, void *opaque) + { ++ if (compress_threads_load_setup()) { ++ return -1; ++ } ++ + xbzrle_load_setup(); +- compress_threads_load_setup(); + ramblock_recv_map_init(); + return 0; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-migration-update-index-field-when-delete-or-qsort-RD.patch b/SOURCES/kvm-migration-update-index-field-when-delete-or-qsort-RD.patch new file mode 100644 index 0000000..0bca5d9 --- /dev/null +++ b/SOURCES/kvm-migration-update-index-field-when-delete-or-qsort-RD.patch @@ -0,0 +1,66 @@ +From f6aecbe90d02dd675d82194240b1be740ca2c2e7 Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Fri, 22 Jun 2018 19:00:00 +0200 +Subject: [PATCH 21/57] migration: update index field when delete or qsort + RDMALocalBlock + +RH-Author: Dr. David Alan Gilbert +Message-id: <20180622190005.21297-14-dgilbert@redhat.com> +Patchwork-id: 81010 +O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH 13/18] migration: update index field when delete or qsort RDMALocalBlock +Bugzilla: 1584139 +RH-Acked-by: Juan Quintela +RH-Acked-by: Peter Xu +RH-Acked-by: Laurent Vivier + +From: Lidong Chen + +rdma_delete_block function deletes RDMALocalBlock base on index field, +but not update the index field. So when next time invoke rdma_delete_block, +it will not work correctly. + +If start and cancel migration repeatedly, some RDMALocalBlock not invoke +ibv_dereg_mr to decrease kernel mm_struct vmpin. When vmpin is large than +max locked memory limitation, ibv_reg_mr will failed, and migration can not +start successfully again. + +Signed-off-by: Lidong Chen +Reviewed-by: Dr. David Alan Gilbert +Message-Id: <1525618499-1560-1-git-send-email-lidongchen@tencent.com> +Signed-off-by: Juan Quintela + +Signed-off-by: Lidong Chen +(cherry picked from commit 71cd73061c014d04bc6b54936e675347ebc8d964) +Signed-off-by: Miroslav Rezanina +--- + migration/rdma.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/migration/rdma.c b/migration/rdma.c +index da474fc..7d233b0 100644 +--- a/migration/rdma.c ++++ b/migration/rdma.c +@@ -708,6 +708,9 @@ static int rdma_delete_block(RDMAContext *rdma, RDMALocalBlock *block) + memcpy(local->block + block->index, old + (block->index + 1), + sizeof(RDMALocalBlock) * + (local->nb_blocks - (block->index + 1))); ++ for (x = block->index; x < local->nb_blocks - 1; x++) { ++ local->block[x].index--; ++ } + } + } else { + assert(block == local->block); +@@ -3246,6 +3249,10 @@ static int qemu_rdma_registration_handle(QEMUFile *f, void *opaque) + qsort(rdma->local_ram_blocks.block, + rdma->local_ram_blocks.nb_blocks, + sizeof(RDMALocalBlock), dest_ram_sort_func); ++ for (i = 0; i < local->nb_blocks; i++) { ++ local->block[i].index = i; ++ } ++ + if (rdma->pin_all) { + ret = qemu_rdma_reg_whole_ram_blocks(rdma); + if (ret) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-mirror-Fail-gracefully-for-source-target.patch b/SOURCES/kvm-mirror-Fail-gracefully-for-source-target.patch new file mode 100644 index 0000000..9b4812b --- /dev/null +++ b/SOURCES/kvm-mirror-Fail-gracefully-for-source-target.patch @@ -0,0 +1,87 @@ +From 5d99c3a36234427da6cc0da9c3b1752c52be31e5 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Mon, 3 Sep 2018 11:15:12 +0200 +Subject: [PATCH] mirror: Fail gracefully for source == target + +RH-Author: Kevin Wolf +Message-id: <20180903111512.21419-2-kwolf@redhat.com> +Patchwork-id: 82034 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 1/1] mirror: Fail gracefully for source == target +Bugzilla: 1582042 +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: Jeffrey Cody +RH-Acked-by: John Snow + +blockdev-mirror with the same node for source and target segfaults +today: A node is in its own backing chain, so mirror_start_job() decides +that this is an active commit. When adding the intermediate nodes with +block_job_add_bdrv(), it starts the iteration through the subchain with +the backing file of source, though, so it never reaches target and +instead runs into NULL at the base. + +While we could fix that by starting with source itself, there is no +point in allowing mirroring a node into itself and I wouldn't be +surprised if this caused more problems later. + +So just check for this scenario and error out. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +(cherry picked from commit 86fae10c64d642256cf019e6829929fa0d259c7a) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/mirror.c | 5 +++++ + tests/qemu-iotests/041 | 6 ++++++ + tests/qemu-iotests/041.out | 4 ++-- + 3 files changed, 13 insertions(+), 2 deletions(-) + +diff --git a/block/mirror.c b/block/mirror.c +index 435268b..65cf43d 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -1133,6 +1133,11 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs, + buf_size = DEFAULT_MIRROR_BUF_SIZE; + } + ++ if (bs == target) { ++ error_setg(errp, "Can't mirror node into itself"); ++ return; ++ } ++ + /* In the case of active commit, add dummy driver to provide consistent + * reads on the top, while disabling it in the intermediate nodes, and make + * the backing chain writable. */ +diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041 +index c20ac7d..9336ab6 100755 +--- a/tests/qemu-iotests/041 ++++ b/tests/qemu-iotests/041 +@@ -234,6 +234,12 @@ class TestSingleBlockdev(TestSingleDrive): + result = self.vm.qmp("blockdev-add", **args) + self.assert_qmp(result, 'return', {}) + ++ def test_mirror_to_self(self): ++ result = self.vm.qmp(self.qmp_cmd, job_id='job0', ++ device=self.qmp_target, sync='full', ++ target=self.qmp_target) ++ self.assert_qmp(result, 'error/class', 'GenericError') ++ + test_large_cluster = None + test_image_not_found = None + test_small_buffer2 = None +diff --git a/tests/qemu-iotests/041.out b/tests/qemu-iotests/041.out +index c28b392..e071d0b 100644 +--- a/tests/qemu-iotests/041.out ++++ b/tests/qemu-iotests/041.out +@@ -1,5 +1,5 @@ +-..................................................................................... ++........................................................................................ + ---------------------------------------------------------------------- +-Ran 85 tests ++Ran 88 tests + + OK +-- +1.8.3.1 + diff --git a/SOURCES/kvm-mirror-Fix-potential-use-after-free-in-active-commit.patch b/SOURCES/kvm-mirror-Fix-potential-use-after-free-in-active-commit.patch new file mode 100644 index 0000000..487e02d --- /dev/null +++ b/SOURCES/kvm-mirror-Fix-potential-use-after-free-in-active-commit.patch @@ -0,0 +1,59 @@ +From 24f8fe9543b18cc484fc43ac1bf5bd7780656fbd Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:35 +0200 +Subject: [PATCH 44/49] mirror: Fix potential use-after-free in active commit + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-38-kwolf@redhat.com> +Patchwork-id: 82188 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 37/42] mirror: Fix potential use-after-free in active commit +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +When starting an active commit job, other callbacks can run before +mirror_start_job() calls bdrv_ref() where needed and cause the nodes to +go away. Add another pair of bdrv_ref/unref() around it to protect +against this case. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + block/mirror.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/block/mirror.c b/block/mirror.c +index 4b27f71..8658873 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -1335,7 +1335,14 @@ void commit_active_start(const char *job_id, BlockDriverState *bs, + + orig_base_flags = bdrv_get_flags(base); + ++ /* bdrv_reopen() drains, which might make the BDSes go away before a ++ * reference is taken in mirror_start_job(). */ ++ bdrv_ref(bs); ++ bdrv_ref(base); ++ + if (bdrv_reopen(base, bs->open_flags, errp)) { ++ bdrv_unref(bs); ++ bdrv_unref(base); + return; + } + +@@ -1344,6 +1351,10 @@ void commit_active_start(const char *job_id, BlockDriverState *bs, + on_error, on_error, true, cb, opaque, + &commit_active_job_driver, false, base, auto_complete, + filter_node_name, false, &local_err); ++ ++ bdrv_unref(bs); ++ bdrv_unref(base); ++ + if (local_err) { + error_propagate(errp, local_err); + goto error_restore_flags; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-monitor-fix-dangling-CPU-pointer.patch b/SOURCES/kvm-monitor-fix-dangling-CPU-pointer.patch deleted file mode 100644 index 0395a8b..0000000 --- a/SOURCES/kvm-monitor-fix-dangling-CPU-pointer.patch +++ /dev/null @@ -1,115 +0,0 @@ -From 062ffad79316d7c3a2ace6d96ffc1f90d61469ec Mon Sep 17 00:00:00 2001 -From: Serhii Popovych -Date: Wed, 8 Nov 2017 13:35:20 +0100 -Subject: [PATCH 2/7] monitor: fix dangling CPU pointer - -RH-Author: Serhii Popovych -Message-id: <1510148120-54741-1-git-send-email-spopovyc@redhat.com> -Patchwork-id: 77520 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH v2] monitor: fix dangling CPU pointer -Bugzilla: 1510001 -RH-Acked-by: Laurent Vivier -RH-Acked-by: David Hildenbrand -RH-Acked-by: Peter Xu - -From: Greg Kurz - -Test: replay case as described in comment 4 on bz: qemu does not crash - -If a CPU selected with the "cpu" command is hot-unplugged then "info cpus" -causes QEMU to exit: - -(qemu) device_del cpu1 -(qemu) info cpus -qemu:qemu_cpu_kick_thread: No such process - -This happens because "cpu" stores the pointer to the selected CPU into -the monitor structure. When the CPU is hot-unplugged, we end up with a -dangling pointer. The "info cpus" command then does: - -hmp_info_cpus() - monitor_get_cpu_index() - mon_get_cpu() - cpu_synchronize_state() <--- called with dangling pointer - -This could cause a QEMU crash as well. - -This patch switches the monitor to store the QOM path instead of a -pointer to the current CPU. The path is then resolved when needed. -If the resolution fails, we assume that the CPU was removed and the -path is resetted to the default (ie, path of first_cpu). - -Reported-by: Satheesh Rajendran -Suggested-by: Igor Mammedov -Signed-off-by: Greg Kurz -Message-Id: <150822818243.26242.12993827911736928961.stgit@bahia.lan> -Reviewed-by: Igor Mammedov -Signed-off-by: Dr. David Alan Gilbert -(cherry picked from commit 751f8cfe2a556b3ef49f6af2860e2d1d2a1ec66a) -Signed-off-by: Serhii Popovych -Signed-off-by: Miroslav Rezanina ---- - monitor.c | 23 ++++++++++++++++++----- - 1 file changed, 18 insertions(+), 5 deletions(-) - -diff --git a/monitor.c b/monitor.c -index bade261..c0a8dbc 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -200,7 +200,7 @@ struct Monitor { - - ReadLineState *rs; - MonitorQMP qmp; -- CPUState *mon_cpu; -+ gchar *mon_cpu_path; - BlockCompletionFunc *password_completion_cb; - void *password_opaque; - mon_cmd_t *cmd_table; -@@ -579,6 +579,7 @@ static void monitor_data_init(Monitor *mon) - - static void monitor_data_destroy(Monitor *mon) - { -+ g_free(mon->mon_cpu_path); - qemu_chr_fe_deinit(&mon->chr, false); - if (monitor_is_qmp(mon)) { - json_message_parser_destroy(&mon->qmp.parser); -@@ -1065,20 +1066,32 @@ int monitor_set_cpu(int cpu_index) - if (cpu == NULL) { - return -1; - } -- cur_mon->mon_cpu = cpu; -+ g_free(cur_mon->mon_cpu_path); -+ cur_mon->mon_cpu_path = object_get_canonical_path(OBJECT(cpu)); - return 0; - } - - CPUState *mon_get_cpu(void) - { -- if (!cur_mon->mon_cpu) { -+ CPUState *cpu; -+ -+ if (cur_mon->mon_cpu_path) { -+ cpu = (CPUState *) object_resolve_path_type(cur_mon->mon_cpu_path, -+ TYPE_CPU, NULL); -+ if (!cpu) { -+ g_free(cur_mon->mon_cpu_path); -+ cur_mon->mon_cpu_path = NULL; -+ } -+ } -+ if (!cur_mon->mon_cpu_path) { - if (!first_cpu) { - return NULL; - } - monitor_set_cpu(first_cpu->cpu_index); -+ cpu = first_cpu; - } -- cpu_synchronize_state(cur_mon->mon_cpu); -- return cur_mon->mon_cpu; -+ cpu_synchronize_state(cpu); -+ return cpu; - } - - CPUArchState *mon_get_cpu_env(void) --- -1.8.3.1 - diff --git a/SOURCES/kvm-multiboot-validate-multiboot-header-address-values.patch b/SOURCES/kvm-multiboot-validate-multiboot-header-address-values.patch deleted file mode 100644 index 6f0227a..0000000 --- a/SOURCES/kvm-multiboot-validate-multiboot-header-address-values.patch +++ /dev/null @@ -1,74 +0,0 @@ -From de21908e4f8daf06b67ba2118c5d2e41da9c51a6 Mon Sep 17 00:00:00 2001 -From: Bandan Das -Date: Thu, 26 Oct 2017 09:55:58 +0200 -Subject: [PATCH 1/7] multiboot: validate multiboot header address values - -RH-Author: Bandan Das -Message-id: -Patchwork-id: 77442 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH] multiboot: validate multiboot header address values -Bugzilla: 1501124 -RH-Acked-by: Thomas Huth -RH-Acked-by: Peter Xu -RH-Acked-by: Miroslav Rezanina - -While loading kernel via multiboot-v1 image, (flags & 0x00010000) -indicates that multiboot header contains valid addresses to load -the kernel image. These addresses are used to compute kernel -size and kernel text offset in the OS image. Validate these -address values to avoid an OOB access issue. - -This is CVE-2017-14167. - -Reported-by: Thomas Garnier -Signed-off-by: Prasad J Pandit -Message-Id: <20170907063256.7418-1-ppandit@redhat.com> -Signed-off-by: Paolo Bonzini -(cherry picked from commit ed4f86e8b6eff8e600c69adee68c7cd34dd2cccb) -Signed-off-by: Miroslav Rezanina ---- - hw/i386/multiboot.c | 19 +++++++++++++++++++ - 1 file changed, 19 insertions(+) - -diff --git a/hw/i386/multiboot.c b/hw/i386/multiboot.c -index f13e231..22688d3 100644 ---- a/hw/i386/multiboot.c -+++ b/hw/i386/multiboot.c -@@ -221,15 +221,34 @@ int load_multiboot(FWCfgState *fw_cfg, - uint32_t mh_header_addr = ldl_p(header+i+12); - uint32_t mh_load_end_addr = ldl_p(header+i+20); - uint32_t mh_bss_end_addr = ldl_p(header+i+24); -+ - mh_load_addr = ldl_p(header+i+16); -+ if (mh_header_addr < mh_load_addr) { -+ fprintf(stderr, "invalid mh_load_addr address\n"); -+ exit(1); -+ } -+ - uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr); - uint32_t mb_load_size = 0; - mh_entry_addr = ldl_p(header+i+28); - - if (mh_load_end_addr) { -+ if (mh_bss_end_addr < mh_load_addr) { -+ fprintf(stderr, "invalid mh_bss_end_addr address\n"); -+ exit(1); -+ } - mb_kernel_size = mh_bss_end_addr - mh_load_addr; -+ -+ if (mh_load_end_addr < mh_load_addr) { -+ fprintf(stderr, "invalid mh_load_end_addr address\n"); -+ exit(1); -+ } - mb_load_size = mh_load_end_addr - mh_load_addr; - } else { -+ if (kernel_file_size < mb_kernel_text_offset) { -+ fprintf(stderr, "invalid kernel_file_size\n"); -+ exit(1); -+ } - mb_kernel_size = kernel_file_size - mb_kernel_text_offset; - mb_load_size = mb_kernel_size; - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-nbd-client-Add-x-dirty-bitmap-to-query-bitmap-from-s.patch b/SOURCES/kvm-nbd-client-Add-x-dirty-bitmap-to-query-bitmap-from-s.patch new file mode 100644 index 0000000..633eae4 --- /dev/null +++ b/SOURCES/kvm-nbd-client-Add-x-dirty-bitmap-to-query-bitmap-from-s.patch @@ -0,0 +1,174 @@ +From d52addb6a2ca32ce942f348ed47da26cd9524fbd Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 18 Jul 2018 22:55:10 +0200 +Subject: [PATCH 85/89] nbd/client: Add x-dirty-bitmap to query bitmap from + server + +RH-Author: John Snow +Message-id: <20180718225511.14878-35-jsnow@redhat.com> +Patchwork-id: 81414 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 34/35] nbd/client: Add x-dirty-bitmap to query bitmap from server +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Eric Blake + +In order to test that the NBD server is properly advertising +dirty bitmaps, we need a bare minimum client that can request +and read the context. Since feature freeze for 3.0 is imminent, +this is the smallest workable patch, which replaces the qemu +block status report with the results of the NBD server's dirty +bitmap (making it very easy to use 'qemu-img map --output=json' +to learn where the dirty portions are). Note that the NBD +protocol defines a dirty section with the same bit but opposite +sense that normal "base:allocation" uses to report an allocated +section; so in qemu-img map output, "data":true corresponds to +clean, "data":false corresponds to dirty. + +A more complete solution that allows dirty bitmaps to be queried +at the same time as normal block status will be required before +this addition can lose the x- prefix. Until then, the fact that +this replaces normal status with dirty status means actions +like 'qemu-img convert' will likely misbehave due to treating +dirty regions of the file as if they are unallocated. + +The next patch adds an iotest to exercise this new code. + +Signed-off-by: Eric Blake +Message-Id: <20180702191458.28741-2-eblake@redhat.com> +(cherry picked from commit 216ee3657e14013505abe7853cecb632199fb13e) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/nbd-client.c | 3 +++ + block/nbd-client.h | 1 + + block/nbd.c | 10 ++++++++-- + include/block/nbd.h | 1 + + nbd/client.c | 4 ++-- + qapi/block-core.json | 7 ++++++- + 6 files changed, 21 insertions(+), 5 deletions(-) + +diff --git a/block/nbd-client.c b/block/nbd-client.c +index e7caf49..98637c0 100644 +--- a/block/nbd-client.c ++++ b/block/nbd-client.c +@@ -966,6 +966,7 @@ int nbd_client_init(BlockDriverState *bs, + const char *export, + QCryptoTLSCreds *tlscreds, + const char *hostname, ++ const char *x_dirty_bitmap, + Error **errp) + { + NBDClientSession *client = nbd_get_client_session(bs); +@@ -978,9 +979,11 @@ int nbd_client_init(BlockDriverState *bs, + client->info.request_sizes = true; + client->info.structured_reply = true; + client->info.base_allocation = true; ++ client->info.x_dirty_bitmap = g_strdup(x_dirty_bitmap); + ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), export, + tlscreds, hostname, + &client->ioc, &client->info, errp); ++ g_free(client->info.x_dirty_bitmap); + if (ret < 0) { + logout("Failed to negotiate with the NBD server\n"); + return ret; +diff --git a/block/nbd-client.h b/block/nbd-client.h +index 0ece76e..cfc9055 100644 +--- a/block/nbd-client.h ++++ b/block/nbd-client.h +@@ -45,6 +45,7 @@ int nbd_client_init(BlockDriverState *bs, + const char *export_name, + QCryptoTLSCreds *tlscreds, + const char *hostname, ++ const char *x_dirty_bitmap, + Error **errp); + void nbd_client_close(BlockDriverState *bs); + +diff --git a/block/nbd.c b/block/nbd.c +index 10912c3..f29c10f 100644 +--- a/block/nbd.c ++++ b/block/nbd.c +@@ -378,6 +378,12 @@ static QemuOptsList nbd_runtime_opts = { + .type = QEMU_OPT_STRING, + .help = "ID of the TLS credentials to use", + }, ++ { ++ .name = "x-dirty-bitmap", ++ .type = QEMU_OPT_STRING, ++ .help = "experimental: expose named dirty bitmap in place of " ++ "block status", ++ }, + { /* end of list */ } + }, + }; +@@ -438,8 +444,8 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags, + } + + /* NBD handshake */ +- ret = nbd_client_init(bs, sioc, s->export, +- tlscreds, hostname, errp); ++ ret = nbd_client_init(bs, sioc, s->export, tlscreds, hostname, ++ qemu_opt_get(opts, "x-dirty-bitmap"), errp); + error: + if (sioc) { + object_unref(OBJECT(sioc)); +diff --git a/include/block/nbd.h b/include/block/nbd.h +index daaeae6..4638c83 100644 +--- a/include/block/nbd.h ++++ b/include/block/nbd.h +@@ -259,6 +259,7 @@ static inline bool nbd_reply_type_is_error(int type) + struct NBDExportInfo { + /* Set by client before nbd_receive_negotiate() */ + bool request_sizes; ++ char *x_dirty_bitmap; + + /* In-out fields, set by client before nbd_receive_negotiate() and + * updated by server results during nbd_receive_negotiate() */ +diff --git a/nbd/client.c b/nbd/client.c +index b9e175d..25603f2 100644 +--- a/nbd/client.c ++++ b/nbd/client.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2016-2017 Red Hat, Inc. ++ * Copyright (C) 2016-2018 Red Hat, Inc. + * Copyright (C) 2005 Anthony Liguori + * + * Network Block Device Client Side +@@ -825,7 +825,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, + + if (info->structured_reply && base_allocation) { + result = nbd_negotiate_simple_meta_context( +- ioc, name, "base:allocation", ++ ioc, name, info->x_dirty_bitmap ?: "base:allocation", + &info->meta_base_allocation_id, errp); + if (result < 0) { + goto fail; +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 69e0cf8..8a00bec 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -3457,12 +3457,17 @@ + # + # @tls-creds: TLS credentials ID + # ++# @x-dirty-bitmap: A "qemu:dirty-bitmap:NAME" string to query in place of ++# traditional "base:allocation" block status (see ++# NBD_OPT_LIST_META_CONTEXT in the NBD protocol) (since 3.0) ++# + # Since: 2.9 + ## + { 'struct': 'BlockdevOptionsNbd', + 'data': { 'server': 'SocketAddress', + '*export': 'str', +- '*tls-creds': 'str' } } ++ '*tls-creds': 'str', ++ '*x-dirty-bitmap': 'str' } } + + ## + # @BlockdevOptionsRaw: +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-client-avoid-read_reply_co-entry-if-send-failed.patch b/SOURCES/kvm-nbd-client-avoid-read_reply_co-entry-if-send-failed.patch deleted file mode 100644 index 071816d..0000000 --- a/SOURCES/kvm-nbd-client-avoid-read_reply_co-entry-if-send-failed.patch +++ /dev/null @@ -1,160 +0,0 @@ -From d532d1959bdce14c56e2dd37a5dd013dd7c5ed39 Mon Sep 17 00:00:00 2001 -From: Eric Blake -Date: Fri, 6 Oct 2017 19:24:06 +0200 -Subject: [PATCH 14/34] nbd-client: avoid read_reply_co entry if send failed - -RH-Author: Eric Blake -Message-id: <20171006192409.29915-2-eblake@redhat.com> -Patchwork-id: 76913 -O-Subject: [RHEV-7.5 qemu-kvm-rhev PATCH 1/4] nbd-client: avoid read_reply_co entry if send failed -Bugzilla: 1482478 -RH-Acked-by: Max Reitz -RH-Acked-by: Laurent Vivier -RH-Acked-by: Stefan Hajnoczi - -From: Stefan Hajnoczi - -The following segfault is encountered if the NBD server closes the UNIX -domain socket immediately after negotiation: - - Program terminated with signal SIGSEGV, Segmentation fault. - #0 aio_co_schedule (ctx=0x0, co=0xd3c0ff2ef0) at util/async.c:441 - 441 QSLIST_INSERT_HEAD_ATOMIC(&ctx->scheduled_coroutines, - (gdb) bt - #0 0x000000d3c01a50f8 in aio_co_schedule (ctx=0x0, co=0xd3c0ff2ef0) at util/async.c:441 - #1 0x000000d3c012fa90 in nbd_coroutine_end (bs=bs@entry=0xd3c0fec650, request=) at block/nbd-client.c:207 - #2 0x000000d3c012fb58 in nbd_client_co_preadv (bs=0xd3c0fec650, offset=0, bytes=, qiov=0x7ffc10a91b20, flags=0) at block/nbd-client.c:237 - #3 0x000000d3c0128e63 in bdrv_driver_preadv (bs=bs@entry=0xd3c0fec650, offset=offset@entry=0, bytes=bytes@entry=512, qiov=qiov@entry=0x7ffc10a91b20, flags=0) at block/io.c:836 - #4 0x000000d3c012c3e0 in bdrv_aligned_preadv (child=child@entry=0xd3c0ff51d0, req=req@entry=0x7f31885d6e90, offset=offset@entry=0, bytes=bytes@entry=512, align=align@entry=1, qiov=qiov@entry=0x7ffc10a91b20, f -+lags=0) at block/io.c:1086 - #5 0x000000d3c012c6b8 in bdrv_co_preadv (child=0xd3c0ff51d0, offset=offset@entry=0, bytes=bytes@entry=512, qiov=qiov@entry=0x7ffc10a91b20, flags=flags@entry=0) at block/io.c:1182 - #6 0x000000d3c011cc17 in blk_co_preadv (blk=0xd3c0ff4f80, offset=0, bytes=512, qiov=0x7ffc10a91b20, flags=0) at block/block-backend.c:1032 - #7 0x000000d3c011ccec in blk_read_entry (opaque=0x7ffc10a91b40) at block/block-backend.c:1079 - #8 0x000000d3c01bbb96 in coroutine_trampoline (i0=, i1=) at util/coroutine-ucontext.c:79 - #9 0x00007f3196cb8600 in __start_context () at /lib64/libc.so.6 - -The problem is that nbd_client_init() uses -nbd_client_attach_aio_context() -> aio_co_schedule(new_context, -client->read_reply_co). Execution of read_reply_co is deferred to a BH -which doesn't run until later. - -In the mean time blk_co_preadv() can be called and nbd_coroutine_end() -calls aio_wake() on read_reply_co. At this point in time -read_reply_co's ctx isn't set because it has never been entered yet. - -This patch simplifies the nbd_co_send_request() -> -nbd_co_receive_reply() -> nbd_coroutine_end() lifecycle to just -nbd_co_send_request() -> nbd_co_receive_reply(). The request is "ended" -if an error occurs at any point. Callers no longer have to invoke -nbd_coroutine_end(). - -This cleanup also eliminates the segfault because we don't call -aio_co_schedule() to wake up s->read_reply_co if sending the request -failed. It is only necessary to wake up s->read_reply_co if a reply was -received. - -Note this only happens with UNIX domain sockets on Linux. It doesn't -seem possible to reproduce this with TCP sockets. - -Suggested-by: Paolo Bonzini -Signed-off-by: Stefan Hajnoczi -Message-Id: <20170829122745.14309-2-stefanha@redhat.com> -Signed-off-by: Eric Blake -(cherry picked from commit 3c2d5183f9fa4eac3d17d841e26da65a0181ae7b) -Signed-off-by: Miroslav Rezanina ---- - block/nbd-client.c | 25 +++++++++---------------- - 1 file changed, 9 insertions(+), 16 deletions(-) - -diff --git a/block/nbd-client.c b/block/nbd-client.c -index 25bcaa2..ea728ff 100644 ---- a/block/nbd-client.c -+++ b/block/nbd-client.c -@@ -144,12 +144,12 @@ static int nbd_co_send_request(BlockDriverState *bs, - request->handle = INDEX_TO_HANDLE(s, i); - - if (s->quit) { -- qemu_co_mutex_unlock(&s->send_mutex); -- return -EIO; -+ rc = -EIO; -+ goto err; - } - if (!s->ioc) { -- qemu_co_mutex_unlock(&s->send_mutex); -- return -EPIPE; -+ rc = -EPIPE; -+ goto err; - } - - if (qiov) { -@@ -166,8 +166,13 @@ static int nbd_co_send_request(BlockDriverState *bs, - } else { - rc = nbd_send_request(s->ioc, request); - } -+ -+err: - if (rc < 0) { - s->quit = true; -+ s->requests[i].coroutine = NULL; -+ s->in_flight--; -+ qemu_co_queue_next(&s->free_sema); - } - qemu_co_mutex_unlock(&s->send_mutex); - return rc; -@@ -201,13 +206,6 @@ static void nbd_co_receive_reply(NBDClientSession *s, - /* Tell the read handler to read another header. */ - s->reply.handle = 0; - } --} -- --static void nbd_coroutine_end(BlockDriverState *bs, -- NBDRequest *request) --{ -- NBDClientSession *s = nbd_get_client_session(bs); -- int i = HANDLE_TO_INDEX(s, request->handle); - - s->requests[i].coroutine = NULL; - -@@ -243,7 +241,6 @@ int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset, - } else { - nbd_co_receive_reply(client, &request, &reply, qiov); - } -- nbd_coroutine_end(bs, &request); - return -reply.error; - } - -@@ -272,7 +269,6 @@ int nbd_client_co_pwritev(BlockDriverState *bs, uint64_t offset, - } else { - nbd_co_receive_reply(client, &request, &reply, NULL); - } -- nbd_coroutine_end(bs, &request); - return -reply.error; - } - -@@ -306,7 +302,6 @@ int nbd_client_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, - } else { - nbd_co_receive_reply(client, &request, &reply, NULL); - } -- nbd_coroutine_end(bs, &request); - return -reply.error; - } - -@@ -330,7 +325,6 @@ int nbd_client_co_flush(BlockDriverState *bs) - } else { - nbd_co_receive_reply(client, &request, &reply, NULL); - } -- nbd_coroutine_end(bs, &request); - return -reply.error; - } - -@@ -355,7 +349,6 @@ int nbd_client_co_pdiscard(BlockDriverState *bs, int64_t offset, int bytes) - } else { - nbd_co_receive_reply(client, &request, &reply, NULL); - } -- nbd_coroutine_end(bs, &request); - return -reply.error; - - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-nbd-server-CVE-2017-15118-Stack-smash-on-large-expor.patch b/SOURCES/kvm-nbd-server-CVE-2017-15118-Stack-smash-on-large-expor.patch deleted file mode 100644 index 4ac95bb..0000000 --- a/SOURCES/kvm-nbd-server-CVE-2017-15118-Stack-smash-on-large-expor.patch +++ /dev/null @@ -1,62 +0,0 @@ -From dd7511a6effe839c73ed8f71ceaa3c53f16ebdbd Mon Sep 17 00:00:00 2001 -From: Eric Blake -Date: Wed, 13 Dec 2017 18:17:30 +0100 -Subject: [PATCH 5/6] nbd/server: CVE-2017-15118 Stack smash on large export - name - -RH-Author: Eric Blake -Message-id: <20171213181730.1278-3-eblake@redhat.com> -Patchwork-id: 78393 -O-Subject: [RHEV-7.5 qemu-kvm-rhev PATCH 2/2] nbd/server: CVE-2017-15118 Stack smash on large export name -Bugzilla: 1516545 1518548 -CVE: CVE-2017-15118/20171128 -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: John Snow -RH-Acked-by: Stefan Hajnoczi - -Introduced in commit f37708f6b8 (2.10). The NBD spec says a client -can request export names up to 4096 bytes in length, even though -they should not expect success on names longer than 256. However, -qemu hard-codes the limit of 256, and fails to filter out a client -that probes for a longer name; the result is a stack smash that can -potentially give an attacker arbitrary control over the qemu -process. - -The smash can be easily demonstrated with this client: -$ qemu-io f raw nbd://localhost:10809/$(printf %3000d 1 | tr ' ' a) - -If the qemu NBD server binary (whether the standalone qemu-nbd, or -the builtin server of QMP nbd-server-start) was compiled with --fstack-protector-strong, the ability to exploit the stack smash -into arbitrary execution is a lot more difficult (but still -theoretically possible to a determined attacker, perhaps in -combination with other CVEs). Still, crashing a running qemu (and -losing the VM) is bad enough, even if the attacker did not obtain -full execution control. - -CC: qemu-stable@nongnu.org -Signed-off-by: Eric Blake -(cherry picked from commit 51ae4f8455c9e32c54770c4ebc25bf86a8128183) -Signed-off-by: Miroslav Rezanina ---- - nbd/server.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/nbd/server.c b/nbd/server.c -index b93cb88..56aed3a 100644 ---- a/nbd/server.c -+++ b/nbd/server.c -@@ -393,6 +393,10 @@ static int nbd_negotiate_handle_info(NBDClient *client, uint32_t length, - msg = "name length is incorrect"; - goto invalid; - } -+ if (namelen >= sizeof(name)) { -+ msg = "name too long for qemu"; -+ goto invalid; -+ } - if (nbd_read(client->ioc, name, namelen, errp) < 0) { - return -EIO; - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-nbd-server-CVE-2017-15119-Reject-options-larger-than.patch b/SOURCES/kvm-nbd-server-CVE-2017-15119-Reject-options-larger-than.patch deleted file mode 100644 index 50a893b..0000000 --- a/SOURCES/kvm-nbd-server-CVE-2017-15119-Reject-options-larger-than.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 0ce164b7410c1c4a75eefaef48896ee245eeba5c Mon Sep 17 00:00:00 2001 -From: Eric Blake -Date: Wed, 13 Dec 2017 18:17:29 +0100 -Subject: [PATCH 4/6] nbd/server: CVE-2017-15119 Reject options larger than 32M - -RH-Author: Eric Blake -Message-id: <20171213181730.1278-2-eblake@redhat.com> -Patchwork-id: 78394 -O-Subject: [RHEV-7.5 qemu-kvm-rhev PATCH 1/2] nbd/server: CVE-2017-15119 Reject options larger than 32M -Bugzilla: 1518529 1518551 -CVE: CVE-2017-15119/20171128 -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: John Snow -RH-Acked-by: Stefan Hajnoczi - -The NBD spec gives us permission to abruptly disconnect on clients -that send outrageously large option requests, rather than having -to spend the time reading to the end of the option. No real -option request requires that much data anyways; and meanwhile, we -already have the practice of abruptly dropping the connection on -any client that sends NBD_CMD_WRITE with a payload larger than 32M. - -For comparison, nbdkit drops the connection on any request with -more than 4096 bytes; however, that limit is probably too low -(as the NBD spec states an export name can theoretically be up -to 4096 bytes, which means a valid NBD_OPT_INFO could be even -longer) - even if qemu doesn't permit exports longer than 256 -bytes. - -It could be argued that a malicious client trying to get us to -read nearly 4G of data on a bad request is a form of denial of -service. In particular, if the server requires TLS, but a client -that does not know the TLS credentials sends any option (other -than NBD_OPT_STARTTLS or NBD_OPT_EXPORT_NAME) with a stated -payload of nearly 4G, then the server was keeping the connection -alive trying to read all the payload, tying up resources that it -would rather be spending on a client that can get past the TLS -handshake. Hence, this warranted a CVE. - -Present since at least 2.5 when handling known options, and made -worse in 2.6 when fixing support for NBD_FLAG_C_FIXED_NEWSTYLE -to handle unknown options. - -CC: qemu-stable@nongnu.org -Signed-off-by: Eric Blake -(cherry picked from commit fdad35ef6c5839d50dfc14073364ac893afebc30) -Signed-off-by: Miroslav Rezanina ---- - nbd/server.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/nbd/server.c b/nbd/server.c -index 993ade3..b93cb88 100644 ---- a/nbd/server.c -+++ b/nbd/server.c -@@ -661,6 +661,12 @@ static int nbd_negotiate_options(NBDClient *client, uint16_t myflags, - } - length = be32_to_cpu(length); - -+ if (length > NBD_MAX_BUFFER_SIZE) { -+ error_setg(errp, "len (%" PRIu32" ) is larger than max len (%u)", -+ length, NBD_MAX_BUFFER_SIZE); -+ return -EINVAL; -+ } -+ - trace_nbd_negotiate_options_check_option(option, - nbd_opt_lookup(option)); - if (client->tlscreds && --- -1.8.3.1 - diff --git a/SOURCES/kvm-nbd-server-Fix-dirty-bitmap-logic-regression.patch b/SOURCES/kvm-nbd-server-Fix-dirty-bitmap-logic-regression.patch new file mode 100644 index 0000000..ef2267b --- /dev/null +++ b/SOURCES/kvm-nbd-server-Fix-dirty-bitmap-logic-regression.patch @@ -0,0 +1,54 @@ +From 05a40305eb495ff14c9bfcb1aa94c168b54d79ce Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 18 Jul 2018 22:55:08 +0200 +Subject: [PATCH 83/89] nbd/server: Fix dirty bitmap logic regression + +RH-Author: John Snow +Message-id: <20180718225511.14878-33-jsnow@redhat.com> +Patchwork-id: 81427 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 32/35] nbd/server: Fix dirty bitmap logic regression +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Eric Blake + +In my hurry to fix a build failure, I introduced a logic bug. +The assertion conditional is backwards, meaning that qemu will +now abort instead of reporting dirty bitmap status. + +The bug can only be tickled by an NBD client using an exported +dirty bitmap (which is still an experimental QMP command), so +it's not the end of the world for supported usage (and neither +'make check' nor qemu-iotests fails); but it also shows that we +really want qemu-io support for reading dirty bitmaps if only +so that I can add iotests coverage to prevent future +brown-bag-of-shame events like this one. + +Fixes: 45eb6fb6 +Signed-off-by: Eric Blake +Message-Id: <20180622153509.375130-1-eblake@redhat.com> +(cherry picked from commit 7606c99a0421be7e9d984766fe239f7791a2fd9c) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + nbd/server.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/nbd/server.c b/nbd/server.c +index 50ac8bf..e52b76b 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -1977,7 +1977,7 @@ static unsigned int bitmap_to_extents(BdrvDirtyBitmap *bitmap, uint64_t offset, + + bdrv_dirty_bitmap_unlock(bitmap); + +- assert(offset > end); ++ assert(offset < end); + *length = end - offset; + return i; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-server-Reject-0-length-block-status-request.patch b/SOURCES/kvm-nbd-server-Reject-0-length-block-status-request.patch new file mode 100644 index 0000000..af8d69d --- /dev/null +++ b/SOURCES/kvm-nbd-server-Reject-0-length-block-status-request.patch @@ -0,0 +1,51 @@ +From 32058dd38df873a275bc004c53b5ae7e74af6871 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 18 Jul 2018 22:54:59 +0200 +Subject: [PATCH 74/89] nbd/server: Reject 0-length block status request + +RH-Author: John Snow +Message-id: <20180718225511.14878-24-jsnow@redhat.com> +Patchwork-id: 81423 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 23/35] nbd/server: Reject 0-length block status request +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Eric Blake + +The NBD spec says that behavior is unspecified if the client +requests 0 length for block status; but since the structured +reply is documenting as returning a non-zero length, it's +easier to just diagnose this with an EINVAL error than to +figure out what to return. + +CC: qemu-stable@nongnu.org +Signed-off-by: Eric Blake +Message-Id: <20180621124937.166549-1-eblake@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +(cherry picked from commit d8b20291cba6aa9bb295885a34f2b5f05d59d1b2) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + nbd/server.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/nbd/server.c b/nbd/server.c +index 9e1f227..493a926 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -2007,6 +2007,10 @@ static coroutine_fn int nbd_handle_request(NBDClient *client, + "discard failed", errp); + + case NBD_CMD_BLOCK_STATUS: ++ if (!request->len) { ++ return nbd_send_generic_reply(client, request->handle, -EINVAL, ++ "need non-zero length", errp); ++ } + if (client->export_meta.valid && client->export_meta.base_allocation) { + return nbd_co_send_block_status(client, request->handle, + blk_bs(exp->blk), request->from, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-server-Silence-gcc-false-positive.patch b/SOURCES/kvm-nbd-server-Silence-gcc-false-positive.patch new file mode 100644 index 0000000..b5e8b0f --- /dev/null +++ b/SOURCES/kvm-nbd-server-Silence-gcc-false-positive.patch @@ -0,0 +1,56 @@ +From 71b082ce48653cb70bf628f753d6e7750f8d03c2 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 18 Jul 2018 22:55:07 +0200 +Subject: [PATCH 82/89] nbd/server: Silence gcc false positive + +RH-Author: John Snow +Message-id: <20180718225511.14878-32-jsnow@redhat.com> +Patchwork-id: 81425 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 31/35] nbd/server: Silence gcc false positive +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Eric Blake + +The code has a while() loop that always initialized 'end', and +the loop always executes at least once (as evidenced by the assert() +just prior to the loop). But some versions of gcc still complain +that 'end' is used uninitialized, so silence them. + +Signed-off-by: Eric Blake +Reviewed-by: Peter Maydell +Message-id: 20180622125814.345274-1-eblake@redhat.com +Signed-off-by: Peter Maydell +(cherry picked from commit 45eb6fb6cea28cdc937764aac6585751047bb294) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + nbd/server.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/nbd/server.c b/nbd/server.c +index 2746046..50ac8bf 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -1937,7 +1937,7 @@ static unsigned int bitmap_to_extents(BdrvDirtyBitmap *bitmap, uint64_t offset, + unsigned int nb_extents, + bool dont_fragment) + { +- uint64_t begin = offset, end; ++ uint64_t begin = offset, end = offset; + uint64_t overall_end = offset + *length; + unsigned int i = 0; + BdrvDirtyBitmapIter *it; +@@ -1977,6 +1977,7 @@ static unsigned int bitmap_to_extents(BdrvDirtyBitmap *bitmap, uint64_t offset, + + bdrv_dirty_bitmap_unlock(bitmap); + ++ assert(offset > end); + *length = end - offset; + return i; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-server-add-nbd_meta_empty_or_pattern-helper.patch b/SOURCES/kvm-nbd-server-add-nbd_meta_empty_or_pattern-helper.patch new file mode 100644 index 0000000..d5a7ff6 --- /dev/null +++ b/SOURCES/kvm-nbd-server-add-nbd_meta_empty_or_pattern-helper.patch @@ -0,0 +1,163 @@ +From 06d93467b8c40769e7b6c39a41594894fe440a9f Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 18 Jul 2018 22:55:02 +0200 +Subject: [PATCH 77/89] nbd/server: add nbd_meta_empty_or_pattern helper + +RH-Author: John Snow +Message-id: <20180718225511.14878-27-jsnow@redhat.com> +Patchwork-id: 81398 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 26/35] nbd/server: add nbd_meta_empty_or_pattern helper +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Vladimir Sementsov-Ogievskiy + +Add nbd_meta_pattern() and nbd_meta_empty_or_pattern() helpers for +metadata query parsing. nbd_meta_pattern() will be reused for the +"qemu" namespace in following patches. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20180609151758.17343-4-vsementsov@virtuozzo.com> +Reviewed-by: Eric Blake +[eblake: comment tweaks] +Signed-off-by: Eric Blake +(cherry picked from commit b0769d8f8df0b51881f1f15c9e29722cf6191a43) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + nbd/server.c | 89 ++++++++++++++++++++++++++++++++++++++++++------------------ + 1 file changed, 62 insertions(+), 27 deletions(-) + +diff --git a/nbd/server.c b/nbd/server.c +index 26cc41a..9171cd4 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -733,53 +733,87 @@ static int nbd_negotiate_send_meta_context(NBDClient *client, + return qio_channel_writev_all(client->ioc, iov, 2, errp) < 0 ? -EIO : 0; + } + +-/* nbd_meta_base_query +- * +- * Handle queries to 'base' namespace. For now, only the base:allocation +- * context is available. 'len' is the amount of text remaining to be read from +- * the current name, after the 'base:' portion has been stripped. ++/* Read strlen(@pattern) bytes, and set @match to true if they match @pattern. ++ * @match is never set to false. + * + * Return -errno on I/O error, 0 if option was completely handled by + * sending a reply about inconsistent lengths, or 1 on success. + * +- * Note: return code = 1 doesn't mean that we've parsed the "base:allocation" +- * namespace. It only means that there are no errors. ++ * Note: return code = 1 doesn't mean that we've read exactly @pattern. ++ * It only means that there are no errors. + */ +-static int nbd_meta_base_query(NBDClient *client, NBDExportMetaContexts *meta, +- uint32_t len, Error **errp) ++static int nbd_meta_pattern(NBDClient *client, const char *pattern, bool *match, ++ Error **errp) + { + int ret; +- char query[sizeof("allocation") - 1]; +- size_t alen = strlen("allocation"); +- +- if (len == 0) { +- if (client->opt == NBD_OPT_LIST_META_CONTEXT) { +- meta->base_allocation = true; +- } +- trace_nbd_negotiate_meta_query_parse("base:"); +- return 1; +- } ++ char *query; ++ size_t len = strlen(pattern); + +- if (len != alen) { +- trace_nbd_negotiate_meta_query_skip("not base:allocation"); +- return nbd_opt_skip(client, len, errp); +- } ++ assert(len); + ++ query = g_malloc(len); + ret = nbd_opt_read(client, query, len, errp); + if (ret <= 0) { ++ g_free(query); + return ret; + } + +- if (strncmp(query, "allocation", alen) == 0) { +- trace_nbd_negotiate_meta_query_parse("base:allocation"); +- meta->base_allocation = true; ++ if (strncmp(query, pattern, len) == 0) { ++ trace_nbd_negotiate_meta_query_parse(pattern); ++ *match = true; + } else { +- trace_nbd_negotiate_meta_query_skip("not base:allocation"); ++ trace_nbd_negotiate_meta_query_skip("pattern not matched"); + } ++ g_free(query); + + return 1; + } + ++/* ++ * Read @len bytes, and set @match to true if they match @pattern, or if @len ++ * is 0 and the client is performing _LIST_. @match is never set to false. ++ * ++ * Return -errno on I/O error, 0 if option was completely handled by ++ * sending a reply about inconsistent lengths, or 1 on success. ++ * ++ * Note: return code = 1 doesn't mean that we've read exactly @pattern. ++ * It only means that there are no errors. ++ */ ++static int nbd_meta_empty_or_pattern(NBDClient *client, const char *pattern, ++ uint32_t len, bool *match, Error **errp) ++{ ++ if (len == 0) { ++ if (client->opt == NBD_OPT_LIST_META_CONTEXT) { ++ *match = true; ++ } ++ trace_nbd_negotiate_meta_query_parse("empty"); ++ return 1; ++ } ++ ++ if (len != strlen(pattern)) { ++ trace_nbd_negotiate_meta_query_skip("different lengths"); ++ return nbd_opt_skip(client, len, errp); ++ } ++ ++ return nbd_meta_pattern(client, pattern, match, errp); ++} ++ ++/* nbd_meta_base_query ++ * ++ * Handle queries to 'base' namespace. For now, only the base:allocation ++ * context is available. 'len' is the amount of text remaining to be read from ++ * the current name, after the 'base:' portion has been stripped. ++ * ++ * Return -errno on I/O error, 0 if option was completely handled by ++ * sending a reply about inconsistent lengths, or 1 on success. ++ */ ++static int nbd_meta_base_query(NBDClient *client, NBDExportMetaContexts *meta, ++ uint32_t len, Error **errp) ++{ ++ return nbd_meta_empty_or_pattern(client, "allocation", len, ++ &meta->base_allocation, errp); ++} ++ + /* nbd_negotiate_meta_query + * + * Parse namespace name and call corresponding function to parse body of the +@@ -823,6 +857,7 @@ static int nbd_negotiate_meta_query(NBDClient *client, + return nbd_opt_skip(client, len, errp); + } + ++ trace_nbd_negotiate_meta_query_parse("base:"); + return nbd_meta_base_query(client, meta, len, errp); + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-server-fix-nbd_co_send_block_status.patch b/SOURCES/kvm-nbd-server-fix-nbd_co_send_block_status.patch new file mode 100644 index 0000000..89f87ad --- /dev/null +++ b/SOURCES/kvm-nbd-server-fix-nbd_co_send_block_status.patch @@ -0,0 +1,58 @@ +From 947350f0e713e80320519fb4131f10ed607d657f Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 18 Jul 2018 22:55:09 +0200 +Subject: [PATCH 84/89] nbd/server: fix nbd_co_send_block_status + +RH-Author: John Snow +Message-id: <20180718225511.14878-34-jsnow@redhat.com> +Patchwork-id: 81418 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 33/35] nbd/server: fix nbd_co_send_block_status +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Vladimir Sementsov-Ogievskiy + +Call nbd_co_send_extents() with correct length parameter +(extent.length may be smaller than original length). + +Also, switch length parameter type to uint32_t, to correspond with +request->len and similar nbd_co_send_bitmap(). + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20180704112302.471456-2-vsementsov@virtuozzo.com> +Signed-off-by: Eric Blake +(cherry picked from commit 0c0eaed14721f8a9db334deb35316411c512059a) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + nbd/server.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/nbd/server.c b/nbd/server.c +index e52b76b..ea5fe0e 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -1910,7 +1910,7 @@ static int nbd_co_send_extents(NBDClient *client, uint64_t handle, + /* Get block status from the exported device and send it to the client */ + static int nbd_co_send_block_status(NBDClient *client, uint64_t handle, + BlockDriverState *bs, uint64_t offset, +- uint64_t length, bool last, ++ uint32_t length, bool last, + uint32_t context_id, Error **errp) + { + int ret; +@@ -1922,7 +1922,8 @@ static int nbd_co_send_block_status(NBDClient *client, uint64_t handle, + client, handle, -ret, "can't get block status", errp); + } + +- return nbd_co_send_extents(client, handle, &extent, 1, length, last, ++ return nbd_co_send_extents(client, handle, &extent, 1, ++ be32_to_cpu(extent.length), last, + context_id, errp); + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-server-fix-trace.patch b/SOURCES/kvm-nbd-server-fix-trace.patch new file mode 100644 index 0000000..0e7322a --- /dev/null +++ b/SOURCES/kvm-nbd-server-fix-trace.patch @@ -0,0 +1,73 @@ +From 4b09857fcf27b4803336119b06033766d474ea54 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 18 Jul 2018 22:55:00 +0200 +Subject: [PATCH 75/89] nbd/server: fix trace + +RH-Author: John Snow +Message-id: <20180718225511.14878-25-jsnow@redhat.com> +Patchwork-id: 81401 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 24/35] nbd/server: fix trace +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Vladimir Sementsov-Ogievskiy + +Return code = 1 doesn't mean that we parsed base:allocation. Use +correct traces in both -parsed and -skipped cases. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20180609151758.17343-2-vsementsov@virtuozzo.com> +Reviewed-by: Eric Blake +[eblake: comment tweaks] +Signed-off-by: Eric Blake +(cherry picked from commit dbb8b396bb46388cee92e9094c563297d04c43ed) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + nbd/server.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/nbd/server.c b/nbd/server.c +index 493a926..942c016 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -736,12 +736,16 @@ static int nbd_negotiate_send_meta_context(NBDClient *client, + + /* nbd_meta_base_query + * +- * Handle query to 'base' namespace. For now, only base:allocation context is +- * available in it. 'len' is the amount of text remaining to be read from ++ * Handle queries to 'base' namespace. For now, only the base:allocation ++ * context is available. 'len' is the amount of text remaining to be read from + * the current name, after the 'base:' portion has been stripped. + * + * Return -errno on I/O error, 0 if option was completely handled by +- * sending a reply about inconsistent lengths, or 1 on success. */ ++ * sending a reply about inconsistent lengths, or 1 on success. ++ * ++ * Note: return code = 1 doesn't mean that we've parsed the "base:allocation" ++ * namespace. It only means that there are no errors. ++ */ + static int nbd_meta_base_query(NBDClient *client, NBDExportMetaContexts *meta, + uint32_t len, Error **errp) + { +@@ -768,10 +772,12 @@ static int nbd_meta_base_query(NBDClient *client, NBDExportMetaContexts *meta, + } + + if (strncmp(query, "allocation", alen) == 0) { ++ trace_nbd_negotiate_meta_query_parse("base:allocation"); + meta->base_allocation = true; ++ } else { ++ trace_nbd_negotiate_meta_query_skip("not base:allocation"); + } + +- trace_nbd_negotiate_meta_query_parse("base:allocation"); + return 1; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-server-implement-dirty-bitmap-export.patch b/SOURCES/kvm-nbd-server-implement-dirty-bitmap-export.patch new file mode 100644 index 0000000..d6662f9 --- /dev/null +++ b/SOURCES/kvm-nbd-server-implement-dirty-bitmap-export.patch @@ -0,0 +1,471 @@ +From 59e211a4d669b8950a66bba63e7ae4e58cee648f Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 18 Jul 2018 22:55:03 +0200 +Subject: [PATCH 78/89] nbd/server: implement dirty bitmap export + +RH-Author: John Snow +Message-id: <20180718225511.14878-28-jsnow@redhat.com> +Patchwork-id: 81412 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 27/35] nbd/server: implement dirty bitmap export +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Vladimir Sementsov-Ogievskiy + +Handle a new NBD meta namespace: "qemu", and corresponding queries: +"qemu:dirty-bitmap:". + +With the new metadata context negotiated, BLOCK_STATUS query will reply +with dirty-bitmap data, converted to extents. The new public function +nbd_export_bitmap selects which bitmap to export. For now, only one bitmap +may be exported. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20180609151758.17343-5-vsementsov@virtuozzo.com> +Reviewed-by: Eric Blake +[eblake: wording tweaks, minor cleanups, additional tracing] +Signed-off-by: Eric Blake +(cherry picked from commit 3d068aff16d6dbf066328977c5152847a62f2a0a) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + include/block/nbd.h | 8 +- + nbd/server.c | 278 +++++++++++++++++++++++++++++++++++++++++++++++----- + nbd/trace-events | 1 + + 3 files changed, 262 insertions(+), 25 deletions(-) + +diff --git a/include/block/nbd.h b/include/block/nbd.h +index fcdcd54..8bb9606 100644 +--- a/include/block/nbd.h ++++ b/include/block/nbd.h +@@ -229,11 +229,13 @@ enum { + #define NBD_REPLY_TYPE_ERROR NBD_REPLY_ERR(1) + #define NBD_REPLY_TYPE_ERROR_OFFSET NBD_REPLY_ERR(2) + +-/* Flags for extents (NBDExtent.flags) of NBD_REPLY_TYPE_BLOCK_STATUS, +- * for base:allocation meta context */ ++/* Extent flags for base:allocation in NBD_REPLY_TYPE_BLOCK_STATUS */ + #define NBD_STATE_HOLE (1 << 0) + #define NBD_STATE_ZERO (1 << 1) + ++/* Extent flags for qemu:dirty-bitmap in NBD_REPLY_TYPE_BLOCK_STATUS */ ++#define NBD_STATE_DIRTY (1 << 0) ++ + static inline bool nbd_reply_type_is_error(int type) + { + return type & (1 << 15); +@@ -315,6 +317,8 @@ void nbd_client_put(NBDClient *client); + void nbd_server_start(SocketAddress *addr, const char *tls_creds, + Error **errp); + ++void nbd_export_bitmap(NBDExport *exp, const char *bitmap, ++ const char *bitmap_export_name, Error **errp); + + /* nbd_read + * Reads @size bytes from @ioc. Returns 0 on success. +diff --git a/nbd/server.c b/nbd/server.c +index 9171cd4..2c2d62c 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -23,6 +23,13 @@ + #include "nbd-internal.h" + + #define NBD_META_ID_BASE_ALLOCATION 0 ++#define NBD_META_ID_DIRTY_BITMAP 1 ++ ++/* NBD_MAX_BITMAP_EXTENTS: 1 mb of extents data. An empirical ++ * constant. If an increase is needed, note that the NBD protocol ++ * recommends no larger than 32 mb, so that the client won't consider ++ * the reply as a denial of service attack. */ ++#define NBD_MAX_BITMAP_EXTENTS (0x100000 / 8) + + static int system_errno_to_nbd_errno(int err) + { +@@ -80,6 +87,9 @@ struct NBDExport { + + BlockBackend *eject_notifier_blk; + Notifier eject_notifier; ++ ++ BdrvDirtyBitmap *export_bitmap; ++ char *export_bitmap_context; + }; + + static QTAILQ_HEAD(, NBDExport) exports = QTAILQ_HEAD_INITIALIZER(exports); +@@ -92,6 +102,7 @@ typedef struct NBDExportMetaContexts { + bool valid; /* means that negotiation of the option finished without + errors */ + bool base_allocation; /* export base:allocation context (block status) */ ++ bool bitmap; /* export qemu:dirty-bitmap: */ + } NBDExportMetaContexts; + + struct NBDClient { +@@ -814,6 +825,56 @@ static int nbd_meta_base_query(NBDClient *client, NBDExportMetaContexts *meta, + &meta->base_allocation, errp); + } + ++/* nbd_meta_bitmap_query ++ * ++ * Handle query to 'qemu:' namespace. ++ * @len is the amount of text remaining to be read from the current name, after ++ * the 'qemu:' portion has been stripped. ++ * ++ * Return -errno on I/O error, 0 if option was completely handled by ++ * sending a reply about inconsistent lengths, or 1 on success. */ ++static int nbd_meta_qemu_query(NBDClient *client, NBDExportMetaContexts *meta, ++ uint32_t len, Error **errp) ++{ ++ bool dirty_bitmap = false; ++ size_t dirty_bitmap_len = strlen("dirty-bitmap:"); ++ int ret; ++ ++ if (!meta->exp->export_bitmap) { ++ trace_nbd_negotiate_meta_query_skip("no dirty-bitmap exported"); ++ return nbd_opt_skip(client, len, errp); ++ } ++ ++ if (len == 0) { ++ if (client->opt == NBD_OPT_LIST_META_CONTEXT) { ++ meta->bitmap = true; ++ } ++ trace_nbd_negotiate_meta_query_parse("empty"); ++ return 1; ++ } ++ ++ if (len < dirty_bitmap_len) { ++ trace_nbd_negotiate_meta_query_skip("not dirty-bitmap:"); ++ return nbd_opt_skip(client, len, errp); ++ } ++ ++ len -= dirty_bitmap_len; ++ ret = nbd_meta_pattern(client, "dirty-bitmap:", &dirty_bitmap, errp); ++ if (ret <= 0) { ++ return ret; ++ } ++ if (!dirty_bitmap) { ++ trace_nbd_negotiate_meta_query_skip("not dirty-bitmap:"); ++ return nbd_opt_skip(client, len, errp); ++ } ++ ++ trace_nbd_negotiate_meta_query_parse("dirty-bitmap:"); ++ ++ return nbd_meta_empty_or_pattern( ++ client, meta->exp->export_bitmap_context + ++ strlen("qemu:dirty_bitmap:"), len, &meta->bitmap, errp); ++} ++ + /* nbd_negotiate_meta_query + * + * Parse namespace name and call corresponding function to parse body of the +@@ -829,9 +890,14 @@ static int nbd_meta_base_query(NBDClient *client, NBDExportMetaContexts *meta, + static int nbd_negotiate_meta_query(NBDClient *client, + NBDExportMetaContexts *meta, Error **errp) + { ++ /* ++ * Both 'qemu' and 'base' namespaces have length = 5 including a ++ * colon. If another length namespace is later introduced, this ++ * should certainly be refactored. ++ */ + int ret; +- char query[sizeof("base:") - 1]; +- size_t baselen = strlen("base:"); ++ size_t ns_len = 5; ++ char ns[5]; + uint32_t len; + + ret = nbd_opt_read(client, &len, sizeof(len), errp); +@@ -840,25 +906,27 @@ static int nbd_negotiate_meta_query(NBDClient *client, + } + cpu_to_be32s(&len); + +- /* The only supported namespace for now is 'base'. So query should start +- * with 'base:'. Otherwise, we can ignore it and skip the remainder. */ +- if (len < baselen) { ++ if (len < ns_len) { + trace_nbd_negotiate_meta_query_skip("length too short"); + return nbd_opt_skip(client, len, errp); + } + +- len -= baselen; +- ret = nbd_opt_read(client, query, baselen, errp); ++ len -= ns_len; ++ ret = nbd_opt_read(client, ns, ns_len, errp); + if (ret <= 0) { + return ret; + } +- if (strncmp(query, "base:", baselen) != 0) { +- trace_nbd_negotiate_meta_query_skip("not for base: namespace"); +- return nbd_opt_skip(client, len, errp); ++ ++ if (!strncmp(ns, "base:", ns_len)) { ++ trace_nbd_negotiate_meta_query_parse("base:"); ++ return nbd_meta_base_query(client, meta, len, errp); ++ } else if (!strncmp(ns, "qemu:", ns_len)) { ++ trace_nbd_negotiate_meta_query_parse("qemu:"); ++ return nbd_meta_qemu_query(client, meta, len, errp); + } + +- trace_nbd_negotiate_meta_query_parse("base:"); +- return nbd_meta_base_query(client, meta, len, errp); ++ trace_nbd_negotiate_meta_query_skip("unknown namespace"); ++ return nbd_opt_skip(client, len, errp); + } + + /* nbd_negotiate_meta_queries +@@ -928,6 +996,16 @@ static int nbd_negotiate_meta_queries(NBDClient *client, + } + } + ++ if (meta->bitmap) { ++ ret = nbd_negotiate_send_meta_context(client, ++ meta->exp->export_bitmap_context, ++ NBD_META_ID_DIRTY_BITMAP, ++ errp); ++ if (ret < 0) { ++ return ret; ++ } ++ } ++ + ret = nbd_negotiate_send_rep(client, NBD_REP_ACK, errp); + if (ret == 0) { + meta->valid = true; +@@ -1556,6 +1634,11 @@ void nbd_export_put(NBDExport *exp) + exp->blk = NULL; + } + ++ if (exp->export_bitmap) { ++ bdrv_dirty_bitmap_set_qmp_locked(exp->export_bitmap, false); ++ g_free(exp->export_bitmap_context); ++ } ++ + g_free(exp); + } + } +@@ -1797,9 +1880,15 @@ static int blockstatus_to_extent_be(BlockDriverState *bs, uint64_t offset, + } + + /* nbd_co_send_extents +- * @extents should be in big-endian */ ++ * ++ * @length is only for tracing purposes (and may be smaller or larger ++ * than the client's original request). @last controls whether ++ * NBD_REPLY_FLAG_DONE is sent. @extents should already be in ++ * big-endian format. ++ */ + static int nbd_co_send_extents(NBDClient *client, uint64_t handle, +- NBDExtent *extents, unsigned nb_extents, ++ NBDExtent *extents, unsigned int nb_extents, ++ uint64_t length, bool last, + uint32_t context_id, Error **errp) + { + NBDStructuredMeta chunk; +@@ -1809,7 +1898,9 @@ static int nbd_co_send_extents(NBDClient *client, uint64_t handle, + {.iov_base = extents, .iov_len = nb_extents * sizeof(extents[0])} + }; + +- set_be_chunk(&chunk.h, NBD_REPLY_FLAG_DONE, NBD_REPLY_TYPE_BLOCK_STATUS, ++ trace_nbd_co_send_extents(handle, nb_extents, context_id, length, last); ++ set_be_chunk(&chunk.h, last ? NBD_REPLY_FLAG_DONE : 0, ++ NBD_REPLY_TYPE_BLOCK_STATUS, + handle, sizeof(chunk) - sizeof(chunk.h) + iov[1].iov_len); + stl_be_p(&chunk.context_id, context_id); + +@@ -1819,8 +1910,8 @@ static int nbd_co_send_extents(NBDClient *client, uint64_t handle, + /* Get block status from the exported device and send it to the client */ + static int nbd_co_send_block_status(NBDClient *client, uint64_t handle, + BlockDriverState *bs, uint64_t offset, +- uint64_t length, uint32_t context_id, +- Error **errp) ++ uint64_t length, bool last, ++ uint32_t context_id, Error **errp) + { + int ret; + NBDExtent extent; +@@ -1831,7 +1922,84 @@ static int nbd_co_send_block_status(NBDClient *client, uint64_t handle, + client, handle, -ret, "can't get block status", errp); + } + +- return nbd_co_send_extents(client, handle, &extent, 1, context_id, errp); ++ return nbd_co_send_extents(client, handle, &extent, 1, length, last, ++ context_id, errp); ++} ++ ++/* ++ * Populate @extents from a dirty bitmap. Unless @dont_fragment, the ++ * final extent may exceed the original @length. Store in @length the ++ * byte length encoded (which may be smaller or larger than the ++ * original), and return the number of extents used. ++ */ ++static unsigned int bitmap_to_extents(BdrvDirtyBitmap *bitmap, uint64_t offset, ++ uint64_t *length, NBDExtent *extents, ++ unsigned int nb_extents, ++ bool dont_fragment) ++{ ++ uint64_t begin = offset, end; ++ uint64_t overall_end = offset + *length; ++ unsigned int i = 0; ++ BdrvDirtyBitmapIter *it; ++ bool dirty; ++ ++ bdrv_dirty_bitmap_lock(bitmap); ++ ++ it = bdrv_dirty_iter_new(bitmap); ++ dirty = bdrv_get_dirty_locked(NULL, bitmap, offset); ++ ++ assert(begin < overall_end && nb_extents); ++ while (begin < overall_end && i < nb_extents) { ++ if (dirty) { ++ end = bdrv_dirty_bitmap_next_zero(bitmap, begin); ++ } else { ++ bdrv_set_dirty_iter(it, begin); ++ end = bdrv_dirty_iter_next(it); ++ } ++ if (end == -1 || end - begin > UINT32_MAX) { ++ /* Cap to an aligned value < 4G beyond begin. */ ++ end = MIN(bdrv_dirty_bitmap_size(bitmap), ++ begin + UINT32_MAX + 1 - ++ bdrv_dirty_bitmap_granularity(bitmap)); ++ } ++ if (dont_fragment && end > overall_end) { ++ end = overall_end; ++ } ++ ++ extents[i].length = cpu_to_be32(end - begin); ++ extents[i].flags = cpu_to_be32(dirty ? NBD_STATE_DIRTY : 0); ++ i++; ++ begin = end; ++ dirty = !dirty; ++ } ++ ++ bdrv_dirty_iter_free(it); ++ ++ bdrv_dirty_bitmap_unlock(bitmap); ++ ++ *length = end - offset; ++ return i; ++} ++ ++static int nbd_co_send_bitmap(NBDClient *client, uint64_t handle, ++ BdrvDirtyBitmap *bitmap, uint64_t offset, ++ uint32_t length, bool dont_fragment, bool last, ++ uint32_t context_id, Error **errp) ++{ ++ int ret; ++ unsigned int nb_extents = dont_fragment ? 1 : NBD_MAX_BITMAP_EXTENTS; ++ NBDExtent *extents = g_new(NBDExtent, nb_extents); ++ uint64_t final_length = length; ++ ++ nb_extents = bitmap_to_extents(bitmap, offset, &final_length, extents, ++ nb_extents, dont_fragment); ++ ++ ret = nbd_co_send_extents(client, handle, extents, nb_extents, ++ final_length, last, context_id, errp); ++ ++ g_free(extents); ++ ++ return ret; + } + + /* nbd_co_receive_request +@@ -2051,11 +2219,34 @@ static coroutine_fn int nbd_handle_request(NBDClient *client, + return nbd_send_generic_reply(client, request->handle, -EINVAL, + "need non-zero length", errp); + } +- if (client->export_meta.valid && client->export_meta.base_allocation) { +- return nbd_co_send_block_status(client, request->handle, +- blk_bs(exp->blk), request->from, +- request->len, +- NBD_META_ID_BASE_ALLOCATION, errp); ++ if (client->export_meta.valid && ++ (client->export_meta.base_allocation || ++ client->export_meta.bitmap)) ++ { ++ if (client->export_meta.base_allocation) { ++ ret = nbd_co_send_block_status(client, request->handle, ++ blk_bs(exp->blk), request->from, ++ request->len, ++ !client->export_meta.bitmap, ++ NBD_META_ID_BASE_ALLOCATION, ++ errp); ++ if (ret < 0) { ++ return ret; ++ } ++ } ++ ++ if (client->export_meta.bitmap) { ++ ret = nbd_co_send_bitmap(client, request->handle, ++ client->exp->export_bitmap, ++ request->from, request->len, ++ request->flags & NBD_CMD_FLAG_REQ_ONE, ++ true, NBD_META_ID_DIRTY_BITMAP, errp); ++ if (ret < 0) { ++ return ret; ++ } ++ } ++ ++ return ret; + } else { + return nbd_send_generic_reply(client, request->handle, -EINVAL, + "CMD_BLOCK_STATUS not negotiated", +@@ -2207,3 +2398,44 @@ void nbd_client_new(NBDExport *exp, + co = qemu_coroutine_create(nbd_co_client_start, client); + qemu_coroutine_enter(co); + } ++ ++void nbd_export_bitmap(NBDExport *exp, const char *bitmap, ++ const char *bitmap_export_name, Error **errp) ++{ ++ BdrvDirtyBitmap *bm = NULL; ++ BlockDriverState *bs = blk_bs(exp->blk); ++ ++ if (exp->export_bitmap) { ++ error_setg(errp, "Export bitmap is already set"); ++ return; ++ } ++ ++ while (true) { ++ bm = bdrv_find_dirty_bitmap(bs, bitmap); ++ if (bm != NULL || bs->backing == NULL) { ++ break; ++ } ++ ++ bs = bs->backing->bs; ++ } ++ ++ if (bm == NULL) { ++ error_setg(errp, "Bitmap '%s' is not found", bitmap); ++ return; ++ } ++ ++ if (bdrv_dirty_bitmap_enabled(bm)) { ++ error_setg(errp, "Bitmap '%s' is enabled", bitmap); ++ return; ++ } ++ ++ if (bdrv_dirty_bitmap_qmp_locked(bm)) { ++ error_setg(errp, "Bitmap '%s' is locked", bitmap); ++ return; ++ } ++ ++ bdrv_dirty_bitmap_set_qmp_locked(bm, true); ++ exp->export_bitmap = bm; ++ exp->export_bitmap_context = ++ g_strdup_printf("qemu:dirty-bitmap:%s", bitmap_export_name); ++} +diff --git a/nbd/trace-events b/nbd/trace-events +index dee081e..5e1d4af 100644 +--- a/nbd/trace-events ++++ b/nbd/trace-events +@@ -64,6 +64,7 @@ nbd_co_send_simple_reply(uint64_t handle, uint32_t error, const char *errname, i + nbd_co_send_structured_done(uint64_t handle) "Send structured reply done: handle = %" PRIu64 + nbd_co_send_structured_read(uint64_t handle, uint64_t offset, void *data, size_t size) "Send structured read data reply: handle = %" PRIu64 ", offset = %" PRIu64 ", data = %p, len = %zu" + nbd_co_send_structured_read_hole(uint64_t handle, uint64_t offset, size_t size) "Send structured read hole reply: handle = %" PRIu64 ", offset = %" PRIu64 ", len = %zu" ++nbd_co_send_extents(uint64_t handle, unsigned int extents, uint32_t id, uint64_t length, int last) "Send block status reply: handle = %" PRIu64 ", extents = %u, context = %d (extents cover %" PRIu64 " bytes, last chunk = %d)" + nbd_co_send_structured_error(uint64_t handle, int err, const char *errname, const char *msg) "Send structured error reply: handle = %" PRIu64 ", error = %d (%s), msg = '%s'" + nbd_co_receive_request_decode_type(uint64_t handle, uint16_t type, const char *name) "Decoding type: handle = %" PRIu64 ", type = %" PRIu16 " (%s)" + nbd_co_receive_request_payload_received(uint64_t handle, uint32_t len) "Payload received: handle = %" PRIu64 ", len = %" PRIu32 +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-server-introduce-NBD_CMD_CACHE.patch b/SOURCES/kvm-nbd-server-introduce-NBD_CMD_CACHE.patch new file mode 100644 index 0000000..5026125 --- /dev/null +++ b/SOURCES/kvm-nbd-server-introduce-NBD_CMD_CACHE.patch @@ -0,0 +1,121 @@ +From f834b08ab5b70b9a39bb0b6c351a65ad46b5879f Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 18 Jul 2018 22:55:06 +0200 +Subject: [PATCH 81/89] nbd/server: introduce NBD_CMD_CACHE + +RH-Author: John Snow +Message-id: <20180718225511.14878-31-jsnow@redhat.com> +Patchwork-id: 81419 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 30/35] nbd/server: introduce NBD_CMD_CACHE +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Vladimir Sementsov-Ogievskiy + +Handle nbd CACHE command. Just do read, without sending read data back. +Cache mechanism should be done by exported node driver chain. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20180413143156.11409-1-vsementsov@virtuozzo.com> +Reviewed-by: Eric Blake +[eblake: fix two missing case labels in switch statements] +Signed-off-by: Eric Blake +(cherry picked from commit bc37b06a5cde24fb24c2a2cc44dd86756034ba9d) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + include/block/nbd.h | 3 ++- + nbd/common.c | 2 ++ + nbd/server.c | 11 +++++++---- + 3 files changed, 11 insertions(+), 5 deletions(-) + +diff --git a/include/block/nbd.h b/include/block/nbd.h +index 8bb9606..daaeae6 100644 +--- a/include/block/nbd.h ++++ b/include/block/nbd.h +@@ -135,6 +135,7 @@ typedef struct NBDExtent { + #define NBD_FLAG_SEND_TRIM (1 << 5) /* Send TRIM (discard) */ + #define NBD_FLAG_SEND_WRITE_ZEROES (1 << 6) /* Send WRITE_ZEROES */ + #define NBD_FLAG_SEND_DF (1 << 7) /* Send DF (Do not Fragment) */ ++#define NBD_FLAG_SEND_CACHE (1 << 8) /* Send CACHE (prefetch) */ + + /* New-style handshake (global) flags, sent from server to client, and + control what will happen during handshake phase. */ +@@ -195,7 +196,7 @@ enum { + NBD_CMD_DISC = 2, + NBD_CMD_FLUSH = 3, + NBD_CMD_TRIM = 4, +- /* 5 reserved for failed experiment NBD_CMD_CACHE */ ++ NBD_CMD_CACHE = 5, + NBD_CMD_WRITE_ZEROES = 6, + NBD_CMD_BLOCK_STATUS = 7, + }; +diff --git a/nbd/common.c b/nbd/common.c +index 8c95c1d..41f5ed8 100644 +--- a/nbd/common.c ++++ b/nbd/common.c +@@ -148,6 +148,8 @@ const char *nbd_cmd_lookup(uint16_t cmd) + return "flush"; + case NBD_CMD_TRIM: + return "trim"; ++ case NBD_CMD_CACHE: ++ return "cache"; + case NBD_CMD_WRITE_ZEROES: + return "write zeroes"; + case NBD_CMD_BLOCK_STATUS: +diff --git a/nbd/server.c b/nbd/server.c +index 2c2d62c..2746046 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -1252,7 +1252,7 @@ static coroutine_fn int nbd_negotiate(NBDClient *client, Error **errp) + int ret; + const uint16_t myflags = (NBD_FLAG_HAS_FLAGS | NBD_FLAG_SEND_TRIM | + NBD_FLAG_SEND_FLUSH | NBD_FLAG_SEND_FUA | +- NBD_FLAG_SEND_WRITE_ZEROES); ++ NBD_FLAG_SEND_WRITE_ZEROES | NBD_FLAG_SEND_CACHE); + bool oldStyle; + + /* Old style negotiation header, no room for options +@@ -2034,7 +2034,9 @@ static int nbd_co_receive_request(NBDRequestData *req, NBDRequest *request, + return -EIO; + } + +- if (request->type == NBD_CMD_READ || request->type == NBD_CMD_WRITE) { ++ if (request->type == NBD_CMD_READ || request->type == NBD_CMD_WRITE || ++ request->type == NBD_CMD_CACHE) ++ { + if (request->len > NBD_MAX_BUFFER_SIZE) { + error_setg(errp, "len (%" PRIu32" ) is larger than max len (%u)", + request->len, NBD_MAX_BUFFER_SIZE); +@@ -2119,7 +2121,7 @@ static coroutine_fn int nbd_do_cmd_read(NBDClient *client, NBDRequest *request, + int ret; + NBDExport *exp = client->exp; + +- assert(request->type == NBD_CMD_READ); ++ assert(request->type == NBD_CMD_READ || request->type == NBD_CMD_CACHE); + + /* XXX: NBD Protocol only documents use of FUA with WRITE */ + if (request->flags & NBD_CMD_FLAG_FUA) { +@@ -2138,7 +2140,7 @@ static coroutine_fn int nbd_do_cmd_read(NBDClient *client, NBDRequest *request, + + ret = blk_pread(exp->blk, request->from + exp->dev_offset, data, + request->len); +- if (ret < 0) { ++ if (ret < 0 || request->type == NBD_CMD_CACHE) { + return nbd_send_generic_reply(client, request->handle, ret, + "reading from file failed", errp); + } +@@ -2171,6 +2173,7 @@ static coroutine_fn int nbd_handle_request(NBDClient *client, + + switch (request->type) { + case NBD_CMD_READ: ++ case NBD_CMD_CACHE: + return nbd_do_cmd_read(client, request, data, errp); + + case NBD_CMD_WRITE: +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-server-refactor-NBDExportMetaContexts.patch b/SOURCES/kvm-nbd-server-refactor-NBDExportMetaContexts.patch new file mode 100644 index 0000000..6280dd2 --- /dev/null +++ b/SOURCES/kvm-nbd-server-refactor-NBDExportMetaContexts.patch @@ -0,0 +1,118 @@ +From 6ba3ec3e20e1980ad6e061a82a101ce0394d6b35 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 18 Jul 2018 22:55:01 +0200 +Subject: [PATCH 76/89] nbd/server: refactor NBDExportMetaContexts + +RH-Author: John Snow +Message-id: <20180718225511.14878-26-jsnow@redhat.com> +Patchwork-id: 81413 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 25/35] nbd/server: refactor NBDExportMetaContexts +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Vladimir Sementsov-Ogievskiy + +Use NBDExport pointer instead of just export name: there is no need to +store a duplicated name in the struct; moreover, NBDExport will be used +further. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20180609151758.17343-3-vsementsov@virtuozzo.com> +Reviewed-by: Eric Blake +[eblake: commit message grammar tweak] +Signed-off-by: Eric Blake +(cherry picked from commit af736e546717d832168dd332a328bfcf74a0ab3d) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + nbd/server.c | 23 +++++++++++------------ + 1 file changed, 11 insertions(+), 12 deletions(-) + +diff --git a/nbd/server.c b/nbd/server.c +index 942c016..26cc41a 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -88,7 +88,7 @@ static QTAILQ_HEAD(, NBDExport) exports = QTAILQ_HEAD_INITIALIZER(exports); + * as selected by NBD_OPT_SET_META_CONTEXT. Also used for + * NBD_OPT_LIST_META_CONTEXT. */ + typedef struct NBDExportMetaContexts { +- char export_name[NBD_MAX_NAME_SIZE + 1]; ++ NBDExport *exp; + bool valid; /* means that negotiation of the option finished without + errors */ + bool base_allocation; /* export base:allocation context (block status) */ +@@ -399,10 +399,9 @@ static int nbd_negotiate_handle_list(NBDClient *client, Error **errp) + return nbd_negotiate_send_rep(client, NBD_REP_ACK, errp); + } + +-static void nbd_check_meta_export_name(NBDClient *client) ++static void nbd_check_meta_export(NBDClient *client) + { +- client->export_meta.valid &= !strcmp(client->exp->name, +- client->export_meta.export_name); ++ client->export_meta.valid &= client->exp == client->export_meta.exp; + } + + /* Send a reply to NBD_OPT_EXPORT_NAME. +@@ -456,7 +455,7 @@ static int nbd_negotiate_handle_export_name(NBDClient *client, + + QTAILQ_INSERT_TAIL(&client->exp->clients, client, next); + nbd_export_get(client->exp); +- nbd_check_meta_export_name(client); ++ nbd_check_meta_export(client); + + return 0; + } +@@ -650,7 +649,7 @@ static int nbd_negotiate_handle_info(NBDClient *client, uint16_t myflags, + client->exp = exp; + QTAILQ_INSERT_TAIL(&client->exp->clients, client, next); + nbd_export_get(client->exp); +- nbd_check_meta_export_name(client); ++ nbd_check_meta_export(client); + rc = 1; + } + return rc; +@@ -835,7 +834,7 @@ static int nbd_negotiate_meta_queries(NBDClient *client, + NBDExportMetaContexts *meta, Error **errp) + { + int ret; +- NBDExport *exp; ++ char export_name[NBD_MAX_NAME_SIZE + 1]; + NBDExportMetaContexts local_meta; + uint32_t nb_queries; + int i; +@@ -854,15 +853,15 @@ static int nbd_negotiate_meta_queries(NBDClient *client, + + memset(meta, 0, sizeof(*meta)); + +- ret = nbd_opt_read_name(client, meta->export_name, NULL, errp); ++ ret = nbd_opt_read_name(client, export_name, NULL, errp); + if (ret <= 0) { + return ret; + } + +- exp = nbd_export_find(meta->export_name); +- if (exp == NULL) { ++ meta->exp = nbd_export_find(export_name); ++ if (meta->exp == NULL) { + return nbd_opt_drop(client, NBD_REP_ERR_UNKNOWN, errp, +- "export '%s' not present", meta->export_name); ++ "export '%s' not present", export_name); + } + + ret = nbd_opt_read(client, &nb_queries, sizeof(nb_queries), errp); +@@ -871,7 +870,7 @@ static int nbd_negotiate_meta_queries(NBDClient *client, + } + cpu_to_be32s(&nb_queries); + trace_nbd_negotiate_meta_context(nbd_opt_lookup(client->opt), +- meta->export_name, nb_queries); ++ export_name, nb_queries); + + if (client->opt == NBD_OPT_LIST_META_CONTEXT && !nb_queries) { + /* enable all known contexts */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nfs-Fix-error-path-in-nfs_options_qdict_to_qapi.patch b/SOURCES/kvm-nfs-Fix-error-path-in-nfs_options_qdict_to_qapi.patch new file mode 100644 index 0000000..8e33fb8 --- /dev/null +++ b/SOURCES/kvm-nfs-Fix-error-path-in-nfs_options_qdict_to_qapi.patch @@ -0,0 +1,43 @@ +From 05767713c9bd39d7d035b8edce4f7149d23500b6 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:47:47 +0200 +Subject: [PATCH 18/89] nfs: Fix error path in nfs_options_qdict_to_qapi() + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-5-kwolf@redhat.com> +Patchwork-id: 81057 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 04/73] nfs: Fix error path in nfs_options_qdict_to_qapi() +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +Don't throw away local_err, but propagate it to errp. + +Signed-off-by: Kevin Wolf +Message-id: 20180516161034.27440-1-kwolf@redhat.com +Reviewed-by: Eric Blake +Reviewed-by: Jeff Cody +Signed-off-by: Jeff Cody +(cherry picked from commit 54b7af4369a37afbd82573d0dcfb27febdb6dd24) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/nfs.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/block/nfs.c b/block/nfs.c +index 1e12958..3059ef2 100644 +--- a/block/nfs.c ++++ b/block/nfs.c +@@ -568,6 +568,7 @@ static BlockdevOptionsNfs *nfs_options_qdict_to_qapi(QDict *options, + visit_free(v); + + if (local_err) { ++ error_propagate(errp, local_err); + return NULL; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nfs-Remove-processed-options-from-QDict.patch b/SOURCES/kvm-nfs-Remove-processed-options-from-QDict.patch new file mode 100644 index 0000000..0cb335f --- /dev/null +++ b/SOURCES/kvm-nfs-Remove-processed-options-from-QDict.patch @@ -0,0 +1,64 @@ +From 27956f992c0e7622feed76bce5c5ff5cc9139e4d Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:47:48 +0200 +Subject: [PATCH 19/89] nfs: Remove processed options from QDict + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-6-kwolf@redhat.com> +Patchwork-id: 81058 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 05/73] nfs: Remove processed options from QDict +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +Commit c22a03454 QAPIfied option parsing in the NFS block driver, but +forgot to remove all the options we processed. Therefore, we get an +error in bdrv_open_inherit(), which thinks the remaining options are +invalid. Trying to open an NFS image will result in an error like this: + + Block protocol 'nfs' doesn't support the option 'server.host' + +Remove all options from the QDict to make the NFS driver work again. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Kevin Wolf +Message-id: 20180516160816.26259-1-kwolf@redhat.com +Reviewed-by: Eric Blake +Reviewed-by: Jeff Cody +Signed-off-by: Jeff Cody +(cherry picked from commit c82be42cc803b36fd7aed5dceec68312c7056fd5) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/nfs.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/block/nfs.c b/block/nfs.c +index 3059ef2..743ca04 100644 +--- a/block/nfs.c ++++ b/block/nfs.c +@@ -557,6 +557,7 @@ static BlockdevOptionsNfs *nfs_options_qdict_to_qapi(QDict *options, + { + BlockdevOptionsNfs *opts = NULL; + Visitor *v; ++ const QDictEntry *e; + Error *local_err = NULL; + + v = qobject_input_visitor_new_flat_confused(options, errp); +@@ -572,6 +573,12 @@ static BlockdevOptionsNfs *nfs_options_qdict_to_qapi(QDict *options, + return NULL; + } + ++ /* Remove the processed options from the QDict (the visitor processes ++ * _all_ options in the QDict) */ ++ while ((e = qdict_first(options))) { ++ qdict_del(options, e->key); ++ } ++ + return opts; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-numa-clarify-error-message-when-node-index-is-out-of.patch b/SOURCES/kvm-numa-clarify-error-message-when-node-index-is-out-of.patch new file mode 100644 index 0000000..855fdc1 --- /dev/null +++ b/SOURCES/kvm-numa-clarify-error-message-when-node-index-is-out-of.patch @@ -0,0 +1,57 @@ +From af911371436ef3adf09fca4433f71f8f17631e1b Mon Sep 17 00:00:00 2001 +From: Igor Mammedov +Date: Mon, 2 Jul 2018 13:57:09 +0200 +Subject: [PATCH 52/57] numa: clarify error message when node index is out of + range in -numa dist, ... + +RH-Author: Igor Mammedov +Message-id: <1530539829-260581-1-git-send-email-imammedo@redhat.com> +Patchwork-id: 81184 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH] numa: clarify error message when node index is out of range in -numa dist, ... +Bugzilla: 1578381 +RH-Acked-by: Andrew Jones +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Eduardo Habkost +RH-Acked-by: Pankaj Gupta + +When using following CLI: + -numa dist,src=128,dst=1,val=20 +user gets a rather confusing error message: + "Invalid node 128, max possible could be 128" + +Where 128 is number of nodes that QEMU supports (MAX_NODES), +while src/dst is an index up to that limit, so it should be +MAX_NODES - 1 in error message. +Make error message to explicitly state valid range for node +index to be more clear. + +Signed-off-by: Igor Mammedov +Message-Id: <1526483174-169008-1-git-send-email-imammedo@redhat.com> +Reviewed-by: Eric Blake +Signed-off-by: Eduardo Habkost +(cherry picked from commit 74f38e96b321ef8df2bf7fa1bd4f673ef06aca5b) +Signed-off-by: Igor Mammedov +Signed-off-by: Miroslav Rezanina +--- + numa.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/numa.c b/numa.c +index daf10d8..bb8f773 100644 +--- a/numa.c ++++ b/numa.c +@@ -140,9 +140,8 @@ static void parse_numa_distance(NumaDistOptions *dist, Error **errp) + uint8_t val = dist->val; + + if (src >= MAX_NODES || dst >= MAX_NODES) { +- error_setg(errp, +- "Invalid node %d, max possible could be %d", +- MAX(src, dst), MAX_NODES); ++ error_setg(errp, "Parameter '%s' expects an integer between 0 and %d", ++ src >= MAX_NODES ? "src" : "dst", MAX_NODES - 1); + return; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-object-fix-OBJ_PROP_LINK_UNREF_ON_RELEASE-ambivalenc.patch b/SOURCES/kvm-object-fix-OBJ_PROP_LINK_UNREF_ON_RELEASE-ambivalenc.patch new file mode 100644 index 0000000..4890b4d --- /dev/null +++ b/SOURCES/kvm-object-fix-OBJ_PROP_LINK_UNREF_ON_RELEASE-ambivalenc.patch @@ -0,0 +1,334 @@ +From b2c33dbdec6e1abecee77c28398275a7337d6154 Mon Sep 17 00:00:00 2001 +From: Serhii Popovych +Date: Mon, 9 Jul 2018 11:31:16 +0200 +Subject: [PATCH 26/89] object: fix OBJ_PROP_LINK_UNREF_ON_RELEASE ambivalence +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Serhii Popovych +Message-id: <1531135878-18813-2-git-send-email-spopovyc@redhat.com> +Patchwork-id: 81265 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v2 1/3] object: fix OBJ_PROP_LINK_UNREF_ON_RELEASE ambivalence +Bugzilla: 1556678 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Marc-André Lureau +RH-Acked-by: David Gibson + +From: Marc-André Lureau + +A link property can be set during creation, with +object_property_add_link() and later with object_property_set_link(). + +add_link() doesn't add a reference to the target object, while +set_link() does. + +Furthemore, OBJ_PROP_LINK_UNREF_ON_RELEASE flags, set during add_link, +says whether a reference must be released when the property is destroyed. +This can lead to leaks if the property was later set_link(), as the +added reference is never released. + +Instead, rename OBJ_PROP_LINK_UNREF_ON_RELEASE to OBJ_PROP_LINK_STRONG +and use that has an indication on how the link handle reference +management in set_link(). + +Signed-off-by: Marc-André Lureau +Message-id: 20180531195119.22021-3-marcandre.lureau@redhat.com +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 265b578c584b1a86c7028790deaa2f4392dd0a65) +Signed-off-by: Serhii Popovych +Signed-off-by: Miroslav Rezanina + +Conflicts: + hw/dma/xlnx-zdma.c + +This file is missing in 2.12.0. +--- + hw/core/qdev-properties.c | 2 +- + hw/core/qdev.c | 2 +- + hw/display/xlnx_dp.c | 2 +- + hw/dma/xilinx_axidma.c | 4 ++-- + hw/i386/pc.c | 2 +- + hw/i386/pc_piix.c | 2 +- + hw/i386/pc_q35.c | 2 +- + hw/ipmi/ipmi.c | 2 +- + hw/net/xilinx_axienet.c | 4 ++-- + hw/ssi/xilinx_spips.c | 2 +- + include/qom/object.h | 12 +++++++++--- + net/can/can_host.c | 2 +- + net/colo-compare.c | 2 +- + qom/object.c | 8 +++++--- + target/arm/cpu.c | 4 ++-- + ui/console.c | 2 +- + 16 files changed, 31 insertions(+), 23 deletions(-) + +diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c +index 5bbc2d9..f3a83a3 100644 +--- a/hw/core/qdev-properties.c ++++ b/hw/core/qdev-properties.c +@@ -1309,7 +1309,7 @@ static void create_link_property(Object *obj, Property *prop, Error **errp) + object_property_add_link(obj, prop->name, prop->link_type, + child, + qdev_prop_allow_set_link_before_realize, +- OBJ_PROP_LINK_UNREF_ON_RELEASE, ++ OBJ_PROP_LINK_STRONG, + errp); + } + +diff --git a/hw/core/qdev.c b/hw/core/qdev.c +index f6f9247..ce7c316 100644 +--- a/hw/core/qdev.c ++++ b/hw/core/qdev.c +@@ -435,7 +435,7 @@ void qdev_init_gpio_out_named(DeviceState *dev, qemu_irq *pins, + object_property_add_link(OBJECT(dev), propname, TYPE_IRQ, + (Object **)&pins[i], + object_property_allow_set_link, +- OBJ_PROP_LINK_UNREF_ON_RELEASE, ++ OBJ_PROP_LINK_STRONG, + &error_abort); + g_free(propname); + } +diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c +index 6715b9c..b737e1d 100644 +--- a/hw/display/xlnx_dp.c ++++ b/hw/display/xlnx_dp.c +@@ -1221,7 +1221,7 @@ static void xlnx_dp_init(Object *obj) + object_property_add_link(obj, "dpdma", TYPE_XLNX_DPDMA, + (Object **) &s->dpdma, + xlnx_dp_set_dpdma, +- OBJ_PROP_LINK_UNREF_ON_RELEASE, ++ OBJ_PROP_LINK_STRONG, + &error_abort); + + /* +diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c +index 9b48103..401a328 100644 +--- a/hw/dma/xilinx_axidma.c ++++ b/hw/dma/xilinx_axidma.c +@@ -525,12 +525,12 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp) + object_property_add_link(OBJECT(ds), "dma", TYPE_XILINX_AXI_DMA, + (Object **)&ds->dma, + object_property_allow_set_link, +- OBJ_PROP_LINK_UNREF_ON_RELEASE, ++ OBJ_PROP_LINK_STRONG, + &local_err); + object_property_add_link(OBJECT(cs), "dma", TYPE_XILINX_AXI_DMA, + (Object **)&cs->dma, + object_property_allow_set_link, +- OBJ_PROP_LINK_UNREF_ON_RELEASE, ++ OBJ_PROP_LINK_STRONG, + &local_err); + if (local_err) { + goto xilinx_axidma_realize_fail; +diff --git a/hw/i386/pc.c b/hw/i386/pc.c +index 265decf..7160969 100644 +--- a/hw/i386/pc.c ++++ b/hw/i386/pc.c +@@ -485,7 +485,7 @@ void pc_cmos_init(PCMachineState *pcms, + TYPE_ISA_DEVICE, + (Object **)&pcms->rtc, + object_property_allow_set_link, +- OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort); ++ OBJ_PROP_LINK_STRONG, &error_abort); + object_property_set_link(OBJECT(pcms), OBJECT(s), + "rtc_state", &error_abort); + +diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c +index 8a355df..00549c4 100644 +--- a/hw/i386/pc_piix.c ++++ b/hw/i386/pc_piix.c +@@ -290,7 +290,7 @@ static void pc_init1(MachineState *machine, + TYPE_HOTPLUG_HANDLER, + (Object **)&pcms->acpi_dev, + object_property_allow_set_link, +- OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort); ++ OBJ_PROP_LINK_STRONG, &error_abort); + object_property_set_link(OBJECT(machine), OBJECT(piix4_pm), + PC_MACHINE_ACPI_DEVICE_PROP, &error_abort); + } +diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c +index e17807e..a273bd5 100644 +--- a/hw/i386/pc_q35.c ++++ b/hw/i386/pc_q35.c +@@ -194,7 +194,7 @@ static void pc_q35_init(MachineState *machine) + TYPE_HOTPLUG_HANDLER, + (Object **)&pcms->acpi_dev, + object_property_allow_set_link, +- OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort); ++ OBJ_PROP_LINK_STRONG, &error_abort); + object_property_set_link(OBJECT(machine), OBJECT(lpc), + PC_MACHINE_ACPI_DEVICE_PROP, &error_abort); + +diff --git a/hw/ipmi/ipmi.c b/hw/ipmi/ipmi.c +index 9be281f..63c0317 100644 +--- a/hw/ipmi/ipmi.c ++++ b/hw/ipmi/ipmi.c +@@ -104,7 +104,7 @@ void ipmi_bmc_find_and_link(Object *obj, Object **bmc) + { + object_property_add_link(obj, "bmc", TYPE_IPMI_BMC, bmc, + isa_ipmi_bmc_check, +- OBJ_PROP_LINK_UNREF_ON_RELEASE, ++ OBJ_PROP_LINK_STRONG, + &error_abort); + } + +diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c +index d4c2c89..cc880a3 100644 +--- a/hw/net/xilinx_axienet.c ++++ b/hw/net/xilinx_axienet.c +@@ -951,12 +951,12 @@ static void xilinx_enet_realize(DeviceState *dev, Error **errp) + object_property_add_link(OBJECT(ds), "enet", "xlnx.axi-ethernet", + (Object **) &ds->enet, + object_property_allow_set_link, +- OBJ_PROP_LINK_UNREF_ON_RELEASE, ++ OBJ_PROP_LINK_STRONG, + &local_err); + object_property_add_link(OBJECT(cs), "enet", "xlnx.axi-ethernet", + (Object **) &cs->enet, + object_property_allow_set_link, +- OBJ_PROP_LINK_UNREF_ON_RELEASE, ++ OBJ_PROP_LINK_STRONG, + &local_err); + if (local_err) { + goto xilinx_enet_realize_fail; +diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c +index 426f971..068878c 100644 +--- a/hw/ssi/xilinx_spips.c ++++ b/hw/ssi/xilinx_spips.c +@@ -1345,7 +1345,7 @@ static void xlnx_zynqmp_qspips_init(Object *obj) + object_property_add_link(obj, "stream-connected-dma", TYPE_STREAM_SLAVE, + (Object **)&rq->dma, + object_property_allow_set_link, +- OBJ_PROP_LINK_UNREF_ON_RELEASE, ++ OBJ_PROP_LINK_STRONG, + NULL); + } + +diff --git a/include/qom/object.h b/include/qom/object.h +index 96ce81b..fc4555d 100644 +--- a/include/qom/object.h ++++ b/include/qom/object.h +@@ -1103,6 +1103,11 @@ char *object_property_get_str(Object *obj, const char *name, + * @errp: returns an error if this function fails + * + * Writes an object's canonical path to a property. ++ * ++ * If the link property was created with ++ * OBJ_PROP_LINK_STRONG bit, the old target object is ++ * unreferenced, and a reference is added to the new target object. ++ * + */ + void object_property_set_link(Object *obj, Object *value, + const char *name, Error **errp); +@@ -1393,7 +1398,7 @@ void object_property_add_child(Object *obj, const char *name, + + typedef enum { + /* Unref the link pointer when the property is deleted */ +- OBJ_PROP_LINK_UNREF_ON_RELEASE = 0x1, ++ OBJ_PROP_LINK_STRONG = 0x1, + } ObjectPropertyLinkFlags; + + /** +@@ -1431,8 +1436,9 @@ void object_property_allow_set_link(const Object *, const char *, + * link property. The reference count for *@child is + * managed by the property from after the function returns till the + * property is deleted with object_property_del(). If the +- * @flags OBJ_PROP_LINK_UNREF_ON_RELEASE bit is set, +- * the reference count is decremented when the property is deleted. ++ * @flags OBJ_PROP_LINK_STRONG bit is set, ++ * the reference count is decremented when the property is deleted or ++ * modified. + */ + void object_property_add_link(Object *obj, const char *name, + const char *type, Object **child, +diff --git a/net/can/can_host.c b/net/can/can_host.c +index c3d2652..c79347a 100644 +--- a/net/can/can_host.c ++++ b/net/can/can_host.c +@@ -77,7 +77,7 @@ static void can_host_instance_init(Object *obj) + object_property_add_link(obj, "canbus", TYPE_CAN_BUS, + (Object **)&ch->bus, + object_property_allow_set_link, +- OBJ_PROP_LINK_UNREF_ON_RELEASE, ++ OBJ_PROP_LINK_STRONG, + &error_abort); + } + +diff --git a/net/colo-compare.c b/net/colo-compare.c +index 23b2d2c..63469b1 100644 +--- a/net/colo-compare.c ++++ b/net/colo-compare.c +@@ -980,7 +980,7 @@ static void colo_compare_init(Object *obj) + object_property_add_link(obj, "iothread", TYPE_IOTHREAD, + (Object **)&s->iothread, + object_property_allow_set_link, +- OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL); ++ OBJ_PROP_LINK_STRONG, NULL); + + s->vnet_hdr = false; + object_property_add_bool(obj, "vnet_hdr_support", compare_get_vnet_hdr, +diff --git a/qom/object.c b/qom/object.c +index 76a89af..c4f1d36 100644 +--- a/qom/object.c ++++ b/qom/object.c +@@ -1564,9 +1564,11 @@ static void object_set_link_property(Object *obj, Visitor *v, + return; + } + +- object_ref(new_target); + *child = new_target; +- object_unref(old_target); ++ if (prop->flags == OBJ_PROP_LINK_STRONG) { ++ object_ref(new_target); ++ object_unref(old_target); ++ } + } + + static Object *object_resolve_link_property(Object *parent, void *opaque, const gchar *part) +@@ -1581,7 +1583,7 @@ static void object_release_link_property(Object *obj, const char *name, + { + LinkProperty *prop = opaque; + +- if ((prop->flags & OBJ_PROP_LINK_UNREF_ON_RELEASE) && *prop->child) { ++ if ((prop->flags & OBJ_PROP_LINK_STRONG) && *prop->child) { + object_unref(*prop->child); + } + g_free(prop); +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index 4255e9c..9d030e0 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -672,7 +672,7 @@ static void arm_cpu_post_init(Object *obj) + TYPE_MEMORY_REGION, + (Object **)&cpu->secure_memory, + qdev_prop_allow_set_link_before_realize, +- OBJ_PROP_LINK_UNREF_ON_RELEASE, ++ OBJ_PROP_LINK_STRONG, + &error_abort); + #endif + } +@@ -700,7 +700,7 @@ static void arm_cpu_post_init(Object *obj) + if (arm_feature(&cpu->env, ARM_FEATURE_M_SECURITY)) { + object_property_add_link(obj, "idau", TYPE_IDAU_INTERFACE, &cpu->idau, + qdev_prop_allow_set_link_before_realize, +- OBJ_PROP_LINK_UNREF_ON_RELEASE, ++ OBJ_PROP_LINK_STRONG, + &error_abort); + qdev_property_add_static(DEVICE(obj), &arm_cpu_initsvtor_property, + &error_abort); +diff --git a/ui/console.c b/ui/console.c +index 73b2d3c..4431e77 100644 +--- a/ui/console.c ++++ b/ui/console.c +@@ -1305,7 +1305,7 @@ static QemuConsole *new_console(DisplayState *ds, console_type_t console_type, + object_property_add_link(obj, "device", TYPE_DEVICE, + (Object **)&s->device, + object_property_allow_set_link, +- OBJ_PROP_LINK_UNREF_ON_RELEASE, ++ OBJ_PROP_LINK_STRONG, + &error_abort); + object_property_add_uint32_ptr(obj, "head", + &s->head, &error_abort); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-osdep-Define-QEMU_MADV_REMOVE.patch b/SOURCES/kvm-osdep-Define-QEMU_MADV_REMOVE.patch deleted file mode 100644 index be9a40e..0000000 --- a/SOURCES/kvm-osdep-Define-QEMU_MADV_REMOVE.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 50789e32c0d8f91b69c918f43ee9415b2fbd86e0 Mon Sep 17 00:00:00 2001 -From: Eduardo Habkost -Date: Thu, 19 Oct 2017 01:34:52 +0200 -Subject: [PATCH 63/69] osdep: Define QEMU_MADV_REMOVE - -RH-Author: Eduardo Habkost -Message-id: <20171019013453.21449-4-ehabkost@redhat.com> -Patchwork-id: 77369 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 3/4] osdep: Define QEMU_MADV_REMOVE -Bugzilla: 1460848 -RH-Acked-by: Michael S. Tsirkin -RH-Acked-by: Igor Mammedov -RH-Acked-by: Paolo Bonzini - -Define QEMU_MADV_REMOVE, so we can use it with qemu_madvise(). - -Signed-off-by: Eduardo Habkost -Message-Id: <20170824192315.5897-3-ehabkost@redhat.com> -Reviewed-by: Dr. David Alan Gilbert -Tested-by: Zack Cornelius -Signed-off-by: Eduardo Habkost -(cherry picked from commit 0f81d3353029d26c6f8731a65d8052c532b1ced6) -Signed-off-by: Eduardo Habkost -Signed-off-by: Miroslav Rezanina ---- - include/qemu/osdep.h | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h -index 6855b94..e9fa217 100644 ---- a/include/qemu/osdep.h -+++ b/include/qemu/osdep.h -@@ -257,6 +257,11 @@ void qemu_anon_ram_free(void *ptr, size_t size); - #else - #define QEMU_MADV_NOHUGEPAGE QEMU_MADV_INVALID - #endif -+#ifdef MADV_REMOVE -+#define QEMU_MADV_REMOVE MADV_REMOVE -+#else -+#define QEMU_MADV_REMOVE QEMU_MADV_INVALID -+#endif - - #elif defined(CONFIG_POSIX_MADVISE) - -@@ -269,6 +274,7 @@ void qemu_anon_ram_free(void *ptr, size_t size); - #define QEMU_MADV_DONTDUMP QEMU_MADV_INVALID - #define QEMU_MADV_HUGEPAGE QEMU_MADV_INVALID - #define QEMU_MADV_NOHUGEPAGE QEMU_MADV_INVALID -+#define QEMU_MADV_REMOVE QEMU_MADV_INVALID - - #else /* no-op */ - -@@ -281,6 +287,7 @@ void qemu_anon_ram_free(void *ptr, size_t size); - #define QEMU_MADV_DONTDUMP QEMU_MADV_INVALID - #define QEMU_MADV_HUGEPAGE QEMU_MADV_INVALID - #define QEMU_MADV_NOHUGEPAGE QEMU_MADV_INVALID -+#define QEMU_MADV_REMOVE QEMU_MADV_INVALID - - #endif - --- -1.8.3.1 - diff --git a/SOURCES/kvm-osdep-Force-define-F_OFD_GETLK-RHEL-only.patch b/SOURCES/kvm-osdep-Force-define-F_OFD_GETLK-RHEL-only.patch deleted file mode 100644 index cc443da..0000000 --- a/SOURCES/kvm-osdep-Force-define-F_OFD_GETLK-RHEL-only.patch +++ /dev/null @@ -1,52 +0,0 @@ -From ac74b9067d079b03f3fe4236270f9eb34121009b Mon Sep 17 00:00:00 2001 -From: Fam Zheng -Date: Thu, 12 Oct 2017 13:54:45 +0200 -Subject: [PATCH 16/69] osdep: Force define F_OFD_GETLK (RHEL only) - -RH-Author: Fam Zheng -Message-id: <20171012135445.4214-1-famz@redhat.com> -Patchwork-id: 77220 -O-Subject: [RHV7.5 qemu-kvm-ma PATCH] osdep: Force define F_OFD_GETLK (RHEL only) -Bugzilla: 1378241 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Thomas Huth - -BZ: 1378241 -Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=14254218 - -glibc is not ready yet (BZ 1461231, which is deferred to 7.6 due to -capacity), so the OFD constants are not defined in the system headers we -pull in. (They do exist in the headers of latest kernel-headers package, -but we don't want to include that anyway.) - -Actually the constants are all that are missing before we can call image -locking done in 7.5, so there is no reason to wait for glibc. - -This patch can be reverted once the new glibc headers are in place. - -Signed-off-by: Fam Zheng -Signed-off-by: Miroslav Rezanina ---- - util/osdep.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/util/osdep.c b/util/osdep.c -index a479fed..8358a44 100644 ---- a/util/osdep.c -+++ b/util/osdep.c -@@ -23,6 +23,11 @@ - */ - #include "qemu/osdep.h" - -+#ifndef F_OFD_SETLK -+#define F_OFD_GETLK 36 -+#define F_OFD_SETLK 37 -+#endif -+ - /* Needed early for CONFIG_BSD etc. */ - - #ifdef CONFIG_SOLARIS --- -1.8.3.1 - diff --git a/SOURCES/kvm-osdep-Retry-SETLK-upon-EINTR.patch b/SOURCES/kvm-osdep-Retry-SETLK-upon-EINTR.patch deleted file mode 100644 index 24c241f..0000000 --- a/SOURCES/kvm-osdep-Retry-SETLK-upon-EINTR.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 3227ce9e3ea004e742f2a3390c426c9699e26a16 Mon Sep 17 00:00:00 2001 -From: Fam Zheng -Date: Fri, 26 Jan 2018 02:07:36 +0100 -Subject: [PATCH 5/8] osdep: Retry SETLK upon EINTR - -RH-Author: Fam Zheng -Message-id: <20180126020736.24596-1-famz@redhat.com> -Patchwork-id: 78706 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH] osdep: Retry SETLK upon EINTR -Bugzilla: 1529053 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Kevin Wolf - -We could hit lock failure if there is a signal that makes fcntl return --1 and errno set to EINTR. In this case we should retry. - -Cc: qemu-stable@nongnu.org -Signed-off-by: Fam Zheng -Reviewed-by: Eric Blake -Signed-off-by: Kevin Wolf -(cherry picked from commit f86428a1f4f91a460ed585682af70d3e8c31dc06) -Signed-off-by: Fam Zheng -Signed-off-by: Miroslav Rezanina ---- - util/osdep.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/util/osdep.c b/util/osdep.c -index 8358a44..ac7d1b2 100644 ---- a/util/osdep.c -+++ b/util/osdep.c -@@ -208,7 +208,9 @@ static int qemu_lock_fcntl(int fd, int64_t start, int64_t len, int fl_type) - .l_type = fl_type, - }; - qemu_probe_lock_ops(); -- ret = fcntl(fd, fcntl_op_setlk, &fl); -+ do { -+ ret = fcntl(fd, fcntl_op_setlk, &fl); -+ } while (ret == -1 && errno == EINTR); - return ret == -1 ? -errno : 0; - } - --- -1.8.3.1 - diff --git a/SOURCES/kvm-osdep-add-wait.h-compat-macros.patch b/SOURCES/kvm-osdep-add-wait.h-compat-macros.patch new file mode 100644 index 0000000..6d17462 --- /dev/null +++ b/SOURCES/kvm-osdep-add-wait.h-compat-macros.patch @@ -0,0 +1,59 @@ +From 39f21fd9c1bcd7f085193e5310efa79c3c759acd Mon Sep 17 00:00:00 2001 +From: "plai@redhat.com" +Date: Thu, 21 Jun 2018 18:54:39 +0200 +Subject: [PATCH 30/57] osdep: add wait.h compat macros + +RH-Author: plai@redhat.com +Message-id: <1529607285-9942-5-git-send-email-plai@redhat.com> +Patchwork-id: 80938 +O-Subject: [RHEL7.6 PATCH BZ 1526645 04/10] osdep: add wait.h compat macros +Bugzilla: 1526645 +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Maxime Coquelin +RH-Acked-by: Laurent Vivier + +From: "Michael S. Tsirkin" + +Man page for WCOREDUMP says: + + WCOREDUMP(wstatus) returns true if the child produced a core dump. + This macro should be employed only if WIFSIGNALED returned true. + + This macro is not specified in POSIX.1-2001 and is not + available on some UNIX implementations (e.g., AIX, SunOS). Therefore, + enclose its use inside #ifdef WCOREDUMP ... #endif. + +Let's do exactly this. + +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 28012e190e6897cfc2a98364240909d08e90ffc0) +Signed-off-by: Paul Lai +Signed-off-by: Miroslav Rezanina +--- + include/qemu/osdep.h | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h +index 4165806..afc28e5 100644 +--- a/include/qemu/osdep.h ++++ b/include/qemu/osdep.h +@@ -108,6 +108,16 @@ extern int daemon(int, int); + #include "qemu/typedefs.h" + + /* ++ * According to waitpid man page: ++ * WCOREDUMP ++ * This macro is not specified in POSIX.1-2001 and is not ++ * available on some UNIX implementations (e.g., AIX, SunOS). ++ * Therefore, enclose its use inside #ifdef WCOREDUMP ... #endif. ++ */ ++#ifndef WCOREDUMP ++#define WCOREDUMP(status) 0 ++#endif ++/* + * We have a lot of unaudited code that may fail in strange ways, or + * even be a security risk during migration, if you disable assertions + * at compile-time. You may comment out these safety checks if you +-- +1.8.3.1 + diff --git a/SOURCES/kvm-osdep-powerpc64-align-memory-to-allow-2MB-radix-THP-.patch b/SOURCES/kvm-osdep-powerpc64-align-memory-to-allow-2MB-radix-THP-.patch new file mode 100644 index 0000000..15a952d --- /dev/null +++ b/SOURCES/kvm-osdep-powerpc64-align-memory-to-allow-2MB-radix-THP-.patch @@ -0,0 +1,48 @@ +From 7ac01358cfb1a7900cfc4b39714f9affb817dda0 Mon Sep 17 00:00:00 2001 +From: David Gibson +Date: Mon, 16 Jul 2018 05:49:55 +0200 +Subject: [PATCH 45/89] osdep: powerpc64 align memory to allow 2MB radix THP + page tables + +RH-Author: David Gibson +Message-id: <20180716054955.12926-1-dgibson@redhat.com> +Patchwork-id: 81358 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH] osdep: powerpc64 align memory to allow 2MB radix THP page tables +Bugzilla: 1600797 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Thomas Huth +RH-Acked-by: Serhii Popovych + +From: Nicholas Piggin + +This allows KVM with the Book3S radix MMU mode to take advantage of +THP and install larger pages in the partition scope page tables (the +host translation). + +Signed-off-by: Nicholas Piggin +Signed-off-by: David Gibson +(cherry picked from commit 0c1272cc7c72dfe0ef66be8f283cf67c74b58586) + +Signed-off-by: David Gibson +Signed-off-by: Miroslav Rezanina +--- + include/qemu/osdep.h | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h +index afc28e5..9ed6242 100644 +--- a/include/qemu/osdep.h ++++ b/include/qemu/osdep.h +@@ -367,7 +367,8 @@ void qemu_anon_ram_free(void *ptr, size_t size); + #endif + + #if defined(__linux__) && \ +- (defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)) ++ (defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) \ ++ || defined(__powerpc64__)) + /* Use 2 MiB alignment so transparent hugepages can be used by KVM. + Valgrind does not support alignments larger than 1 MiB, + therefore we need special code which handles running on Valgrind. */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pc-Add-rhel7.6.0-machine-types.patch b/SOURCES/kvm-pc-Add-rhel7.6.0-machine-types.patch new file mode 100644 index 0000000..6efbbf1 --- /dev/null +++ b/SOURCES/kvm-pc-Add-rhel7.6.0-machine-types.patch @@ -0,0 +1,116 @@ +From 9476ec6ee439ffc60ddd1478c2ed1fb87253f319 Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Fri, 29 Jun 2018 18:59:37 +0200 +Subject: [PATCH 50/57] pc: Add rhel7.6.0 machine-types + +RH-Author: Eduardo Habkost +Message-id: <20180629185937.24186-2-ehabkost@redhat.com> +Patchwork-id: 81175 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/1] pc: Add rhel7.6.0 machine-types +Bugzilla: 1557051 +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Igor Mammedov + +Add rhel7.6.0 machine-types. They will be similar to the +existing 7.5.0 machines, but without the PC_RHEL7_5_COMPAT bits. + +Signed-off-by: Eduardo Habkost +Signed-off-by: Miroslav Rezanina +--- + hw/i386/pc_piix.c | 21 ++++++++++++++++++--- + hw/i386/pc_q35.c | 18 ++++++++++++++++-- + 2 files changed, 34 insertions(+), 5 deletions(-) + +diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c +index 9991650..8a355df 100644 +--- a/hw/i386/pc_piix.c ++++ b/hw/i386/pc_piix.c +@@ -1157,6 +1157,21 @@ static void pc_machine_rhel7_options(MachineClass *m) + m->is_default = 1; + } + ++static void pc_init_rhel760(MachineState *machine) ++{ ++ pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \ ++ TYPE_I440FX_PCI_DEVICE); ++} ++ ++static void pc_machine_rhel760_options(MachineClass *m) ++{ ++ pc_machine_rhel7_options(m); ++ m->desc = "RHEL 7.6.0 PC (i440FX + PIIX, 1996)"; ++} ++ ++DEFINE_PC_MACHINE(rhel760, "pc-i440fx-rhel7.6.0", pc_init_rhel760, ++ pc_machine_rhel760_options); ++ + static void pc_init_rhel750(MachineState *machine) + { + pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \ +@@ -1165,7 +1180,9 @@ static void pc_init_rhel750(MachineState *machine) + + static void pc_machine_rhel750_options(MachineClass *m) + { +- pc_machine_rhel7_options(m); ++ pc_machine_rhel760_options(m); ++ m->alias = NULL; ++ m->is_default = 0; + m->desc = "RHEL 7.5.0 PC (i440FX + PIIX, 1996)"; + m->auto_enable_numa_with_memhp = false; + SET_MACHINE_COMPAT(m, PC_RHEL7_5_COMPAT); +@@ -1184,8 +1201,6 @@ static void pc_machine_rhel740_options(MachineClass *m) + { + PCMachineClass *pcmc = PC_MACHINE_CLASS(m); + pc_machine_rhel750_options(m); +- m->alias = NULL; +- m->is_default = 0; + m->desc = "RHEL 7.4.0 PC (i440FX + PIIX, 1996)"; + m->numa_auto_assign_ram = numa_legacy_auto_assign_ram; + pcmc->pc_rom_ro = false; +diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c +index a4387e0..e17807e 100644 +--- a/hw/i386/pc_q35.c ++++ b/hw/i386/pc_q35.c +@@ -424,6 +424,20 @@ static void pc_q35_machine_rhel7_options(MachineClass *m) + SET_MACHINE_COMPAT(m, PC_RHEL_COMPAT); + } + ++static void pc_q35_init_rhel760(MachineState *machine) ++{ ++ pc_q35_init(machine); ++} ++ ++static void pc_q35_machine_rhel760_options(MachineClass *m) ++{ ++ pc_q35_machine_rhel7_options(m); ++ m->desc = "RHEL-7.6.0 PC (Q35 + ICH9, 2009)"; ++} ++ ++DEFINE_PC_MACHINE(q35_rhel760, "pc-q35-rhel7.6.0", pc_q35_init_rhel760, ++ pc_q35_machine_rhel760_options); ++ + static void pc_q35_init_rhel750(MachineState *machine) + { + pc_q35_init(machine); +@@ -432,7 +446,8 @@ static void pc_q35_init_rhel750(MachineState *machine) + static void pc_q35_machine_rhel750_options(MachineClass *m) + { + PCMachineClass *pcmc = PC_MACHINE_CLASS(m); +- pc_q35_machine_rhel7_options(m); ++ pc_q35_machine_rhel760_options(m); ++ m->alias = NULL; + m->desc = "RHEL-7.5.0 PC (Q35 + ICH9, 2009)"; + m->auto_enable_numa_with_memhp = false; + pcmc->default_nic_model = "e1000"; +@@ -451,7 +466,6 @@ static void pc_q35_machine_rhel740_options(MachineClass *m) + { + PCMachineClass *pcmc = PC_MACHINE_CLASS(m); + pc_q35_machine_rhel750_options(m); +- m->alias = NULL; + m->desc = "RHEL-7.4.0 PC (Q35 + ICH9, 2009)"; + m->numa_auto_assign_ram = numa_legacy_auto_assign_ram; + pcmc->pc_rom_ro = false; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pc-acpi-fix-memory-hotplug-regression-by-reducing-st.patch b/SOURCES/kvm-pc-acpi-fix-memory-hotplug-regression-by-reducing-st.patch new file mode 100644 index 0000000..8279315 --- /dev/null +++ b/SOURCES/kvm-pc-acpi-fix-memory-hotplug-regression-by-reducing-st.patch @@ -0,0 +1,101 @@ +From 6d5bc18c3af1969cfcaea9c9bafb5ad0d32bb163 Mon Sep 17 00:00:00 2001 +From: Igor Mammedov +Date: Tue, 7 Aug 2018 12:33:52 +0200 +Subject: [PATCH 05/13] pc: acpi: fix memory hotplug regression by reducing + stub SRAT entry size + +RH-Author: Igor Mammedov +Message-id: <1533645232-98572-1-git-send-email-imammedo@redhat.com> +Patchwork-id: 81662 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH] pc: acpi: fix memory hotplug regression by reducing stub SRAT entry size +Bugzilla: 1609234 +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Eduardo Habkost + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1609234 +Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=17640116 +Branch: rhv7/master-2.12.0 + + 1: there is no coldplugged dimm in the last numa node + but there is a coldplugged dimm in another node + + -m 4096,slots=4,maxmem=32G \ + -object memory-backend-ram,id=m0,size=2G \ + -device pc-dimm,memdev=m0,node=0 \ + -numa node,nodeid=0 \ + -numa node,nodeid=1 + + 2: if order of dimms on CLI is: + 1st plugged dimm in node1 + 2nd plugged dimm in node0 + + -m 4096,slots=4,maxmem=32G \ + -object memory-backend-ram,size=2G,id=m0 \ + -device pc-dimm,memdev=m0,node=1 \ + -object memory-backend-ram,id=m1,size=2G \ + -device pc-dimm,memdev=m1,node=0 \ + -numa node,nodeid=0 \ + -numa node,nodeid=1 + +(qemu) object_add memory-backend-ram,id=m2,size=1G +(qemu) device_add pc-dimm,memdev=m2,node=0 + +the first DIMM hotplug to any node except the last one +fails (Windows is unable to online it). + +Length reduction of stub hotplug memory SRAT entry, +fixes issue for some reason. + +RHBZ: 1609234 + +Signed-off-by: Igor Mammedov +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin + +(cherry picked from commit 10efd7e1088855dc019e6a248ac7f9b24af8dd26) +Signed-off-by: Miroslav Rezanina +--- + hw/i386/acpi-build.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c +index b309a97..683e5f4 100644 +--- a/hw/i386/acpi-build.c ++++ b/hw/i386/acpi-build.c +@@ -2271,7 +2271,16 @@ static void build_srat_hotpluggable_memory(GArray *table_data, uint64_t base, + numamem = acpi_data_push(table_data, sizeof *numamem); + + if (!info) { +- build_srat_memory(numamem, cur, end - cur, default_node, ++ /* ++ * Entry is required for Windows to enable memory hotplug in OS ++ * and for Linux to enable SWIOTLB when booted with less than ++ * 4G of RAM. Windows works better if the entry sets proximity ++ * to the highest NUMA node in the machine at the end of the ++ * reserved space. ++ * Memory devices may override proximity set by this entry, ++ * providing _PXM method if necessary. ++ */ ++ build_srat_memory(numamem, end - 1, 1, default_node, + MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED); + break; + } +@@ -2404,14 +2413,6 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) + build_srat_memory(numamem, 0, 0, 0, MEM_AFFINITY_NOFLAGS); + } + +- /* +- * Entry is required for Windows to enable memory hotplug in OS +- * and for Linux to enable SWIOTLB when booted with less than +- * 4G of RAM. Windows works better if the entry sets proximity +- * to the highest NUMA node in the machine. +- * Memory devices may override proximity set by this entry, +- * providing _PXM method if necessary. +- */ + if (hotplugabble_address_space_size) { + build_srat_hotpluggable_memory(table_data, pcms->hotplug_memory.base, + hotplugabble_address_space_size, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pc-acpi-revert-back-to-1-SRAT-entry-for-hotpluggable.patch b/SOURCES/kvm-pc-acpi-revert-back-to-1-SRAT-entry-for-hotpluggable.patch new file mode 100644 index 0000000..ce02fe8 --- /dev/null +++ b/SOURCES/kvm-pc-acpi-revert-back-to-1-SRAT-entry-for-hotpluggable.patch @@ -0,0 +1,156 @@ +From cffbabd734488678614832ff26222aaa10920472 Mon Sep 17 00:00:00 2001 +From: Igor Mammedov +Date: Wed, 12 Sep 2018 15:21:41 +0200 +Subject: [PATCH 06/49] pc: acpi: revert back to 1 SRAT entry for hotpluggable + area + +RH-Author: Igor Mammedov +Message-id: <1536765701-266415-1-git-send-email-imammedo@redhat.com> +Patchwork-id: 82145 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH] pc: acpi: revert back to 1 SRAT entry for hotpluggable area +Bugzilla: 1626059 +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Eduardo Habkost + +Commit + 10efd7e108 "pc: acpi: fix memory hotplug regression by reducing stub SRAT entry size" +attemped to fix hotplug regression introduced by + 848a1cc1e "hw/acpi-build: build SRAT memory affinity structures for DIMM devices" + +fixed issue for Windows/3.0+ linux kernels, however it regressed 2.6 based +kernels (RHEL6) to the point where guest might crash at boot. +Reason is that 2.6 kernel discards SRAT table due too small last entry +which down the road leads to crashes. Hack I've tried in 10efd7e108 is also +not ACPI spec compliant according to which whole possible RAM should be +described in SRAT. Revert 10efd7e108 to fix regression for 2.6 based kernels. + +With 10efd7e108 reverted, I've also tried splitting SRAT table statically +in different ways %/node and %/slot but Windows still fails to online +2nd pc-dimm hot-plugged into node 0 (as described in 10efd7e108) and +sometimes even coldplugged pc-dimms where affected with static SRAT +partitioning. +The only known so far way where Windows stays happy is when we have 1 +SRAT entry in the last node covering all hotplug area. + +Revert 848a1cc1e until we come up with a way to avoid regression +on Windows with hotplug area split in several entries. +Tested this with 2.6/3.0 based kernels (RHEL6/7) and WS20[08/12/12R2/16]). + +Signed-off-by: Igor Mammedov +Acked-by: Laszlo Ersek +Reviewed-by: Eduardo Habkost +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(pull request https://www.mail-archive.com/qemu-devel@nongnu.org/msg560638.html) + +Signed-off-by: Miroslav Rezanina + +Conflicts: + hw/i386/acpi-build.c + - contextual conflict since we do not have + (d471bf3e hw/i386: Use the IEC binary prefix definitions) + (b0c14ec4 machine: make MemoryHotplugState accessible via the machine) + +Since it's blocker and urgent, sending patch without waiting for upstream +commit id (pull req is out there but it looks like Peter is absent to merge it) +--- + hw/i386/acpi-build.c | 74 +++++++++------------------------------------------- + 1 file changed, 13 insertions(+), 61 deletions(-) + +diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c +index 683e5f4..2bc8117 100644 +--- a/hw/i386/acpi-build.c ++++ b/hw/i386/acpi-build.c +@@ -2253,64 +2253,6 @@ build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog) + #define HOLE_640K_START (640 * 1024) + #define HOLE_640K_END (1024 * 1024) + +-static void build_srat_hotpluggable_memory(GArray *table_data, uint64_t base, +- uint64_t len, int default_node) +-{ +- MemoryDeviceInfoList *info_list = qmp_pc_dimm_device_list(); +- MemoryDeviceInfoList *info; +- MemoryDeviceInfo *mi; +- PCDIMMDeviceInfo *di; +- uint64_t end = base + len, cur, size; +- bool is_nvdimm; +- AcpiSratMemoryAffinity *numamem; +- MemoryAffinityFlags flags; +- +- for (cur = base, info = info_list; +- cur < end; +- cur += size, info = info->next) { +- numamem = acpi_data_push(table_data, sizeof *numamem); +- +- if (!info) { +- /* +- * Entry is required for Windows to enable memory hotplug in OS +- * and for Linux to enable SWIOTLB when booted with less than +- * 4G of RAM. Windows works better if the entry sets proximity +- * to the highest NUMA node in the machine at the end of the +- * reserved space. +- * Memory devices may override proximity set by this entry, +- * providing _PXM method if necessary. +- */ +- build_srat_memory(numamem, end - 1, 1, default_node, +- MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED); +- break; +- } +- +- mi = info->value; +- is_nvdimm = (mi->type == MEMORY_DEVICE_INFO_KIND_NVDIMM); +- di = !is_nvdimm ? mi->u.dimm.data : mi->u.nvdimm.data; +- +- if (cur < di->addr) { +- build_srat_memory(numamem, cur, di->addr - cur, default_node, +- MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED); +- numamem = acpi_data_push(table_data, sizeof *numamem); +- } +- +- size = di->size; +- +- flags = MEM_AFFINITY_ENABLED; +- if (di->hotpluggable) { +- flags |= MEM_AFFINITY_HOTPLUGGABLE; +- } +- if (is_nvdimm) { +- flags |= MEM_AFFINITY_NON_VOLATILE; +- } +- +- build_srat_memory(numamem, di->addr, size, di->node, flags); +- } +- +- qapi_free_MemoryDeviceInfoList(info_list); +-} +- + static void + build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) + { +@@ -2413,10 +2355,20 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) + build_srat_memory(numamem, 0, 0, 0, MEM_AFFINITY_NOFLAGS); + } + ++ /* ++ * Entry is required for Windows to enable memory hotplug in OS ++ * and for Linux to enable SWIOTLB when booted with less than ++ * 4G of RAM. Windows works better if the entry sets proximity ++ * to the highest NUMA node in the machine at the end of the ++ * reserved space. ++ * Memory devices may override proximity set by this entry, ++ * providing _PXM method if necessary. ++ */ + if (hotplugabble_address_space_size) { +- build_srat_hotpluggable_memory(table_data, pcms->hotplug_memory.base, +- hotplugabble_address_space_size, +- pcms->numa_nodes - 1); ++ numamem = acpi_data_push(table_data, sizeof *numamem); ++ build_srat_memory(numamem, pcms->hotplug_memory.base, ++ hotplugabble_address_space_size, pcms->numa_nodes - 1, ++ MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED); + } + + build_header(linker, table_data, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pc-bios-keymaps-keymaps-update.patch b/SOURCES/kvm-pc-bios-keymaps-keymaps-update.patch deleted file mode 100644 index 08d6c93..0000000 --- a/SOURCES/kvm-pc-bios-keymaps-keymaps-update.patch +++ /dev/null @@ -1,27918 +0,0 @@ -From 1e23fbdd90c3004fcf833222801dc69cc524bdca Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Mon, 23 Oct 2017 12:29:35 +0200 -Subject: [PATCH 2/9] pc-bios/keymaps: keymaps update - -RH-Author: Gerd Hoffmann -Message-id: <20171023122935.11297-2-kraxel@redhat.com> -Patchwork-id: 77430 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 1/1] pc-bios/keymaps: keymaps update -Bugzilla: 1503128 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Laurent Vivier -RH-Acked-by: Miroslav Rezanina - -Update the keymaps with the ones generated by qemu-keymap - -Signed-off-by: Gerd Hoffmann -Message-id: 20171005153330.19210-4-kraxel@redhat.com -(cherry picked from commit a7815faffb2bd594b92aa3542d7b799cc89c5414) -Signed-off-by: Miroslav Rezanina ---- - pc-bios/keymaps/ar | 819 ++++++++++++++++++++++++++++++++---- - pc-bios/keymaps/bepo | 1108 ++++++++++++++++++++++++++++++++++--------------- - pc-bios/keymaps/cz | 853 ++++++++++++++++++++++++++++++++++--- - pc-bios/keymaps/da | 732 +++++++++++++++++++++++++++++++- - pc-bios/keymaps/de | 767 +++++++++++++++++++++++++++++++++- - pc-bios/keymaps/de-ch | 921 ++++++++++++++++++++++++++++++++++------ - pc-bios/keymaps/en-gb | 724 +++++++++++++++++++++++++++++++- - pc-bios/keymaps/en-us | 718 +++++++++++++++++++++++++++++++- - pc-bios/keymaps/es | 744 ++++++++++++++++++++++++++++++++- - pc-bios/keymaps/et | 818 ++++++++++++++++++++++++++++++++---- - pc-bios/keymaps/fi | 814 +++++++++++++++++++++++++++++++++--- - pc-bios/keymaps/fo | 879 ++++++++++++++++++++++++++++++++++++--- - pc-bios/keymaps/fr | 706 +++++++++++++++++++++++++++++-- - pc-bios/keymaps/fr-be | 724 +++++++++++++++++++++++++++++++- - pc-bios/keymaps/fr-ca | 802 ++++++++++++++++++++++++++++++++--- - pc-bios/keymaps/fr-ch | 800 +++++++++++++++++++++++++++++++++-- - pc-bios/keymaps/hr | 752 ++++++++++++++++++++++++++++++++- - pc-bios/keymaps/hu | 883 +++++++++++++++++++++++++++++++++++---- - pc-bios/keymaps/is | 802 ++++++++++++++++++++++++++++++++--- - pc-bios/keymaps/it | 757 ++++++++++++++++++++++++++++++++- - pc-bios/keymaps/ja | 792 +++++++++++++++++++++++++++++++---- - pc-bios/keymaps/lt | 844 +++++++++++++++++++++++++++++++++++-- - pc-bios/keymaps/lv | 766 ++++++++++++++++++++++++++++++++-- - pc-bios/keymaps/mk | 814 ++++++++++++++++++++++++++++++++---- - pc-bios/keymaps/nl | 794 ++++++++++++++++++++++++++++++++++- - pc-bios/keymaps/no | 758 ++++++++++++++++++++++++++++++++- - pc-bios/keymaps/pl | 789 +++++++++++++++++++++++++++++++++-- - pc-bios/keymaps/pt | 737 +++++++++++++++++++++++++++++++- - pc-bios/keymaps/pt-br | 775 +++++++++++++++++++++++++++++++++- - pc-bios/keymaps/ru | 835 ++++++++++++++++++++++++++++++++----- - pc-bios/keymaps/th | 878 +++++++++++++++++++++++++++++++++------ - pc-bios/keymaps/tr | 819 +++++++++++++++++++++++++++++++++--- - 32 files changed, 24007 insertions(+), 1717 deletions(-) - -diff --git a/pc-bios/keymaps/ar b/pc-bios/keymaps/ar -index c430c03..a763c9a 100644 ---- a/pc-bios/keymaps/ar -+++ b/pc-bios/keymaps/ar -@@ -1,98 +1,753 @@ --# generated from XKB map ar --include common --map 0x401 -+# -+# generated by qemu-keymap -+# model : pc105 -+# layout : ar -+# variant : - -+# options : - -+ -+# name: "Arabic" -+ -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+1 0x02 - exclam 0x02 shift -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+2 0x03 - at 0x03 shift -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+3 0x04 - numbersign 0x04 shift -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+4 0x05 - dollar 0x05 shift -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+5 0x06 - percent 0x06 shift -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+6 0x07 - asciicircum 0x07 shift -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+7 0x08 - ampersand 0x08 shift -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+8 0x09 - asterisk 0x09 shift --parenleft 0x0a shift --parenright 0x0b shift -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+9 0x0a -+parenright 0x0a shift -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+0 0x0b -+parenleft 0x0b shift -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc - minus 0x0c - underscore 0x0c shift -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd - equal 0x0d - plus 0x0d shift --Arabic_dad 0x10 altgr --Arabic_fatha 0x10 shift altgr --Arabic_sad 0x11 altgr --Arabic_fathatan 0x11 shift altgr --Arabic_theh 0x12 altgr --Arabic_damma 0x12 shift altgr --Arabic_qaf 0x13 altgr --Arabic_dammatan 0x13 shift altgr --Arabic_feh 0x14 altgr --UFEF9 0x14 shift altgr --Arabic_ghain 0x15 altgr --Arabic_hamzaunderalef 0x15 shift altgr --Arabic_ain 0x16 altgr --grave 0x16 shift altgr --Arabic_ha 0x17 altgr --division 0x17 shift altgr --Arabic_khah 0x18 altgr --multiply 0x18 shift altgr --Arabic_hah 0x19 altgr --Arabic_semicolon 0x19 shift altgr --bracketleft 0x1a --braceleft 0x1a shift --Arabic_jeem 0x1a altgr --bracketright 0x1b --braceright 0x1b shift --Arabic_dal 0x1b altgr --Arabic_sheen 0x1e altgr --backslash 0x1e shift altgr --Arabic_seen 0x1f altgr --Arabic_yeh 0x20 altgr --bracketleft 0x20 shift altgr --Arabic_beh 0x21 altgr --bracketright 0x21 shift altgr --Arabic_lam 0x22 altgr --UFEF7 0x22 shift altgr --Arabic_alef 0x23 altgr --Arabic_hamzaonalef 0x23 shift altgr --Arabic_teh 0x24 altgr --Arabic_tatweel 0x24 shift altgr --Arabic_noon 0x25 altgr --Arabic_comma 0x25 shift altgr --Arabic_meem 0x26 altgr --slash 0x26 shift altgr --semicolon 0x27 -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+Arabic_dad 0x10 -+Arabic_fatha 0x10 shift -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+Arabic_sad 0x11 -+Arabic_fathatan 0x11 shift -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+Arabic_theh 0x12 -+Arabic_damma 0x12 shift -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+Arabic_qaf 0x13 -+Arabic_dammatan 0x13 shift -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+Arabic_feh 0x14 -+UFEF9 0x14 shift -+Arabic_veh 0x14 altgr -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+Arabic_ghain 0x15 -+Arabic_hamzaunderalef 0x15 shift -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+Arabic_ain 0x16 -+grave 0x16 shift -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+Arabic_ha 0x17 -+division 0x17 shift -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+Arabic_khah 0x18 -+multiply 0x18 shift -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+Arabic_hah 0x19 -+Arabic_semicolon 0x19 shift -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a -+Arabic_jeem 0x1a -+less 0x1a shift -+Arabic_tcheh 0x1a altgr -+ -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b -+Arabic_dal 0x1b -+greater 0x1b shift -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+Arabic_sheen 0x1e -+Arabic_kasra 0x1e shift -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+Arabic_seen 0x1f -+Arabic_kasratan 0x1f shift -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+Arabic_yeh 0x20 -+bracketright 0x20 shift -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+Arabic_beh 0x21 -+bracketleft 0x21 shift -+Arabic_peh 0x21 altgr -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+Arabic_lam 0x22 -+UFEF7 0x22 shift -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+Arabic_alef 0x23 -+Arabic_hamzaonalef 0x23 shift -+U0671 0x23 altgr -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+Arabic_teh 0x24 -+Arabic_tatweel 0x24 shift -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+Arabic_noon 0x25 -+Arabic_comma 0x25 shift -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+Arabic_meem 0x26 -+slash 0x26 shift -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 -+Arabic_kaf 0x27 - colon 0x27 shift --Arabic_kaf 0x27 altgr --apostrophe 0x28 -+Arabic_gaf 0x27 altgr -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 -+Arabic_tah 0x28 - quotedbl 0x28 shift --Arabic_tah 0x28 altgr --grave 0x29 --asciitilde 0x29 shift --Arabic_thal 0x29 altgr --Arabic_shadda 0x29 shift altgr -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 -+Arabic_thal 0x29 -+Arabic_shadda 0x29 shift -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b - backslash 0x2b - bar 0x2b shift --less 0x2b altgr --greater 0x2b shift altgr --Arabic_hamzaonyeh 0x2c altgr --asciitilde 0x2c shift altgr --Arabic_hamza 0x2d altgr --Arabic_sukun 0x2d shift altgr --Arabic_hamzaonwaw 0x2e altgr --Arabic_kasra 0x2e shift altgr --Arabic_ra 0x2f altgr --Arabic_kasratan 0x2f shift altgr --UFEFB 0x30 altgr --UFEF5 0x30 shift altgr --Arabic_alefmaksura 0x31 altgr --Arabic_maddaonalef 0x31 shift altgr --Arabic_tehmarbuta 0x32 altgr --apostrophe 0x32 shift altgr --comma 0x33 --less 0x33 shift --Arabic_waw 0x33 altgr --period 0x34 --greater 0x34 shift --Arabic_zain 0x34 altgr --slash 0x35 --question 0x35 shift --Arabic_zah 0x35 altgr --Arabic_question_mark 0x35 shift altgr -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+Arabic_hamzaonyeh 0x2c -+asciitilde 0x2c shift -+guillemotright 0x2c altgr -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+Arabic_hamza 0x2d -+Arabic_sukun 0x2d shift -+guillemotleft 0x2d altgr -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+Arabic_hamzaonwaw 0x2e -+braceright 0x2e shift -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+Arabic_ra 0x2f -+braceleft 0x2f shift -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+UFEFB 0x30 -+UFEF5 0x30 shift -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+Arabic_alefmaksura 0x31 -+Arabic_maddaonalef 0x31 shift -+Arabic_superscript_alef 0x31 altgr -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+Arabic_tehmarbuta 0x32 -+apostrophe 0x32 shift -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 -+Arabic_waw 0x33 -+comma 0x33 shift -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 -+Arabic_zain 0x34 -+period 0x34 shift -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 -+Arabic_zah 0x35 -+Arabic_question_mark 0x35 shift -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Decimal 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 -+bar 0x56 -+brokenbar 0x56 shift -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+Alt_R 0xb8 -+Meta_R 0xb8 shift -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/bepo b/pc-bios/keymaps/bepo -index d40041a..dbe8daa 100644 ---- a/pc-bios/keymaps/bepo -+++ b/pc-bios/keymaps/bepo -@@ -1,333 +1,781 @@ --include common -+# -+# generated by qemu-keymap -+# model : pc105 -+# layout : fr -+# variant : dvorak -+# options : - -+ -+# name: "French (Dvorak)" -+ -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+equal 0x02 -+1 0x02 shift -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+slash 0x03 -+2 0x03 shift -+plusminus 0x03 altgr -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+minus 0x04 -+3 0x04 shift -+onequarter 0x04 altgr -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+egrave 0x05 -+4 0x05 shift -+onehalf 0x05 altgr -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+backslash 0x06 -+5 0x06 shift -+threequarters 0x06 altgr -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+dead_circumflex 0x07 -+6 0x07 shift -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+parenleft 0x08 -+7 0x08 shift -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+ISO_Level3_Latch 0x09 -+8 0x09 shift -+grave 0x09 altgr -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+parenright 0x0a -+9 0x0a shift -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+quotedbl 0x0b -+0 0x0b shift -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc -+bracketleft 0x0c -+plus 0x0c shift -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd -+bracketright 0x0d -+percent 0x0d shift -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+colon 0x10 -+question 0x10 shift -+ae 0x10 altgr -+AE 0x10 shift altgr -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+apostrophe 0x11 -+less 0x11 shift -+dollar 0x11 altgr -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+eacute 0x12 -+greater 0x12 shift -+Eacute 0x12 altgr -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+g 0x13 -+G 0x13 shift -+EuroSign 0x13 altgr -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+period 0x14 -+exclam 0x14 shift -+degree 0x14 altgr -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+h 0x15 -+H 0x15 shift -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+v 0x16 -+V 0x16 shift -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+c 0x17 -+C 0x17 shift -+ccedilla 0x17 altgr -+Ccedilla 0x17 shift altgr -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+m 0x18 -+M 0x18 shift -+mu 0x18 altgr -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+k 0x19 -+K 0x19 shift -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a -+z 0x1a -+Z 0x1a shift -+ -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b -+dead_diaeresis 0x1b -+ampersand 0x1b shift -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+o 0x1e -+O 0x1e shift -+ograve 0x1e altgr -+Ograve 0x1e shift altgr -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+a 0x1f -+A 0x1f shift -+agrave 0x1f altgr -+Agrave 0x1f shift altgr -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+u 0x20 -+U 0x20 shift -+ugrave 0x20 altgr -+Ugrave 0x20 shift altgr -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+e 0x21 -+E 0x21 shift -+egrave 0x21 altgr -+Egrave 0x21 shift altgr -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+b 0x22 -+B 0x22 shift -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+f 0x23 -+F 0x23 shift -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+s 0x24 -+S 0x24 shift -+guillemotleft 0x24 altgr -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+t 0x25 -+T 0x25 shift -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+n 0x26 -+N 0x26 shift -+guillemotright 0x26 altgr -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 -+d 0x27 -+D 0x27 shift -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 -+w 0x28 -+W 0x28 shift -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 -+underscore 0x29 -+asterisk 0x29 shift -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b -+asciitilde 0x2b -+numbersign 0x2b shift -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+semicolon 0x2c -+bar 0x2c shift -+oe 0x2c altgr -+OE 0x2c shift altgr -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+q 0x2d -+Q 0x2d shift -+braceleft 0x2d altgr -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+comma 0x2e -+at 0x2e shift -+braceright 0x2e altgr -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+i 0x2f -+I 0x2f shift -+igrave 0x2f altgr -+Igrave 0x2f shift altgr -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+y 0x30 -+Y 0x30 shift -+sterling 0x30 altgr -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+x 0x31 -+X 0x31 shift -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+r 0x32 -+R 0x32 shift -+masculine 0x32 altgr -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 -+l 0x33 -+L 0x33 shift -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 -+p 0x34 -+P 0x34 shift -+section 0x34 altgr -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 -+j 0x35 -+J 0x35 shift -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+nobreakspace 0x39 altgr -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Decimal 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 -+agrave 0x56 -+ccedilla 0x56 shift -+Agrave 0x56 altgr -+Ccedilla 0x56 shift altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+Alt_R 0xb8 -+Meta_R 0xb8 shift -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) - --# Bépo : Improved ergonomic french keymap using Dvorak method. --# Built by community on 'Dvorak Fr / Bépo' : --# see http://www.clavier-dvorak.org/wiki/ to join and help. - # --# Bépo layout (1.0rc2 version) for a pc105 keyboard (french) : --# ┌────┐ --# │ S A│ S = Shift, A = AltGr + Shift --# │ s a│ s = normal, a = AltGr --# └────┘ -+# quirks section start - # --# ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┲━━━━━━━━━┓ --# │ # ¶ │ 1 „ │ 2 “ │ 3 ” │ 4 ≤ │ 5 ≥ │ 6 │ 7 ¬ │ 8 ¼ │ 9 ½ │ 0 ¾ │ ° ′ │ ` ″ ┃ ⌫ Retour┃ --# │ $ – │ " — │ « < │ » > │ ( [ │ ) ] │ @ ^ │ + ± │ - − │ / ÷ │ * × │ = ≠ │ % ‰ ┃ arrière┃ --# ┢━━━━━┷━┱───┴─┬───┴─┬───┴─┬───┴─┬───┴─┬───┴─┬───┴─┬───┴─┬───┴─┬───┴─┬───┴─┬───┺━┳━━━━━━━┫ --# ┃ ┃ B ¦ │ É ˝ │ P § │ O Œ │ È ` │ ! │ V │ D Ð │ L │ J IJ │ Z Ə │ W ┃Entrée ┃ --# ┃Tab ↹ ┃ b | │ é ˊ │ p & │ o œ │ è ` │ ˆ ¡ │ v ˇ │ d ð │ l / │ j ij │ z ə │ w ̆ ┃ ⏎ ┃ --# ┣━━━━━━━┻┱────┴┬────┴┬────┴┬────┴┬────┴┬────┴┬────┴┬────┴┬────┴┬────┴┬────┴┬────┺┓ ┃ --# ┃ ┃ A Æ │ U Ù │ I ˙ │ E ¤ │ ; ̛ │ C ſ │ T Þ │ S ẞ │ R ™ │ N │ M º │ Ç , ┃ ┃ --# ┃Maj ⇬ ┃ a æ │ u ù │ i ̈ │ e € │ , ’ │ c © │ t þ │ s ß │ r ® │ n ˜ │ m ¯ │ ç ¸ ┃ ┃ --# ┣━━━━━━━┳┹────┬┴────┬┴────┬┴────┬┴────┬┴────┬┴────┬┴────┬┴────┬┴────┬┴────┲┷━━━━━┻━━━━━━┫ --# ┃ ┃ Ê │ À │ Y ‘ │ X ’ │ : · │ K │ ? ̉ │ Q ̣ │ G │ H ‡ │ F ª ┃ ┃ --# ┃Shift ⇧┃ ê / │ à \ │ y { │ x } │ . … │ k ~ │ ' ¿ │ q ˚ │ g µ │ h † │ f ˛ ┃Shift ⇧ ┃ --# ┣━━━━━━━╋━━━━━┷━┳━━━┷━━━┱─┴─────┴─────┴─────┴─────┴─────┴───┲━┷━━━━━╈━━━━━┻━┳━━━━━━━┳━━━┛ --# ┃ ┃ ┃ ┃ Espace inséc. Espace inséc. fin ┃ ┃ ┃ ┃ --# ┃Ctrl ┃Meta ┃Alt ┃ ␣ (Espace) _ ␣ ┃AltGr ⇮┃Menu ┃Ctrl ┃ --# ┗━━━━━━━┻━━━━━━━┻━━━━━━━┹───────────────────────────────────┺━━━━━━━┻━━━━━━━┻━━━━━━━┛ -- -- --# First row --## keycode 41 = dollar numbersign U+2013 U+00b6 --dollar 0x29 --numbersign 0x29 shift --U2013 0x29 altgr --U00b6 0x29 shift altgr -- --## keycode 2 = +quotedbl +one U+2014 U+201e --quotedbl 0x2 --one 0x2 shift --U2014 0x2 altgr --U201e 0x2 shift altgr -- --## keycode 3 = +guillemotleft +two less U+201c --guillemotleft 0x3 --two 0x3 shift --less 0x3 altgr --U201c 0x3 shift altgr -- --## keycode 4 = +guillemotright +three greater U+201d --guillemotright 0x4 --three 0x4 shift --greater 0x4 altgr --U201d 0x4 shift altgr -- --## keycode 5 = +parenleft +four bracketleft U+2264 --parenleft 0x5 --four 0x5 shift --bracketleft 0x5 altgr --U2264 0x5 shift altgr -- --## keycode 6 = +parenright +five bracketright U+2265 --parenright 0x6 --five 0x6 shift --bracketright 0x6 altgr --U2265 0x6 shift altgr -- --## keycode 7 = +at +six asciicircum --at 0x7 --six 0x7 shift --asciicircum 0x7 altgr -- --## keycode 8 = +plus +seven U+00b1 U+00ac --plus 0x8 --seven 0x8 shift --U00b1 0x8 altgr --U00ac 0x8 shift altgr -- --## keycode 9 = +minus +eight U+2212 U+00bc --minus 0x9 --eight 0x9 shift --U2212 0x9 altgr --U00bc 0x9 shift altgr -- --## keycode 10 = +slash +nine U+00f7 U+00bd --slash 0xa --nine 0xa shift --U00f7 0xa altgr --U00bd 0xa shift altgr -- --## keycode 11 = +asterisk +zero U+00d7 U+00be --asterisk 0xb --zero 0xb shift --U00d7 0xb altgr --U00be 0xb shift altgr -- --## keycode 12 = equal U+00b0 U+2260 U+2032 --equal 0xc --U00b0 0xc shift --U2260 0xc altgr --U2032 0xc shift altgr -- --## keycode 13 = percent grave U+2030 U+2033 --percent 0xd --grave 0xd shift --U2030 0xd altgr --U2033 0xd shift altgr -- -- --# Second row -- --# simplified letter definitions notation : --## keycode 16 = b --b 0x10 addupper --## keycode 18 = p --p 0x12 addupper --## keycode 19 = o --o 0x13 addupper --## keycode 22 = v --v 0x16 addupper --## keycode 23 = d --d 0x17 addupper --## keycode 24 = l --l 0x18 addupper --## keycode 25 = j --j 0x19 addupper --## keycode 26 = z --z 0x1a addupper --## keycode 27 = w --w 0x1b addupper -- --# then, add specific definitions --## AltGr keycode 16 = bar --bar 0x10 altgr --## Shift AltGr keycode 16 = brokenbar --brokenbar 0x10 shift altgr -- --## keycode 17 = +eacute +Eacute dead_acute --eacute 0x11 --Eacute 0x11 shift --dead_acute 0x11 altgr -- --## AltGr keycode 18 = ampersand --ampersand 0x12 altgr --## Shift AltGr keycode 18 = U+00a7 --U00a7 0x12 shift altgr -- --## AltGr keycode 19 = +U+0153 --U+0153 0x13 altgr --## Shift AltGr keycode 19 = +U+0152 --U+0152 0x13 shift altgr -- --## keycode 20 = +egrave +Egrave dead_grave grave # no Meta ! --egrave 0x14 --Egrave 0x14 shift --dead_grave 0x14 altgr -- --## keycode 21 = dead_circumflex exclam exclamdown --dead_circumflex 0x15 --exclam 0x15 shift --exclamdown 0x15 altgr -- --## AltGr keycode 22 = dead_caron --dead_caron 0x16 altgr -- --## AltGr keycode 23 = eth --eth 0x17 altgr --## Shift AltGr keycode 23 = ETH --ETH 0x17 shift altgr -- --## AltGr keycode 25 = +U+0133 --U+0133 0x19 altgr --## Shift AltGr keycode 25 = +U+0132 --U+0132 0x19 shift altgr -- --## AltGr keycode 26 = +U+0259 --U+0259 0x1a altgr --## Shift AltGr keycode 26 = +U+018f --U+018f 0x1a shift altgr -- -- -- --# Third row -- --# simplified letter definitions notation : --## keycode 30 = a --a 0x1e addupper --## keycode 31 = u --u 0x1f addupper --## keycode 32 = i --i 0x20 addupper --## keycode 33 = e --e 0x21 addupper --## keycode 35 = c --c 0x23 addupper --## keycode 36 = t --t 0x24 addupper --## keycode 37 = s --s 0x25 addupper --## keycode 38 = r --r 0x26 addupper --## keycode 39 = n --n 0x27 addupper --## keycode 40 = m --m 0x28 addupper -- --# then, add specific definitions --## AltGr keycode 30 = +ae --ae 0x1e altgr --## Shift AltGr keycode 30 = +AE --AE 0x1e shift altgr -- --## AltGr keycode 31 = +ugrave --ugrave 0x1f altgr --## Shift AltGr keycode 31 = +Ugrave --Ugrave 0x1f shift altgr -- --## AltGr keycode 32 = dead_diaeresis --dead_diaeresis 0x20 altgr -- -- --## AltGr keycode 33 = U+20ac --U20ac 0x21 altgr -- --## keycode 34 = comma semicolon U+2019 +U+031b --comma 0x22 --semicolon 0x22 shift --U2019 0x22 altgr --U+031b 0x22 shift altgr -- --## AltGr keycode 35 = copyright --copyright 0x23 altgr --## Shift AltGr keycode 35 = U+017f --U017f 0x23 shift altgr -- --## AltGr keycode 36 = +thorn --thorn 0x24 altgr --## Shift AltGr keycode 36 = +THORN --THORN 0x24 shift altgr -- --## AltGr keycode 37 = +ssharp --ssharp 0x25 altgr --## Shift AltGr keycode 37 = U+1e9e --U1e9e 0x25 shift altgr -- --## AltGr keycode 38 = registered --registered 0x26 altgr --## Shift AltGr keycode 38 = U+2122 --U2122 0x26 shift altgr -- --## AltGr keycode 39 = dead_tilde --dead_tilde 0x27 altgr -- --## Shift AltGr keycode 40 = masculine --masculine 0x28 shift altgr -- --## keycode 43 = +ccedilla +Ccedilla dead_cedilla --ccedilla 0x2b --Ccedilla 0x2b shift --dead_cedilla 0x2b altgr -- -- --# Fourth row -- --# simplified letter definitions notation : --## keycode 45 = y --y 0x2d addupper --## keycode 46 = x --x 0x2e addupper --## keycode 48 = k --k 0x30 addupper --## keycode 50 = q --q 0x32 addupper --## keycode 51 = g --g 0x33 addupper --## keycode 52 = h --h 0x34 addupper --## keycode 53 = f --f 0x35 addupper -- --# then, add specific definitions --## keycode 86 = +ecircumflex +Ecircumflex slash slash --ecircumflex 0x56 --Ecircumflex 0x56 shift -- --## keycode 44 = +agrave +Agrave backslash --agrave 0x2c --Agrave 0x2c shift --backslash 0x2c altgr -- --## AltGr keycode 45 = braceleft --braceleft 0x2d altgr --## Shift AltGr keycode 45 = U+2018 --U2018 0x2d shift altgr -- --## AltGr keycode 46 = braceright --braceright 0x2e altgr -- --## keycode 47 = period colon U+2026 periodcentered --period 0x2f --colon 0x2f shift --U2026 0x2f altgr --periodcentered 0x2f shift altgr -- --## AltGr keycode 48 = asciitilde --asciitilde 0x30 altgr --## Shift AltGr keycode 48 = U+2328 --U2328 0x30 shift altgr -- --## keycode 49 = apostrophe question questiondown +U+0309 --apostrophe 0x31 --question 0x31 shift --questiondown 0x31 altgr --U+0309 0x31 shift altgr -- --## AltGr keycode 51 = mu --mu 0x33 altgr -- --## AltGr keycode 52 = U+2020 --U2020 0x34 altgr --## Shift AltGr keycode 52 = U+2021 --U2021 0x34 shift altgr -- --## Shift AltGr keycode 53 = ordfeminine --ordfeminine 0x35 shift altgr -- -- -- --## keycode 57 = space nobreakspace underscore U+202f --space 0x39 --nobreakspace 0x39 shift --underscore 0x39 altgr --U202f 0x39 shift altgr -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/cz b/pc-bios/keymaps/cz -index 6584bfb..46b3775 100644 ---- a/pc-bios/keymaps/cz -+++ b/pc-bios/keymaps/cz -@@ -1,94 +1,837 @@ --include common -+# -+# generated by qemu-keymap -+# model : pc105 -+# layout : cz -+# variant : - -+# options : - - --# Czech qwertz layout --# comments are czech descriptions of the characters -+# name: "Czech" - --# ----------- --# First row --# ----------- -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper - --# strednik, kolecko --semicolon 0x29 --dead_abovering 0x29 shift -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+plus 0x02 -+1 0x02 shift -+exclam 0x02 altgr -+dead_tilde 0x02 shift altgr -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+ecaron 0x03 -+2 0x03 shift -+at 0x03 altgr -+dead_caron 0x03 shift altgr -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+scaron 0x04 -+3 0x04 shift -+numbersign 0x04 altgr -+dead_circumflex 0x04 shift altgr -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+ccaron 0x05 -+4 0x05 shift -+dollar 0x05 altgr -+dead_breve 0x05 shift altgr -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+rcaron 0x06 -+5 0x06 shift -+percent 0x06 altgr -+dead_abovering 0x06 shift altgr -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+zcaron 0x07 -+6 0x07 shift -+asciicircum 0x07 altgr -+dead_ogonek 0x07 shift altgr - --# numbers --plus 0x2 --1 0x2 shift --ecaron 0x3 --2 0x3 shift --scaron 0x4 --3 0x4 shift --ccaron 0x5 --4 0x5 shift --rcaron 0x6 --5 0x6 shift --zcaron 0x7 --6 0x7 shift --yacute 0x8 --7 0x8 shift --aacute 0x9 --8 0x9 shift --iacute 0xa --9 0xa shift --eacute 0xb --0 0xb shift -- --# rovnitko -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+yacute 0x08 -+7 0x08 shift -+ampersand 0x08 altgr -+dead_grave 0x08 shift altgr -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+aacute 0x09 -+8 0x09 shift -+asterisk 0x09 altgr -+dead_abovedot 0x09 shift altgr -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+iacute 0x0a -+9 0x0a shift -+braceleft 0x0a altgr -+dead_acute 0x0a shift altgr -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+eacute 0x0b -+0 0x0b shift -+braceright 0x0b altgr -+dead_doubleacute 0x0b shift altgr -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc - equal 0x0c - percent 0x0c shift -+backslash 0x0c altgr -+dead_diaeresis 0x0c shift altgr - --# carka, hacek -+# evdev 13 (0xd), QKeyCode "equal", number 0xd - dead_acute 0x0d - dead_caron 0x0d shift -+dead_macron 0x0d altgr -+dead_cedilla 0x0d shift altgr -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+q 0x10 -+Q 0x10 shift -+backslash 0x10 altgr -+Greek_OMEGA 0x10 shift altgr - --# ------------ --# Second row --# ------------ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+w 0x11 -+W 0x11 shift -+bar 0x11 altgr -+Lstroke 0x11 shift altgr - --z 0x15 addupper -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+e 0x12 -+E 0x12 shift -+EuroSign 0x12 altgr - --# u s carkou, zpetne lomitko -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+r 0x13 -+R 0x13 shift -+paragraph 0x13 altgr -+registered 0x13 shift altgr -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+t 0x14 -+T 0x14 shift -+tslash 0x14 altgr -+Tslash 0x14 shift altgr -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+z 0x15 -+Z 0x15 shift -+leftarrow 0x15 altgr -+yen 0x15 shift altgr -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+u 0x16 -+U 0x16 shift -+downarrow 0x16 altgr -+uparrow 0x16 shift altgr -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+i 0x17 -+I 0x17 shift -+rightarrow 0x17 altgr -+idotless 0x17 shift altgr -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+o 0x18 -+O 0x18 shift -+oslash 0x18 altgr -+Oslash 0x18 shift altgr -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+p 0x19 -+P 0x19 shift -+thorn 0x19 altgr -+THORN 0x19 shift altgr -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a - uacute 0x1a - slash 0x1a shift -+bracketleft 0x1a altgr -+division 0x1a shift altgr - --# prava zavorka, leva zavorka -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b - parenright 0x1b - parenleft 0x1b shift -+bracketright 0x1b altgr -+multiply 0x1b shift altgr -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+a 0x1e -+A 0x1e shift -+asciitilde 0x1e altgr -+AE 0x1e shift altgr -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+s 0x1f -+S 0x1f shift -+dstroke 0x1f altgr -+section 0x1f shift altgr -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+d 0x20 -+D 0x20 shift -+Dstroke 0x20 altgr -+ETH 0x20 shift altgr -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+f 0x21 -+F 0x21 shift -+bracketleft 0x21 altgr -+ordfeminine 0x21 shift altgr -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+g 0x22 -+G 0x22 shift -+bracketright 0x22 altgr -+ENG 0x22 shift altgr -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+h 0x23 -+H 0x23 shift -+grave 0x23 altgr -+Hstroke 0x23 shift altgr - --# ----------- --# Third row --# ----------- -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+j 0x24 -+J 0x24 shift -+apostrophe 0x24 altgr -+dead_horn 0x24 shift altgr - --# u s krouzkem, uvozovky -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+k 0x25 -+K 0x25 shift -+lstroke 0x25 altgr -+ampersand 0x25 shift altgr -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+l 0x26 -+L 0x26 shift -+Lstroke 0x26 altgr -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 - uring 0x27 - quotedbl 0x27 shift -+dollar 0x27 altgr -+dead_doubleacute 0x27 shift altgr - --# paragraf, vykricnik -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 - section 0x28 - exclam 0x28 shift -+apostrophe 0x28 altgr -+ssharp 0x28 shift altgr -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 -+semicolon 0x29 -+dead_abovering 0x29 shift -+grave 0x29 altgr -+asciitilde 0x29 shift altgr -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a - --# vodorovna dvojtecka, apostrof -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b - dead_diaeresis 0x2b - apostrophe 0x2b shift -+backslash 0x2b altgr -+bar 0x2b shift altgr -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+y 0x2c -+Y 0x2c shift -+degree 0x2c altgr -+less 0x2c shift altgr -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+x 0x2d -+X 0x2d shift -+numbersign 0x2d altgr -+greater 0x2d shift altgr - --# ------------ --# Fourth row --# ------------ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+c 0x2e -+C 0x2e shift -+ampersand 0x2e altgr -+copyright 0x2e shift altgr - --# zpetne lomitko, roura --backslash 0x2b --bar 0x2b shift -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+v 0x2f -+V 0x2f shift -+at 0x2f altgr -+leftsinglequotemark 0x2f shift altgr - --y 0x2c addupper -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+b 0x30 -+B 0x30 shift -+braceleft 0x30 altgr -+rightsinglequotemark 0x30 shift altgr - --# carka, otaznik -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+n 0x31 -+N 0x31 shift -+braceright 0x31 altgr -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+m 0x32 -+M 0x32 shift -+asciicircum 0x32 altgr -+masculine 0x32 shift altgr -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 - comma 0x33 - question 0x33 shift -+less 0x33 altgr -+multiply 0x33 shift altgr - --# tecka, dvojtecka -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 - period 0x34 - colon 0x34 shift -+greater 0x34 altgr -+division 0x34 shift altgr - --# minus, podtrzitko -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 - minus 0x35 - underscore 0x35 shift -+asterisk 0x35 altgr -+dead_abovedot 0x35 shift altgr -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Decimal 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 -+backslash 0x56 -+bar 0x56 shift -+slash 0x56 altgr -+brokenbar 0x56 shift altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+ISO_Level3_Shift 0xb8 -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/da b/pc-bios/keymaps/da -index 3884dcf..f7cdad7 100644 ---- a/pc-bios/keymaps/da -+++ b/pc-bios/keymaps/da -@@ -1,120 +1,836 @@ --# generated from XKB map dk --include common --map 0x406 -+# -+# generated by qemu-keymap -+# model : pc105 -+# layout : dk -+# variant : - -+# options : - -+ -+# name: "Danish" -+ -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+1 0x02 - exclam 0x02 shift - exclamdown 0x02 altgr - onesuperior 0x02 shift altgr -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+2 0x03 - quotedbl 0x03 shift - at 0x03 altgr - twosuperior 0x03 shift altgr -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+3 0x04 - numbersign 0x04 shift - sterling 0x04 altgr - threesuperior 0x04 shift altgr -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+4 0x05 - currency 0x05 shift - dollar 0x05 altgr - onequarter 0x05 shift altgr -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+5 0x06 - percent 0x06 shift - onehalf 0x06 altgr - cent 0x06 shift altgr -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+6 0x07 - ampersand 0x07 shift - yen 0x07 altgr - fiveeighths 0x07 shift altgr -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+7 0x08 - slash 0x08 shift - braceleft 0x08 altgr - division 0x08 shift altgr -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+8 0x09 - parenleft 0x09 shift - bracketleft 0x09 altgr - guillemotleft 0x09 shift altgr -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+9 0x0a - parenright 0x0a shift - bracketright 0x0a altgr - guillemotright 0x0a shift altgr -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+0 0x0b - equal 0x0b shift - braceright 0x0b altgr - degree 0x0b shift altgr -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc - plus 0x0c - question 0x0c shift - plusminus 0x0c altgr - questiondown 0x0c shift altgr -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd - dead_acute 0x0d - dead_grave 0x0d shift - bar 0x0d altgr - brokenbar 0x0d shift altgr -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+q 0x10 -+Q 0x10 shift -+at 0x10 altgr - Greek_OMEGA 0x10 shift altgr -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+w 0x11 -+W 0x11 shift - lstroke 0x11 altgr - Lstroke 0x11 shift altgr -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+e 0x12 -+E 0x12 shift - EuroSign 0x12 altgr - cent 0x12 shift altgr -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+r 0x13 -+R 0x13 shift - registered 0x13 altgr -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+t 0x14 -+T 0x14 shift - thorn 0x14 altgr - THORN 0x14 shift altgr -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+y 0x15 -+Y 0x15 shift - leftarrow 0x15 altgr - yen 0x15 shift altgr -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+u 0x16 -+U 0x16 shift - downarrow 0x16 altgr - uparrow 0x16 shift altgr -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+i 0x17 -+I 0x17 shift - rightarrow 0x17 altgr - idotless 0x17 shift altgr -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+o 0x18 -+O 0x18 shift - oe 0x18 altgr - OE 0x18 shift altgr -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+p 0x19 -+P 0x19 shift - thorn 0x19 altgr - THORN 0x19 shift altgr -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a - aring 0x1a - Aring 0x1a shift - dead_diaeresis 0x1a altgr - dead_abovering 0x1a shift altgr -+ -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b - dead_diaeresis 0x1b - dead_circumflex 0x1b shift - dead_tilde 0x1b altgr - dead_caron 0x1b shift altgr -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+a 0x1e -+A 0x1e shift - ordfeminine 0x1e altgr - masculine 0x1e shift altgr -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+s 0x1f -+S 0x1f shift - ssharp 0x1f altgr - section 0x1f shift altgr -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+d 0x20 -+D 0x20 shift - eth 0x20 altgr - ETH 0x20 shift altgr -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+f 0x21 -+F 0x21 shift - dstroke 0x21 altgr - ordfeminine 0x21 shift altgr -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+g 0x22 -+G 0x22 shift - eng 0x22 altgr - ENG 0x22 shift altgr -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+h 0x23 -+H 0x23 shift - hstroke 0x23 altgr - Hstroke 0x23 shift altgr -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+j 0x24 -+J 0x24 shift -+dead_hook 0x24 altgr -+dead_horn 0x24 shift altgr -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+k 0x25 -+K 0x25 shift - kra 0x25 altgr -+ampersand 0x25 shift altgr -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+l 0x26 -+L 0x26 shift - lstroke 0x26 altgr - Lstroke 0x26 shift altgr -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 - ae 0x27 - AE 0x27 shift -+dead_acute 0x27 altgr -+dead_doubleacute 0x27 shift altgr -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 - oslash 0x28 --Ooblique 0x28 shift -+Oslash 0x28 shift -+dead_circumflex 0x28 altgr - dead_caron 0x28 shift altgr -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 - onehalf 0x29 - section 0x29 shift - threequarters 0x29 altgr - paragraph 0x29 shift altgr -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b - apostrophe 0x2b - asterisk 0x2b shift - dead_doubleacute 0x2b altgr - multiply 0x2b shift altgr -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+z 0x2c -+Z 0x2c shift - guillemotleft 0x2c altgr -+less 0x2c shift altgr -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+x 0x2d -+X 0x2d shift - guillemotright 0x2d altgr -+greater 0x2d shift altgr -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+c 0x2e -+C 0x2e shift - copyright 0x2e altgr -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+v 0x2f -+V 0x2f shift - leftdoublequotemark 0x2f altgr --grave 0x2f shift altgr -+leftsinglequotemark 0x2f shift altgr -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+b 0x30 -+B 0x30 shift - rightdoublequotemark 0x30 altgr -+rightsinglequotemark 0x30 shift altgr -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+n 0x31 -+N 0x31 shift -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+m 0x32 -+M 0x32 shift - mu 0x32 altgr - masculine 0x32 shift altgr -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 - comma 0x33 - semicolon 0x33 shift - dead_cedilla 0x33 altgr - dead_ogonek 0x33 shift altgr -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 - period 0x34 - colon 0x34 shift - periodcentered 0x34 altgr - dead_abovedot 0x34 shift altgr -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 - minus 0x35 - underscore 0x35 shift --hyphen 0x35 altgr --macron 0x35 shift altgr --nobreakspace 0x39 altgr -+dead_belowdot 0x35 altgr -+dead_abovedot 0x35 shift altgr -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Separator 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 - less 0x56 - greater 0x56 shift - backslash 0x56 altgr - notsign 0x56 shift altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+ISO_Level3_Shift 0xb8 -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/de b/pc-bios/keymaps/de -index ed929c7..d0b4715 100644 ---- a/pc-bios/keymaps/de -+++ b/pc-bios/keymaps/de -@@ -1,114 +1,839 @@ --# generated from XKB map de --include common --map 0x407 -+# -+# generated by qemu-keymap -+# model : pc105 -+# layout : de -+# variant : - -+# options : - -+ -+# name: "German" -+ -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+1 0x02 - exclam 0x02 shift - onesuperior 0x02 altgr - exclamdown 0x02 shift altgr -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+2 0x03 - quotedbl 0x03 shift - twosuperior 0x03 altgr - oneeighth 0x03 shift altgr -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+3 0x04 - section 0x04 shift - threesuperior 0x04 altgr - sterling 0x04 shift altgr -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+4 0x05 - dollar 0x05 shift - onequarter 0x05 altgr - currency 0x05 shift altgr -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+5 0x06 - percent 0x06 shift - onehalf 0x06 altgr - threeeighths 0x06 shift altgr -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+6 0x07 - ampersand 0x07 shift --threequarters 0x07 altgr -+notsign 0x07 altgr - fiveeighths 0x07 shift altgr -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+7 0x08 - slash 0x08 shift - braceleft 0x08 altgr - seveneighths 0x08 shift altgr -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+8 0x09 - parenleft 0x09 shift - bracketleft 0x09 altgr - trademark 0x09 shift altgr -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+9 0x0a - parenright 0x0a shift - bracketright 0x0a altgr - plusminus 0x0a shift altgr -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+0 0x0b - equal 0x0b shift - braceright 0x0b altgr -+degree 0x0b shift altgr -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc - ssharp 0x0c - question 0x0c shift - backslash 0x0c altgr - questiondown 0x0c shift altgr --acute 0x0d -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd - dead_acute 0x0d --grave 0x0d shift - dead_grave 0x0d shift - dead_cedilla 0x0d altgr - dead_ogonek 0x0d shift altgr -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+q 0x10 -+Q 0x10 shift - at 0x10 altgr - Greek_OMEGA 0x10 shift altgr -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+w 0x11 -+W 0x11 shift -+lstroke 0x11 altgr -+Lstroke 0x11 shift altgr -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+e 0x12 -+E 0x12 shift - EuroSign 0x12 altgr -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+r 0x13 -+R 0x13 shift - paragraph 0x13 altgr - registered 0x13 shift altgr -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+t 0x14 -+T 0x14 shift - tslash 0x14 altgr - Tslash 0x14 shift altgr --z 0x15 addupper -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+z 0x15 -+Z 0x15 shift - leftarrow 0x15 altgr - yen 0x15 shift altgr -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+u 0x16 -+U 0x16 shift - downarrow 0x16 altgr - uparrow 0x16 shift altgr -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+i 0x17 -+I 0x17 shift - rightarrow 0x17 altgr - idotless 0x17 shift altgr -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+o 0x18 -+O 0x18 shift - oslash 0x18 altgr --Ooblique 0x18 shift altgr -+Oslash 0x18 shift altgr -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+p 0x19 -+P 0x19 shift - thorn 0x19 altgr - THORN 0x19 shift altgr -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a - udiaeresis 0x1a - Udiaeresis 0x1a shift - dead_diaeresis 0x1a altgr - dead_abovering 0x1a shift altgr -+ -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b - plus 0x1b - asterisk 0x1b shift - asciitilde 0x1b altgr --dead_tilde 0x1b altgr --dead_macron 0x1b shift altgr -+macron 0x1b shift altgr -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+a 0x1e -+A 0x1e shift - ae 0x1e altgr - AE 0x1e shift altgr -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+s 0x1f -+S 0x1f shift -+U017F 0x1f altgr -+U1E9E 0x1f shift altgr -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+d 0x20 -+D 0x20 shift - eth 0x20 altgr - ETH 0x20 shift altgr -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+f 0x21 -+F 0x21 shift - dstroke 0x21 altgr - ordfeminine 0x21 shift altgr -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+g 0x22 -+G 0x22 shift - eng 0x22 altgr - ENG 0x22 shift altgr -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+h 0x23 -+H 0x23 shift - hstroke 0x23 altgr - Hstroke 0x23 shift altgr -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+j 0x24 -+J 0x24 shift -+dead_belowdot 0x24 altgr -+dead_abovedot 0x24 shift altgr -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+k 0x25 -+K 0x25 shift - kra 0x25 altgr -+ampersand 0x25 shift altgr -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+l 0x26 -+L 0x26 shift -+lstroke 0x26 altgr -+Lstroke 0x26 shift altgr -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 - odiaeresis 0x27 - Odiaeresis 0x27 shift - dead_doubleacute 0x27 altgr -+dead_belowdot 0x27 shift altgr -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 - adiaeresis 0x28 - Adiaeresis 0x28 shift -+dead_circumflex 0x28 altgr - dead_caron 0x28 shift altgr --asciicircum 0x29 -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 - dead_circumflex 0x29 - degree 0x29 shift --notsign 0x29 altgr -+U2032 0x29 altgr -+U2033 0x29 shift altgr -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b - numbersign 0x2b - apostrophe 0x2b shift -+rightsinglequotemark 0x2b altgr - dead_breve 0x2b shift altgr --y 0x2c addupper --guillemotleft 0x2c altgr --guillemotright 0x2d altgr -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+y 0x2c -+Y 0x2c shift -+guillemotright 0x2c altgr -+U203A 0x2c shift altgr -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+x 0x2d -+X 0x2d shift -+guillemotleft 0x2d altgr -+U2039 0x2d shift altgr -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+c 0x2e -+C 0x2e shift - cent 0x2e altgr - copyright 0x2e shift altgr --leftdoublequotemark 0x2f altgr --rightdoublequotemark 0x30 altgr -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+v 0x2f -+V 0x2f shift -+doublelowquotemark 0x2f altgr -+singlelowquotemark 0x2f shift altgr -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+b 0x30 -+B 0x30 shift -+leftdoublequotemark 0x30 altgr -+leftsinglequotemark 0x30 shift altgr -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+n 0x31 -+N 0x31 shift -+rightdoublequotemark 0x31 altgr -+rightsinglequotemark 0x31 shift altgr -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+m 0x32 -+M 0x32 shift - mu 0x32 altgr - masculine 0x32 shift altgr -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 - comma 0x33 - semicolon 0x33 shift --horizconnector 0x33 altgr -+periodcentered 0x33 altgr - multiply 0x33 shift altgr -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 - period 0x34 - colon 0x34 shift --periodcentered 0x34 altgr -+U2026 0x34 altgr - division 0x34 shift altgr -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 - minus 0x35 - underscore 0x35 shift --dead_belowdot 0x35 altgr --dead_abovedot 0x35 shift altgr -+endash 0x35 altgr -+emdash 0x35 shift altgr -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Separator 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 -+less 0x56 -+greater 0x56 shift -+bar 0x56 altgr -+brokenbar 0x56 shift altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+ISO_Level3_Shift 0xb8 -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/de-ch b/pc-bios/keymaps/de-ch -index 852f8b8..ad37f6c 100644 ---- a/pc-bios/keymaps/de-ch -+++ b/pc-bios/keymaps/de-ch -@@ -1,169 +1,836 @@ --# rdesktop Swiss-German (de-ch) keymap file --# 2003-06-03 by noldi@tristar.ch - # --include common --map 0x00000807 --# --# Scan Code 1 --section 0x29 --degree 0x29 shift --notsign 0x29 altgr inhibit --# --# Scan Code 2 --plus 0x2 shift --brokenbar 0x02 altgr --# --# Scan Code 3 -+# generated by qemu-keymap -+# model : pc105 -+# layout : ch -+# variant : - -+# options : - -+ -+# name: "German (Switzerland)" -+ -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+1 0x02 -+plus 0x02 shift -+bar 0x02 altgr -+exclamdown 0x02 shift altgr -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+2 0x03 - quotedbl 0x03 shift - at 0x03 altgr --# --# Scan Code 4 -+oneeighth 0x03 shift altgr -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+3 0x04 - asterisk 0x04 shift - numbersign 0x04 altgr --# --# Scan Code 5 -+sterling 0x04 shift altgr -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+4 0x05 - ccedilla 0x05 shift --onequarter 0x05 altgr inhibit --# --# Scan Code 6 -+onequarter 0x05 altgr -+dollar 0x05 shift altgr -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+5 0x06 - percent 0x06 shift --onehalf 0x06 altgr inhibit --# --# Scan Code 7 -+onehalf 0x06 altgr -+threeeighths 0x06 shift altgr -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+6 0x07 - ampersand 0x07 shift - notsign 0x07 altgr --# --# Scan Code 8 -+fiveeighths 0x07 shift altgr -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+7 0x08 - slash 0x08 shift - bar 0x08 altgr --# --# Scan Code 9 -+seveneighths 0x08 shift altgr -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+8 0x09 - parenleft 0x09 shift - cent 0x09 altgr --# --# Scan Code 10 -+trademark 0x09 shift altgr -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+9 0x0a - parenright 0x0a shift --# --# Scan Code 11 -+bracketright 0x0a altgr -+plusminus 0x0a shift altgr -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+0 0x0b - equal 0x0b shift --braceright 0x0b altgr inhibit --# --# Scan Code 12 -+braceright 0x0b altgr -+degree 0x0b shift altgr -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc - apostrophe 0x0c - question 0x0c shift - dead_acute 0x0c altgr --# --# Scan Code 13 -+questiondown 0x0c shift altgr -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd - dead_circumflex 0x0d - dead_grave 0x0d shift - dead_tilde 0x0d altgr --# --# Scan Code 19 -+dead_ogonek 0x0d shift altgr -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+q 0x10 -+Q 0x10 shift -+at 0x10 altgr -+Greek_OMEGA 0x10 shift altgr -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+w 0x11 -+W 0x11 shift -+lstroke 0x11 altgr -+Lstroke 0x11 shift altgr -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+e 0x12 -+E 0x12 shift - EuroSign 0x12 altgr --# --# Scan Code 22 --z 0x15 addupper --# --# Scan Code 27 -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+r 0x13 -+R 0x13 shift -+paragraph 0x13 altgr -+registered 0x13 shift altgr -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+t 0x14 -+T 0x14 shift -+tslash 0x14 altgr -+Tslash 0x14 shift altgr -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+z 0x15 -+Z 0x15 shift -+leftarrow 0x15 altgr -+yen 0x15 shift altgr -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+u 0x16 -+U 0x16 shift -+downarrow 0x16 altgr -+uparrow 0x16 shift altgr -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+i 0x17 -+I 0x17 shift -+rightarrow 0x17 altgr -+idotless 0x17 shift altgr -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+o 0x18 -+O 0x18 shift -+oe 0x18 altgr -+OE 0x18 shift altgr -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+p 0x19 -+P 0x19 shift -+thorn 0x19 altgr -+THORN 0x19 shift altgr -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a - udiaeresis 0x1a - egrave 0x1a shift - bracketleft 0x1a altgr --# --# Scan Code 28 -+dead_abovering 0x1a shift altgr -+ -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b - dead_diaeresis 0x1b - exclam 0x1b shift - bracketright 0x1b altgr --# --# Scan Code 40 -+dead_macron 0x1b shift altgr -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+a 0x1e -+A 0x1e shift -+ae 0x1e altgr -+AE 0x1e shift altgr -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+s 0x1f -+S 0x1f shift -+ssharp 0x1f altgr -+section 0x1f shift altgr -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+d 0x20 -+D 0x20 shift -+eth 0x20 altgr -+ETH 0x20 shift altgr -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+f 0x21 -+F 0x21 shift -+dstroke 0x21 altgr -+ordfeminine 0x21 shift altgr -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+g 0x22 -+G 0x22 shift -+eng 0x22 altgr -+ENG 0x22 shift altgr -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+h 0x23 -+H 0x23 shift -+hstroke 0x23 altgr -+Hstroke 0x23 shift altgr -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+j 0x24 -+J 0x24 shift -+dead_hook 0x24 altgr -+dead_horn 0x24 shift altgr -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+k 0x25 -+K 0x25 shift -+kra 0x25 altgr -+ampersand 0x25 shift altgr -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+l 0x26 -+L 0x26 shift -+lstroke 0x26 altgr -+Lstroke 0x26 shift altgr -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 - odiaeresis 0x27 - eacute 0x27 shift --# --# Scan Code 41 -+dead_acute 0x27 altgr -+dead_doubleacute 0x27 shift altgr -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 - adiaeresis 0x28 - agrave 0x28 shift - braceleft 0x28 altgr --# --# Scan Code 42 (only on international keyboards) -+dead_caron 0x28 shift altgr -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 -+section 0x29 -+degree 0x29 shift -+notsign 0x29 altgr -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b - dollar 0x2b - sterling 0x2b shift - braceright 0x2b altgr --# --# Scan Code 45 (only on international keyboards) --backslash 0x56 altgr --# --# Scan Code 46 --y 0x2c addupper --# --# Scan Code 53 -+dead_breve 0x2b shift altgr -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+y 0x2c -+Y 0x2c shift -+guillemotleft 0x2c altgr -+less 0x2c shift altgr -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+x 0x2d -+X 0x2d shift -+guillemotright 0x2d altgr -+greater 0x2d shift altgr -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+c 0x2e -+C 0x2e shift -+cent 0x2e altgr -+copyright 0x2e shift altgr -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+v 0x2f -+V 0x2f shift -+leftdoublequotemark 0x2f altgr -+leftsinglequotemark 0x2f shift altgr -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+b 0x30 -+B 0x30 shift -+rightdoublequotemark 0x30 altgr -+rightsinglequotemark 0x30 shift altgr -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+n 0x31 -+N 0x31 shift -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+m 0x32 -+M 0x32 shift -+mu 0x32 altgr -+masculine 0x32 shift altgr -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 - comma 0x33 - semicolon 0x33 shift --# --# Scan Code 54 -+horizconnector 0x33 altgr -+multiply 0x33 shift altgr -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 - period 0x34 - colon 0x34 shift --# --# Scan Code 55 -+periodcentered 0x34 altgr -+division 0x34 shift altgr -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 - minus 0x35 - underscore 0x35 shift --# --# Suppress Windows unsupported AltGr keys --# --# Scan Code 17 --paragraph 0x10 altgr inhibit --# --# Scan Code 21 --tslash 0x14 altgr inhibit --# --# Scan Code 22 --leftarrow 0x15 altgr inhibit --# --# Scan Code 23 --downarrow 0x16 altgr inhibit --# --# Scan Code 24 --rightarrow 0x17 altgr inhibit --# --# Scan Code 25 --oslash 0x18 altgr inhibit --# --# Scan Code 26 --thorn 0x19 altgr inhibit --# --# Scan Code 31 --ae 0x1e altgr inhibit --# --# Scan Code 32 --ssharp 0x1f altgr inhibit --# --# Scan Code 33 --eth 0x20 altgr inhibit --# --# Scan Code 34 --dstroke 0x21 altgr inhibit --# --# Scan Code 35 --eng 0x22 altgr inhibit --# --# Scan Code 36 --hstroke 0x23 altgr inhibit --# --# Scan Code 38 --kra 0x25 altgr inhibit --# --# Scan Code 39 --lstroke 0x26 altgr inhibit --# --# Scan Code 46 --guillemotleft 0x2c altgr inhibit --# --# Scan Code 47 --guillemotright 0x2d altgr inhibit --# --# Scan Code 49 --leftdoublequotemark 0x2f altgr inhibit --# --# Scan Code 50 --rightdoublequotemark 0x30 altgr inhibit --# --# Scan Code 52 --mu 0x32 altgr inhibit -+dead_belowdot 0x35 altgr -+dead_abovedot 0x35 shift altgr -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Decimal 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 -+less 0x56 -+greater 0x56 shift -+backslash 0x56 altgr -+brokenbar 0x56 shift altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+ISO_Level3_Shift 0xb8 -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/en-gb b/pc-bios/keymaps/en-gb -index b45f06c..999cca7 100644 ---- a/pc-bios/keymaps/en-gb -+++ b/pc-bios/keymaps/en-gb -@@ -1,119 +1,835 @@ --# generated from XKB map gb --include common --map 0x809 -+# -+# generated by qemu-keymap -+# model : pc105 -+# layout : gb -+# variant : - -+# options : - -+ -+# name: "English (UK)" -+ -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+1 0x02 - exclam 0x02 shift - onesuperior 0x02 altgr - exclamdown 0x02 shift altgr -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+2 0x03 - quotedbl 0x03 shift - twosuperior 0x03 altgr - oneeighth 0x03 shift altgr -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+3 0x04 - sterling 0x04 shift - threesuperior 0x04 altgr -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+4 0x05 - dollar 0x05 shift - EuroSign 0x05 altgr -+onequarter 0x05 shift altgr -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+5 0x06 - percent 0x06 shift - onehalf 0x06 altgr - threeeighths 0x06 shift altgr -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+6 0x07 - asciicircum 0x07 shift - threequarters 0x07 altgr - fiveeighths 0x07 shift altgr -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+7 0x08 - ampersand 0x08 shift - braceleft 0x08 altgr - seveneighths 0x08 shift altgr -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+8 0x09 - asterisk 0x09 shift - bracketleft 0x09 altgr - trademark 0x09 shift altgr -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+9 0x0a - parenleft 0x0a shift - bracketright 0x0a altgr - plusminus 0x0a shift altgr -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+0 0x0b - parenright 0x0b shift - braceright 0x0b altgr - degree 0x0b shift altgr -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc - minus 0x0c - underscore 0x0c shift - backslash 0x0c altgr - questiondown 0x0c shift altgr -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd - equal 0x0d - plus 0x0d shift - dead_cedilla 0x0d altgr - dead_ogonek 0x0d shift altgr -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+q 0x10 -+Q 0x10 shift - at 0x10 altgr - Greek_OMEGA 0x10 shift altgr -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+w 0x11 -+W 0x11 shift - lstroke 0x11 altgr - Lstroke 0x11 shift altgr -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+e 0x12 -+E 0x12 shift -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+r 0x13 -+R 0x13 shift - paragraph 0x13 altgr - registered 0x13 shift altgr -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+t 0x14 -+T 0x14 shift - tslash 0x14 altgr - Tslash 0x14 shift altgr -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+y 0x15 -+Y 0x15 shift - leftarrow 0x15 altgr - yen 0x15 shift altgr -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+u 0x16 -+U 0x16 shift - downarrow 0x16 altgr - uparrow 0x16 shift altgr -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+i 0x17 -+I 0x17 shift - rightarrow 0x17 altgr - idotless 0x17 shift altgr -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+o 0x18 -+O 0x18 shift - oslash 0x18 altgr --Ooblique 0x18 shift altgr -+Oslash 0x18 shift altgr -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+p 0x19 -+P 0x19 shift - thorn 0x19 altgr - THORN 0x19 shift altgr -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a - bracketleft 0x1a - braceleft 0x1a shift - dead_diaeresis 0x1a altgr - dead_abovering 0x1a shift altgr -+ -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b - bracketright 0x1b - braceright 0x1b shift - dead_tilde 0x1b altgr - dead_macron 0x1b shift altgr -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+a 0x1e -+A 0x1e shift - ae 0x1e altgr - AE 0x1e shift altgr -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+s 0x1f -+S 0x1f shift - ssharp 0x1f altgr - section 0x1f shift altgr -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+d 0x20 -+D 0x20 shift - eth 0x20 altgr - ETH 0x20 shift altgr -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+f 0x21 -+F 0x21 shift - dstroke 0x21 altgr - ordfeminine 0x21 shift altgr -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+g 0x22 -+G 0x22 shift - eng 0x22 altgr - ENG 0x22 shift altgr -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+h 0x23 -+H 0x23 shift - hstroke 0x23 altgr - Hstroke 0x23 shift altgr -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+j 0x24 -+J 0x24 shift -+dead_hook 0x24 altgr -+dead_horn 0x24 shift altgr -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+k 0x25 -+K 0x25 shift - kra 0x25 altgr -+ampersand 0x25 shift altgr -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+l 0x26 -+L 0x26 shift - lstroke 0x26 altgr - Lstroke 0x26 shift altgr -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 - semicolon 0x27 - colon 0x27 shift - dead_acute 0x27 altgr - dead_doubleacute 0x27 shift altgr -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 - apostrophe 0x28 - at 0x28 shift - dead_circumflex 0x28 altgr - dead_caron 0x28 shift altgr -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 - grave 0x29 - notsign 0x29 shift - bar 0x29 altgr -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b - numbersign 0x2b - asciitilde 0x2b shift - dead_grave 0x2b altgr - dead_breve 0x2b shift altgr -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+z 0x2c -+Z 0x2c shift - guillemotleft 0x2c altgr - less 0x2c shift altgr -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+x 0x2d -+X 0x2d shift - guillemotright 0x2d altgr - greater 0x2d shift altgr -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+c 0x2e -+C 0x2e shift - cent 0x2e altgr - copyright 0x2e shift altgr -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+v 0x2f -+V 0x2f shift - leftdoublequotemark 0x2f altgr -+leftsinglequotemark 0x2f shift altgr -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+b 0x30 -+B 0x30 shift - rightdoublequotemark 0x30 altgr -+rightsinglequotemark 0x30 shift altgr -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+n 0x31 -+N 0x31 shift -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+m 0x32 -+M 0x32 shift - mu 0x32 altgr - masculine 0x32 shift altgr -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 - comma 0x33 - less 0x33 shift - horizconnector 0x33 altgr - multiply 0x33 shift altgr -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 - period 0x34 - greater 0x34 shift - periodcentered 0x34 altgr - division 0x34 shift altgr -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 - slash 0x35 - question 0x35 shift - dead_belowdot 0x35 altgr - dead_abovedot 0x35 shift altgr -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Decimal 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 - backslash 0x56 - bar 0x56 shift -+bar 0x56 altgr -+brokenbar 0x56 shift altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+ISO_Level3_Shift 0xb8 -+Multi_key 0xb8 shift -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/en-us b/pc-bios/keymaps/en-us -index f5784bb..a70e03a 100644 ---- a/pc-bios/keymaps/en-us -+++ b/pc-bios/keymaps/en-us -@@ -1,35 +1,747 @@ --# generated from XKB map us --include common --map 0x409 -+# -+# generated by qemu-keymap -+# model : pc105 -+# layout : us -+# variant : - -+# options : - -+ -+# name: "English (US)" -+ -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+1 0x02 - exclam 0x02 shift -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+2 0x03 - at 0x03 shift -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+3 0x04 - numbersign 0x04 shift -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+4 0x05 - dollar 0x05 shift -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+5 0x06 - percent 0x06 shift -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+6 0x07 - asciicircum 0x07 shift -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+7 0x08 - ampersand 0x08 shift -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+8 0x09 - asterisk 0x09 shift -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+9 0x0a - parenleft 0x0a shift -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+0 0x0b - parenright 0x0b shift -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc - minus 0x0c - underscore 0x0c shift -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd - equal 0x0d - plus 0x0d shift -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+q 0x10 -+Q 0x10 shift -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+w 0x11 -+W 0x11 shift -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+e 0x12 -+E 0x12 shift -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+r 0x13 -+R 0x13 shift -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+t 0x14 -+T 0x14 shift -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+y 0x15 -+Y 0x15 shift -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+u 0x16 -+U 0x16 shift -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+i 0x17 -+I 0x17 shift -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+o 0x18 -+O 0x18 shift -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+p 0x19 -+P 0x19 shift -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a - bracketleft 0x1a - braceleft 0x1a shift -+ -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b - bracketright 0x1b - braceright 0x1b shift -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+a 0x1e -+A 0x1e shift -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+s 0x1f -+S 0x1f shift -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+d 0x20 -+D 0x20 shift -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+f 0x21 -+F 0x21 shift -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+g 0x22 -+G 0x22 shift -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+h 0x23 -+H 0x23 shift -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+j 0x24 -+J 0x24 shift -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+k 0x25 -+K 0x25 shift -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+l 0x26 -+L 0x26 shift -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 - semicolon 0x27 - colon 0x27 shift -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 - apostrophe 0x28 - quotedbl 0x28 shift -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 - grave 0x29 - asciitilde 0x29 shift -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b - backslash 0x2b - bar 0x2b shift -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+z 0x2c -+Z 0x2c shift -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+x 0x2d -+X 0x2d shift -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+c 0x2e -+C 0x2e shift -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+v 0x2f -+V 0x2f shift -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+b 0x30 -+B 0x30 shift -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+n 0x31 -+N 0x31 shift -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+m 0x32 -+M 0x32 shift -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 - comma 0x33 - less 0x33 shift -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 - period 0x34 - greater 0x34 shift -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 - slash 0x35 - question 0x35 shift -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Decimal 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 -+less 0x56 -+greater 0x56 shift -+bar 0x56 altgr -+brokenbar 0x56 shift altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+Alt_R 0xb8 -+Meta_R 0xb8 shift -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/es b/pc-bios/keymaps/es -index 0c29eec..53e66e8 100644 ---- a/pc-bios/keymaps/es -+++ b/pc-bios/keymaps/es -@@ -1,105 +1,835 @@ --# generated from XKB map es --include common --map 0x40a -+# -+# generated by qemu-keymap -+# model : pc105 -+# layout : es -+# variant : - -+# options : - -+ -+# name: "Spanish" -+ -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+1 0x02 - exclam 0x02 shift - bar 0x02 altgr -+exclamdown 0x02 shift altgr -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+2 0x03 - quotedbl 0x03 shift - at 0x03 altgr - oneeighth 0x03 shift altgr -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+3 0x04 - periodcentered 0x04 shift - numbersign 0x04 altgr - sterling 0x04 shift altgr -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+4 0x05 - dollar 0x05 shift - asciitilde 0x05 altgr -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+5 0x06 - percent 0x06 shift - onehalf 0x06 altgr - threeeighths 0x06 shift altgr -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+6 0x07 - ampersand 0x07 shift - notsign 0x07 altgr - fiveeighths 0x07 shift altgr -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+7 0x08 - slash 0x08 shift -+braceleft 0x08 altgr - seveneighths 0x08 shift altgr -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+8 0x09 - parenleft 0x09 shift -+bracketleft 0x09 altgr - trademark 0x09 shift altgr -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+9 0x0a - parenright 0x0a shift -+bracketright 0x0a altgr - plusminus 0x0a shift altgr -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+0 0x0b - equal 0x0b shift -+braceright 0x0b altgr - degree 0x0b shift altgr -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc - apostrophe 0x0c - question 0x0c shift -+backslash 0x0c altgr -+questiondown 0x0c shift altgr -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd - exclamdown 0x0d - questiondown 0x0d shift -+dead_tilde 0x0d altgr -+asciitilde 0x0d shift altgr -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+q 0x10 -+Q 0x10 shift -+at 0x10 altgr - Greek_OMEGA 0x10 shift altgr -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+w 0x11 -+W 0x11 shift - lstroke 0x11 altgr - Lstroke 0x11 shift altgr -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+e 0x12 -+E 0x12 shift - EuroSign 0x12 altgr -+cent 0x12 shift altgr -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+r 0x13 -+R 0x13 shift - paragraph 0x13 altgr - registered 0x13 shift altgr -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+t 0x14 -+T 0x14 shift - tslash 0x14 altgr - Tslash 0x14 shift altgr -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+y 0x15 -+Y 0x15 shift - leftarrow 0x15 altgr - yen 0x15 shift altgr -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+u 0x16 -+U 0x16 shift - downarrow 0x16 altgr - uparrow 0x16 shift altgr -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+i 0x17 -+I 0x17 shift - rightarrow 0x17 altgr - idotless 0x17 shift altgr -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+o 0x18 -+O 0x18 shift - oslash 0x18 altgr --Ooblique 0x18 shift altgr -+Oslash 0x18 shift altgr -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+p 0x19 -+P 0x19 shift - thorn 0x19 altgr - THORN 0x19 shift altgr -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a - dead_grave 0x1a - dead_circumflex 0x1a shift - bracketleft 0x1a altgr - dead_abovering 0x1a shift altgr -+ -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b - plus 0x1b - asterisk 0x1b shift - bracketright 0x1b altgr - dead_macron 0x1b shift altgr -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+a 0x1e -+A 0x1e shift - ae 0x1e altgr - AE 0x1e shift altgr -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+s 0x1f -+S 0x1f shift - ssharp 0x1f altgr - section 0x1f shift altgr -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+d 0x20 -+D 0x20 shift - eth 0x20 altgr - ETH 0x20 shift altgr -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+f 0x21 -+F 0x21 shift - dstroke 0x21 altgr -+ordfeminine 0x21 shift altgr -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+g 0x22 -+G 0x22 shift - eng 0x22 altgr - ENG 0x22 shift altgr -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+h 0x23 -+H 0x23 shift - hstroke 0x23 altgr - Hstroke 0x23 shift altgr -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+j 0x24 -+J 0x24 shift -+dead_hook 0x24 altgr -+dead_horn 0x24 shift altgr -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+k 0x25 -+K 0x25 shift - kra 0x25 altgr -+ampersand 0x25 shift altgr -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+l 0x26 -+L 0x26 shift - lstroke 0x26 altgr - Lstroke 0x26 shift altgr -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 - ntilde 0x27 - Ntilde 0x27 shift -+asciitilde 0x27 altgr - dead_doubleacute 0x27 shift altgr -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 - dead_acute 0x28 - dead_diaeresis 0x28 shift - braceleft 0x28 altgr -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 - masculine 0x29 - ordfeminine 0x29 shift - backslash 0x29 altgr -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b - ccedilla 0x2b - Ccedilla 0x2b shift - braceright 0x2b altgr - dead_breve 0x2b shift altgr -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+z 0x2c -+Z 0x2c shift - guillemotleft 0x2c altgr --less 0x56 --greater 0x56 shift -+less 0x2c shift altgr -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+x 0x2d -+X 0x2d shift - guillemotright 0x2d altgr -+greater 0x2d shift altgr -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+c 0x2e -+C 0x2e shift - cent 0x2e altgr - copyright 0x2e shift altgr -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+v 0x2f -+V 0x2f shift - leftdoublequotemark 0x2f altgr --grave 0x2f shift altgr -+leftsinglequotemark 0x2f shift altgr -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+b 0x30 -+B 0x30 shift - rightdoublequotemark 0x30 altgr -+rightsinglequotemark 0x30 shift altgr -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+n 0x31 -+N 0x31 shift -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+m 0x32 -+M 0x32 shift - mu 0x32 altgr -+masculine 0x32 shift altgr -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 - comma 0x33 - semicolon 0x33 shift - horizconnector 0x33 altgr - multiply 0x33 shift altgr -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 - period 0x34 - colon 0x34 shift -+periodcentered 0x34 altgr - division 0x34 shift altgr -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 - minus 0x35 - underscore 0x35 shift - dead_belowdot 0x35 altgr - dead_abovedot 0x35 shift altgr -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Decimal 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 -+less 0x56 -+greater 0x56 shift -+bar 0x56 altgr -+brokenbar 0x56 shift altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+ISO_Level3_Shift 0xb8 -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/et b/pc-bios/keymaps/et -index 85541a3..7bed679 100644 ---- a/pc-bios/keymaps/et -+++ b/pc-bios/keymaps/et -@@ -1,85 +1,745 @@ --map 0x00000425 --include common -- --# --# Top row - # --dead_caron 0x29 --dead_tilde 0x29 shift -- --# 1 --exclam 0x2 shift -- --# 2 --quotedbl 0x3 shift --at 0x3 altgr -- --# 3 --numbersign 0x4 shift --sterling 0x4 altgr --# 4 --currency 0x5 shift --dollar 0x5 altgr --# 5 --percent 0x6 shift --# 6 --ampersand 0x7 shift --# 7 --slash 0x8 shift --braceleft 0x8 altgr --# 8 --parenleft 0x9 shift --bracketleft 0x9 altgr --# 9 --parenright 0xa shift --bracketright 0xa altgr --# 0 --equal 0xb shift --braceright 0xb altgr -- --plus 0xc --question 0xc shift --backslash 0xc altgr -- --acute 0xd --dead_acute 0xd --grave 0xd shift --dead_grave 0xd shift -+# generated by qemu-keymap -+# model : pc105 -+# layout : et -+# variant : - -+# options : - - --# --# QWERTY first row --# --EuroSign 0x12 altgr --udiaeresis 0x1a --Udiaeresis 0x1a shift --otilde 0x1b --Otilde 0x1b shift --section 0x1b altgr -+# name: "Amharic" - --# --# QWERTY second row --# --scaron 0x1f altgr --Scaron 0x1f altgr shift --odiaeresis 0x27 --Odiaeresis 0x27 shift --adiaeresis 0x28 --Adiaeresis 0x28 shift --asciicircum 0x28 altgr --apostrophe 0x2b --asterisk 0x2b shift --onehalf 0x2b altgr --# --# QWERTY third row --# -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+U1369 0x02 -+U1372 0x02 shift -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+U136A 0x03 -+U1373 0x03 shift -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+U136B 0x04 -+U1374 0x04 shift -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+U136C 0x05 -+U1375 0x05 shift -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+U136D 0x06 -+U1376 0x06 shift -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+U136E 0x07 -+U1377 0x07 shift -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+U136F 0x08 -+U1378 0x08 shift -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+U1370 0x09 -+U1379 0x09 shift -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+U1371 0x0a -+U137A 0x0a shift -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+U137B 0x0b -+U137C 0x0b shift -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc -+minus 0x0c -+underscore 0x0c shift -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd -+equal 0x0d -+plus 0x0d shift -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+U1240 0x10 -+U1250 0x10 shift -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+U12C8 0x11 -+VoidSymbol 0x11 shift -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+UFE69 0x12 -+UFE70 0x12 shift -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+U1228 0x13 -+VoidSymbol 0x13 shift -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+U1270 0x14 -+U1320 0x14 shift -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+U12E8 0x15 -+VoidSymbol 0x15 shift -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+UFE75 0x16 -+UFE76 0x16 shift -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+UFE71 0x17 -+UFE72 0x17 shift -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+UFE73 0x18 -+UFE74 0x18 shift -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+U1350 0x19 -+U1330 0x19 shift -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a -+U1340 0x1a -+U1338 0x1a shift -+ -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b -+U1328 0x1b -+U1280 0x1b shift -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+UFE67 0x1e -+UFE68 0x1e shift -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+U1230 0x1f -+U1220 0x1f shift -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+U12F0 0x20 -+U12F8 0x20 shift -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+U1348 0x21 -+VoidSymbol 0x21 shift -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+U1308 0x22 -+U1318 0x22 shift -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+U1200 0x23 -+U1210 0x23 shift -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+U1300 0x24 -+VoidSymbol 0x24 shift -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+U12A8 0x25 -+U12B8 0x25 shift -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+U1208 0x26 -+VoidSymbol 0x26 shift -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 -+U1362 0x27 -+U1361 0x27 shift -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 -+U1366 0x28 -+U1365 0x28 shift -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b -+VoidSymbol 0x2b -+U2010 0x2b shift -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+U12D8 0x2c -+U12E0 0x2c shift -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+U12A0 0x2d -+U12D0 0x2d shift -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+U1278 0x2e -+UFE78 0x2e shift -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+U1238 0x2f -+U1268 0x2f shift -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+U1260 0x30 -+VoidSymbol 0x30 shift -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+U1290 0x31 -+U1298 0x31 shift -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+U1218 0x32 -+VoidSymbol 0x32 shift -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 -+U1363 0x33 -+VoidSymbol 0x33 shift -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 -+U1364 0x34 -+VoidSymbol 0x34 shift -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 -+U1367 0x35 -+question 0x35 shift -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Decimal 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 - less 0x56 - greater 0x56 shift - bar 0x56 altgr --zcaron 0x2c altgr --Zcaron 0x2c altgr shift --comma 0x33 --semicolon 0x33 shift --period 0x34 --colon 0x34 shift --minus 0x35 --underscore 0x35 shift -+brokenbar 0x56 shift altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+Alt_R 0xb8 -+Meta_R 0xb8 shift -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym ISO_Next_Group) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/fi b/pc-bios/keymaps/fi -index 4be7586..1c7653d 100644 ---- a/pc-bios/keymaps/fi -+++ b/pc-bios/keymaps/fi -@@ -1,122 +1,810 @@ --# generated from XKB map se_FI --include common --map 0x40b -+# -+# generated by qemu-keymap -+# model : pc105 -+# layout : fi -+# variant : - -+# options : - -+ -+# name: "Finnish" -+ -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+1 0x02 - exclam 0x02 shift --exclamdown 0x02 altgr --onesuperior 0x02 shift altgr -+exclamdown 0x02 shift altgr -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+2 0x03 - quotedbl 0x03 shift - at 0x03 altgr --twosuperior 0x03 shift altgr -+rightdoublequotemark 0x03 shift altgr -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+3 0x04 - numbersign 0x04 shift - sterling 0x04 altgr --threesuperior 0x04 shift altgr -+guillemotright 0x04 shift altgr -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+4 0x05 - currency 0x05 shift - dollar 0x05 altgr --onequarter 0x05 shift altgr -+guillemotleft 0x05 shift altgr -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+5 0x06 - percent 0x06 shift --onehalf 0x06 altgr --cent 0x06 shift altgr -+permille 0x06 altgr -+leftdoublequotemark 0x06 shift altgr -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+6 0x07 - ampersand 0x07 shift --yen 0x07 altgr --fiveeighths 0x07 shift altgr -+singlelowquotemark 0x07 altgr -+doublelowquotemark 0x07 shift altgr -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+7 0x08 - slash 0x08 shift - braceleft 0x08 altgr --division 0x08 shift altgr -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+8 0x09 - parenleft 0x09 shift - bracketleft 0x09 altgr --guillemotleft 0x09 shift altgr -+less 0x09 shift altgr -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+9 0x0a - parenright 0x0a shift - bracketright 0x0a altgr --guillemotright 0x0a shift altgr -+greater 0x0a shift altgr -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+0 0x0b - equal 0x0b shift - braceright 0x0b altgr - degree 0x0b shift altgr -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc - plus 0x0c - question 0x0c shift - backslash 0x0c altgr - questiondown 0x0c shift altgr -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd - dead_acute 0x0d - dead_grave 0x0d shift --plusminus 0x0d altgr --notsign 0x0d shift altgr --at 0x10 altgr --Greek_OMEGA 0x10 shift altgr --lstroke 0x11 altgr --Lstroke 0x11 shift altgr -+dead_cedilla 0x0d altgr -+dead_ogonek 0x0d shift altgr -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+q 0x10 -+Q 0x10 shift -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+w 0x11 -+W 0x11 shift -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+e 0x12 -+E 0x12 shift - EuroSign 0x12 altgr --cent 0x12 shift altgr --registered 0x13 altgr -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+r 0x13 -+R 0x13 shift -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+t 0x14 -+T 0x14 shift - thorn 0x14 altgr - THORN 0x14 shift altgr --leftarrow 0x15 altgr --yen 0x15 shift altgr --downarrow 0x16 altgr --uparrow 0x16 shift altgr --rightarrow 0x17 altgr --idotless 0x17 shift altgr -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+y 0x15 -+Y 0x15 shift -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+u 0x16 -+U 0x16 shift -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+i 0x17 -+I 0x17 shift -+idotless 0x17 altgr -+bar 0x17 shift altgr -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+o 0x18 -+O 0x18 shift - oe 0x18 altgr - OE 0x18 shift altgr --thorn 0x19 altgr --THORN 0x19 shift altgr -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+p 0x19 -+P 0x19 shift -+dead_horn 0x19 altgr -+dead_hook 0x19 shift altgr -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a - aring 0x1a - Aring 0x1a shift --dead_diaeresis 0x1a altgr -+dead_doubleacute 0x1a altgr - dead_abovering 0x1a shift altgr -+ -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b - dead_diaeresis 0x1b - dead_circumflex 0x1b shift - dead_tilde 0x1b altgr --dead_caron 0x1b shift altgr --ordfeminine 0x1e altgr --masculine 0x1e shift altgr -+dead_macron 0x1b shift altgr -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+a 0x1e -+A 0x1e shift -+schwa 0x1e altgr -+SCHWA 0x1e shift altgr -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+s 0x1f -+S 0x1f shift - ssharp 0x1f altgr --section 0x1f shift altgr -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+d 0x20 -+D 0x20 shift - eth 0x20 altgr - ETH 0x20 shift altgr --dstroke 0x21 altgr --ordfeminine 0x21 shift altgr --eng 0x22 altgr --ENG 0x22 shift altgr --hstroke 0x23 altgr --Hstroke 0x23 shift altgr -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+f 0x21 -+F 0x21 shift -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+g 0x22 -+G 0x22 shift -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+h 0x23 -+H 0x23 shift -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+j 0x24 -+J 0x24 shift -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+k 0x25 -+K 0x25 shift - kra 0x25 altgr --ampersand 0x25 shift altgr --lstroke 0x26 altgr --Lstroke 0x26 shift altgr -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+l 0x26 -+L 0x26 shift -+dead_stroke 0x26 altgr -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 - odiaeresis 0x27 - Odiaeresis 0x27 shift - oslash 0x27 altgr --Ooblique 0x27 shift altgr -+Oslash 0x27 shift altgr -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 - adiaeresis 0x28 - Adiaeresis 0x28 shift - ae 0x28 altgr - AE 0x28 shift altgr -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 - section 0x29 - onehalf 0x29 shift --paragraph 0x29 altgr --threequarters 0x29 shift altgr -+dead_stroke 0x29 altgr -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b - apostrophe 0x2b - asterisk 0x2b shift --acute 0x2b altgr --multiply 0x2b shift altgr --guillemotleft 0x2c altgr --guillemotright 0x2d altgr --copyright 0x2e altgr --leftdoublequotemark 0x2f altgr --grave 0x2f shift altgr --rightdoublequotemark 0x30 altgr --apostrophe 0x30 shift altgr -+dead_caron 0x2b altgr -+dead_breve 0x2b shift altgr -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+z 0x2c -+Z 0x2c shift -+ezh 0x2c altgr -+EZH 0x2c shift altgr -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+x 0x2d -+X 0x2d shift -+multiply 0x2d altgr -+periodcentered 0x2d shift altgr -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+c 0x2e -+C 0x2e shift -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+v 0x2f -+V 0x2f shift -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+b 0x30 -+B 0x30 shift -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+n 0x31 -+N 0x31 shift -+eng 0x31 altgr -+ENG 0x31 shift altgr -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+m 0x32 -+M 0x32 shift - mu 0x32 altgr --masculine 0x32 shift altgr -+emdash 0x32 shift altgr -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 - comma 0x33 - semicolon 0x33 shift --dead_cedilla 0x33 altgr --dead_ogonek 0x33 shift altgr -+rightsinglequotemark 0x33 altgr -+leftsinglequotemark 0x33 shift altgr -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 - period 0x34 - colon 0x34 shift --periodcentered 0x34 altgr -+dead_belowdot 0x34 altgr - dead_abovedot 0x34 shift altgr -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 - minus 0x35 - underscore 0x35 shift --hyphen 0x35 altgr --macron 0x35 shift altgr -+endash 0x35 altgr -+dead_belowcomma 0x35 shift altgr -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 - nobreakspace 0x39 altgr -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Separator 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 -+less 0x56 -+greater 0x56 shift -+bar 0x56 altgr -+brokenbar 0x56 shift altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+ISO_Level3_Shift 0xb8 -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/fo b/pc-bios/keymaps/fo -index c00d9d4..e69575b 100644 ---- a/pc-bios/keymaps/fo -+++ b/pc-bios/keymaps/fo -@@ -1,76 +1,837 @@ --map 0x438 --include common -- --# --# Top row - # --onehalf 0x29 --section 0x29 shift -+# generated by qemu-keymap -+# model : pc105 -+# layout : fo -+# variant : - -+# options : - - --# 1 --exclam 0x2 shift -- --# 2 --quotedbl 0x3 shift --at 0x3 altgr -- --# 3 --numbersign 0x4 shift --sterling 0x4 altgr --# 4 --currency 0x5 shift --dollar 0x5 altgr --# 5 --percent 0x6 shift --# 6 --ampersand 0x7 shift --# 7 --slash 0x8 shift --braceleft 0x8 altgr --# 8 --parenleft 0x9 shift --bracketleft 0x9 altgr --# 9 --parenright 0xa shift --bracketright 0xa altgr --# 0 --equal 0xb shift --braceright 0xb altgr -- --plus 0xc --question 0xc shift --plusminus 0xc altgr -- --bar 0xd altgr --dead_acute 0xd -+# name: "Faroese" - --# --# QWERTY first row --# -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+1 0x02 -+exclam 0x02 shift -+exclamdown 0x02 altgr -+onesuperior 0x02 shift altgr -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+2 0x03 -+quotedbl 0x03 shift -+at 0x03 altgr -+twosuperior 0x03 shift altgr -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+3 0x04 -+numbersign 0x04 shift -+sterling 0x04 altgr -+threesuperior 0x04 shift altgr -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+4 0x05 -+currency 0x05 shift -+dollar 0x05 altgr -+onequarter 0x05 shift altgr -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+5 0x06 -+percent 0x06 shift -+onehalf 0x06 altgr -+cent 0x06 shift altgr -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+6 0x07 -+ampersand 0x07 shift -+yen 0x07 altgr -+fiveeighths 0x07 shift altgr -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+7 0x08 -+slash 0x08 shift -+braceleft 0x08 altgr -+division 0x08 shift altgr -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+8 0x09 -+parenleft 0x09 shift -+bracketleft 0x09 altgr -+guillemotleft 0x09 shift altgr -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+9 0x0a -+parenright 0x0a shift -+bracketright 0x0a altgr -+guillemotright 0x0a shift altgr -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+0 0x0b -+equal 0x0b shift -+braceright 0x0b altgr -+degree 0x0b shift altgr -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc -+plus 0x0c -+question 0x0c shift -+plusminus 0x0c altgr -+questiondown 0x0c shift altgr -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd -+dead_acute 0x0d -+dead_grave 0x0d shift -+bar 0x0d altgr -+brokenbar 0x0d shift altgr -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+q 0x10 -+Q 0x10 shift -+at 0x10 altgr -+Greek_OMEGA 0x10 shift altgr -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+w 0x11 -+W 0x11 shift -+lstroke 0x11 altgr -+Lstroke 0x11 shift altgr -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+e 0x12 -+E 0x12 shift - EuroSign 0x12 altgr -+cent 0x12 shift altgr -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+r 0x13 -+R 0x13 shift -+registered 0x13 altgr -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+t 0x14 -+T 0x14 shift -+thorn 0x14 altgr -+THORN 0x14 shift altgr -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+y 0x15 -+Y 0x15 shift -+leftarrow 0x15 altgr -+yen 0x15 shift altgr -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+u 0x16 -+U 0x16 shift -+downarrow 0x16 altgr -+uparrow 0x16 shift altgr -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+i 0x17 -+I 0x17 shift -+rightarrow 0x17 altgr -+idotless 0x17 shift altgr -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+o 0x18 -+O 0x18 shift -+oe 0x18 altgr -+OE 0x18 shift altgr -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+p 0x19 -+P 0x19 shift -+thorn 0x19 altgr -+THORN 0x19 shift altgr -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a - aring 0x1a - Aring 0x1a shift --eth 0x1b addupper --asciitilde 0x1b altgr -+dead_diaeresis 0x1a altgr -+dead_circumflex 0x1a shift altgr - --# --# QWERTY second row --# --ae 0x27 addupper -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b -+eth 0x1b -+ETH 0x1b shift -+dead_tilde 0x1b altgr -+dead_caron 0x1b shift altgr -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+a 0x1e -+A 0x1e shift -+ordfeminine 0x1e altgr -+masculine 0x1e shift altgr -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+s 0x1f -+S 0x1f shift -+ssharp 0x1f altgr -+section 0x1f shift altgr -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+d 0x20 -+D 0x20 shift -+eth 0x20 altgr -+ETH 0x20 shift altgr -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+f 0x21 -+F 0x21 shift -+dstroke 0x21 altgr -+ordfeminine 0x21 shift altgr -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+g 0x22 -+G 0x22 shift -+eng 0x22 altgr -+ENG 0x22 shift altgr -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+h 0x23 -+H 0x23 shift -+hstroke 0x23 altgr -+Hstroke 0x23 shift altgr -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+j 0x24 -+J 0x24 shift -+dead_hook 0x24 altgr -+dead_horn 0x24 shift altgr -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+k 0x25 -+K 0x25 shift -+kra 0x25 altgr -+ampersand 0x25 shift altgr -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+l 0x26 -+L 0x26 shift -+lstroke 0x26 altgr -+Lstroke 0x26 shift altgr -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 -+ae 0x27 -+AE 0x27 shift -+dead_acute 0x27 altgr -+dead_doubleacute 0x27 shift altgr -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 - oslash 0x28 --Ooblique 0x28 shift -+Oslash 0x28 shift -+dead_circumflex 0x28 altgr -+dead_caron 0x28 shift altgr -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 -+onehalf 0x29 -+section 0x29 shift -+threequarters 0x29 altgr -+paragraph 0x29 shift altgr -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b - apostrophe 0x2b - asterisk 0x2b shift -+dead_doubleacute 0x2b altgr -+multiply 0x2b shift altgr - --# --# QWERTY third row --# --less 0x56 --greater 0x56 shift --backslash 0x56 altgr -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+z 0x2c -+Z 0x2c shift -+guillemotleft 0x2c altgr -+less 0x2c shift altgr -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+x 0x2d -+X 0x2d shift -+guillemotright 0x2d altgr -+greater 0x2d shift altgr -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+c 0x2e -+C 0x2e shift -+copyright 0x2e altgr -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+v 0x2f -+V 0x2f shift -+leftdoublequotemark 0x2f altgr -+leftsinglequotemark 0x2f shift altgr -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+b 0x30 -+B 0x30 shift -+rightdoublequotemark 0x30 altgr -+rightsinglequotemark 0x30 shift altgr -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+n 0x31 -+N 0x31 shift -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+m 0x32 -+M 0x32 shift -+mu 0x32 altgr -+masculine 0x32 shift altgr -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 - comma 0x33 - semicolon 0x33 shift -+dead_cedilla 0x33 altgr -+dead_ogonek 0x33 shift altgr -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 - period 0x34 - colon 0x34 shift -+periodcentered 0x34 altgr -+dead_abovedot 0x34 shift altgr -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 - minus 0x35 - underscore 0x35 shift -+hyphen 0x35 altgr -+macron 0x35 shift altgr -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+nobreakspace 0x39 altgr -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Decimal 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 -+less 0x56 -+greater 0x56 shift -+backslash 0x56 altgr -+notsign 0x56 shift altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+ISO_Level3_Shift 0xb8 -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/fr b/pc-bios/keymaps/fr -index ba5a176..5b25227 100644 ---- a/pc-bios/keymaps/fr -+++ b/pc-bios/keymaps/fr -@@ -1,181 +1,837 @@ --include common --map 0x40c - # --# Top row --# --twosuperior 0x29 --notsign 0x29 altgr -- -+# generated by qemu-keymap -+# model : pc105 -+# layout : fr -+# variant : - -+# options : - -+ -+# name: "French" -+ -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 - ampersand 0x02 - 1 0x02 shift - onesuperior 0x02 altgr - exclamdown 0x02 shift altgr - -+# evdev 3 (0x3), QKeyCode "2", number 0x3 - eacute 0x03 - 2 0x03 shift - asciitilde 0x03 altgr - oneeighth 0x03 shift altgr - -+# evdev 4 (0x4), QKeyCode "3", number 0x4 - quotedbl 0x04 - 3 0x04 shift - numbersign 0x04 altgr -+sterling 0x04 shift altgr - -+# evdev 5 (0x5), QKeyCode "4", number 0x5 - apostrophe 0x05 - 4 0x05 shift - braceleft 0x05 altgr -+dollar 0x05 shift altgr - -+# evdev 6 (0x6), QKeyCode "5", number 0x6 - parenleft 0x06 - 5 0x06 shift - bracketleft 0x06 altgr - threeeighths 0x06 shift altgr - -+# evdev 7 (0x7), QKeyCode "6", number 0x7 - minus 0x07 - 6 0x07 shift - bar 0x07 altgr - fiveeighths 0x07 shift altgr - -+# evdev 8 (0x8), QKeyCode "7", number 0x8 - egrave 0x08 - 7 0x08 shift - grave 0x08 altgr - seveneighths 0x08 shift altgr - -+# evdev 9 (0x9), QKeyCode "8", number 0x9 - underscore 0x09 - 8 0x09 shift - backslash 0x09 altgr - trademark 0x09 shift altgr - -+# evdev 10 (0xa), QKeyCode "9", number 0xa - ccedilla 0x0a - 9 0x0a shift - asciicircum 0x0a altgr - plusminus 0x0a shift altgr - -+# evdev 11 (0xb), QKeyCode "0", number 0xb - agrave 0x0b - 0 0x0b shift - at 0x0b altgr -+degree 0x0b shift altgr - -+# evdev 12 (0xc), QKeyCode "minus", number 0xc - parenright 0x0c - degree 0x0c shift - bracketright 0x0c altgr - questiondown 0x0c shift altgr - -+# evdev 13 (0xd), QKeyCode "equal", number 0xd - equal 0x0d - plus 0x0d shift - braceright 0x0d altgr - dead_ogonek 0x0d shift altgr - --# --# AZERTY first row --# -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift - --a 0x10 addupper -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+a 0x10 -+A 0x10 shift - ae 0x10 altgr - AE 0x10 shift altgr - --z 0x11 addupper -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+z 0x11 -+Z 0x11 shift - guillemotleft 0x11 altgr -+less 0x11 shift altgr - -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+e 0x12 -+E 0x12 shift - EuroSign 0x12 altgr -+cent 0x12 shift altgr - -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+r 0x13 -+R 0x13 shift - paragraph 0x13 altgr - registered 0x13 shift altgr - -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+t 0x14 -+T 0x14 shift - tslash 0x14 altgr - Tslash 0x14 shift altgr - -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+y 0x15 -+Y 0x15 shift - leftarrow 0x15 altgr - yen 0x15 shift altgr - -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+u 0x16 -+U 0x16 shift - downarrow 0x16 altgr - uparrow 0x16 shift altgr - -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+i 0x17 -+I 0x17 shift - rightarrow 0x17 altgr - idotless 0x17 shift altgr - -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+o 0x18 -+O 0x18 shift - oslash 0x18 altgr --Ooblique 0x18 shift altgr -+Oslash 0x18 shift altgr - -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+p 0x19 -+P 0x19 shift - thorn 0x19 altgr - THORN 0x19 shift altgr - -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a - dead_circumflex 0x1a - dead_diaeresis 0x1a shift -+dead_diaeresis 0x1a altgr - dead_abovering 0x1a shift altgr - -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b - dollar 0x1b - sterling 0x1b shift - currency 0x1b altgr - dead_macron 0x1b shift altgr - --# --# AZERTY second row --# --q 0x1e addupper -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+q 0x1e -+Q 0x1e shift -+at 0x1e altgr - Greek_OMEGA 0x1e shift altgr - -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+s 0x1f -+S 0x1f shift - ssharp 0x1f altgr -+section 0x1f shift altgr - -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+d 0x20 -+D 0x20 shift - eth 0x20 altgr - ETH 0x20 shift altgr - -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+f 0x21 -+F 0x21 shift - dstroke 0x21 altgr - ordfeminine 0x21 shift altgr - -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+g 0x22 -+G 0x22 shift - eng 0x22 altgr - ENG 0x22 shift altgr - -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+h 0x23 -+H 0x23 shift - hstroke 0x23 altgr - Hstroke 0x23 shift altgr - -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+j 0x24 -+J 0x24 shift -+dead_hook 0x24 altgr -+dead_horn 0x24 shift altgr -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+k 0x25 -+K 0x25 shift - kra 0x25 altgr -+ampersand 0x25 shift altgr - -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+l 0x26 -+L 0x26 shift - lstroke 0x26 altgr - Lstroke 0x26 shift altgr - --m 0x27 addupper -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 -+m 0x27 -+M 0x27 shift -+mu 0x27 altgr - masculine 0x27 shift altgr - -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 - ugrave 0x28 - percent 0x28 shift -+dead_circumflex 0x28 altgr - dead_caron 0x28 shift altgr - -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 -+twosuperior 0x29 -+asciitilde 0x29 shift -+notsign 0x29 altgr -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b - asterisk 0x2b - mu 0x2b shift - dead_grave 0x2b altgr - dead_breve 0x2b shift altgr - --# --# AZERTY third row --# --less 0x56 --greater 0x56 shift -- --w 0x2c addupper -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+w 0x2c -+W 0x2c shift -+lstroke 0x2c altgr -+Lstroke 0x2c shift altgr - -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+x 0x2d -+X 0x2d shift - guillemotright 0x2d altgr -+greater 0x2d shift altgr - -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+c 0x2e -+C 0x2e shift - cent 0x2e altgr - copyright 0x2e shift altgr - -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+v 0x2f -+V 0x2f shift - leftdoublequotemark 0x2f altgr -+leftsinglequotemark 0x2f shift altgr - -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+b 0x30 -+B 0x30 shift - rightdoublequotemark 0x30 altgr -+rightsinglequotemark 0x30 shift altgr - -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+n 0x31 -+N 0x31 shift -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 - comma 0x32 - question 0x32 shift - dead_acute 0x32 altgr - dead_doubleacute 0x32 shift altgr - -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 - semicolon 0x33 - period 0x33 shift - horizconnector 0x33 altgr - multiply 0x33 shift altgr - -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 - colon 0x34 - slash 0x34 shift - periodcentered 0x34 altgr - division 0x34 shift altgr - -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 - exclam 0x35 - section 0x35 shift - dead_belowdot 0x35 altgr - dead_abovedot 0x35 shift altgr -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Decimal 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 -+less 0x56 -+greater 0x56 shift -+bar 0x56 altgr -+brokenbar 0x56 shift altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+ISO_Level3_Shift 0xb8 -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/fr-be b/pc-bios/keymaps/fr-be -index 62f7128..9d2ac5d 100644 ---- a/pc-bios/keymaps/fr-be -+++ b/pc-bios/keymaps/fr-be -@@ -1,134 +1,836 @@ --# generated from XKB map be --include common --map 0x80c -+# -+# generated by qemu-keymap -+# model : pc105 -+# layout : be -+# variant : - -+# options : - -+ -+# name: "Belgian" -+ -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 - ampersand 0x02 - 1 0x02 shift - bar 0x02 altgr - exclamdown 0x02 shift altgr -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 - eacute 0x03 - 2 0x03 shift - at 0x03 altgr - oneeighth 0x03 shift altgr -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 - quotedbl 0x04 - 3 0x04 shift - numbersign 0x04 altgr - sterling 0x04 shift altgr -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 - apostrophe 0x05 - 4 0x05 shift - onequarter 0x05 altgr - dollar 0x05 shift altgr -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 - parenleft 0x06 - 5 0x06 shift - onehalf 0x06 altgr - threeeighths 0x06 shift altgr -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 - section 0x07 - 6 0x07 shift - asciicircum 0x07 altgr - fiveeighths 0x07 shift altgr -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 - egrave 0x08 - 7 0x08 shift - braceleft 0x08 altgr - seveneighths 0x08 shift altgr -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 - exclam 0x09 - 8 0x09 shift - bracketleft 0x09 altgr - trademark 0x09 shift altgr -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa - ccedilla 0x0a - 9 0x0a shift - braceleft 0x0a altgr - plusminus 0x0a shift altgr -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb - agrave 0x0b - 0 0x0b shift - braceright 0x0b altgr - degree 0x0b shift altgr -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc - parenright 0x0c - degree 0x0c shift - backslash 0x0c altgr - questiondown 0x0c shift altgr -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd - minus 0x0d - underscore 0x0d shift - dead_cedilla 0x0d altgr - dead_ogonek 0x0d shift altgr --a 0x10 addupper -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+a 0x10 -+A 0x10 shift -+at 0x10 altgr - Greek_OMEGA 0x10 shift altgr --z 0x11 addupper -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+z 0x11 -+Z 0x11 shift - lstroke 0x11 altgr - Lstroke 0x11 shift altgr -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+e 0x12 -+E 0x12 shift - EuroSign 0x12 altgr - cent 0x12 shift altgr -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+r 0x13 -+R 0x13 shift - paragraph 0x13 altgr - registered 0x13 shift altgr -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+t 0x14 -+T 0x14 shift - tslash 0x14 altgr - Tslash 0x14 shift altgr -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+y 0x15 -+Y 0x15 shift - leftarrow 0x15 altgr - yen 0x15 shift altgr -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+u 0x16 -+U 0x16 shift - downarrow 0x16 altgr - uparrow 0x16 shift altgr -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+i 0x17 -+I 0x17 shift - rightarrow 0x17 altgr - idotless 0x17 shift altgr --oslash 0x18 altgr --Ooblique 0x18 shift altgr -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+o 0x18 -+O 0x18 shift -+oe 0x18 altgr -+OE 0x18 shift altgr -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+p 0x19 -+P 0x19 shift - thorn 0x19 altgr - THORN 0x19 shift altgr -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a - dead_circumflex 0x1a - dead_diaeresis 0x1a shift - bracketleft 0x1a altgr - dead_abovering 0x1a shift altgr -+ -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b - dollar 0x1b - asterisk 0x1b shift - bracketright 0x1b altgr - dead_macron 0x1b shift altgr --q 0x1e addupper -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+q 0x1e -+Q 0x1e shift - ae 0x1e altgr - AE 0x1e shift altgr -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+s 0x1f -+S 0x1f shift - ssharp 0x1f altgr -+section 0x1f shift altgr -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+d 0x20 -+D 0x20 shift - eth 0x20 altgr - ETH 0x20 shift altgr -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+f 0x21 -+F 0x21 shift - dstroke 0x21 altgr - ordfeminine 0x21 shift altgr -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+g 0x22 -+G 0x22 shift - eng 0x22 altgr - ENG 0x22 shift altgr -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+h 0x23 -+H 0x23 shift - hstroke 0x23 altgr - Hstroke 0x23 shift altgr -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+j 0x24 -+J 0x24 shift -+dead_hook 0x24 altgr -+dead_horn 0x24 shift altgr -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+k 0x25 -+K 0x25 shift - kra 0x25 altgr -+ampersand 0x25 shift altgr -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+l 0x26 -+L 0x26 shift - lstroke 0x26 altgr - Lstroke 0x26 shift altgr --m 0x27 addupper -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 -+m 0x27 -+M 0x27 shift - dead_acute 0x27 altgr - dead_doubleacute 0x27 shift altgr -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 - ugrave 0x28 - percent 0x28 shift - dead_acute 0x28 altgr - dead_caron 0x28 shift altgr -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 - twosuperior 0x29 - threesuperior 0x29 shift - notsign 0x29 altgr -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b - mu 0x2b - sterling 0x2b shift - dead_grave 0x2b altgr - dead_breve 0x2b shift altgr --w 0x2c addupper -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+w 0x2c -+W 0x2c shift - guillemotleft 0x2c altgr -+less 0x2c shift altgr -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+x 0x2d -+X 0x2d shift - guillemotright 0x2d altgr -+greater 0x2d shift altgr -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+c 0x2e -+C 0x2e shift - cent 0x2e altgr - copyright 0x2e shift altgr -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+v 0x2f -+V 0x2f shift - leftdoublequotemark 0x2f altgr --grave 0x2f shift altgr -+leftsinglequotemark 0x2f shift altgr -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+b 0x30 -+B 0x30 shift - rightdoublequotemark 0x30 altgr -+rightsinglequotemark 0x30 shift altgr -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+n 0x31 -+N 0x31 shift -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 - comma 0x32 - question 0x32 shift - dead_cedilla 0x32 altgr - masculine 0x32 shift altgr -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 - semicolon 0x33 - period 0x33 shift - horizconnector 0x33 altgr - multiply 0x33 shift altgr -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 - colon 0x34 - slash 0x34 shift - periodcentered 0x34 altgr - division 0x34 shift altgr -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 - equal 0x35 - plus 0x35 shift - dead_tilde 0x35 altgr - dead_abovedot 0x35 shift altgr -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Decimal 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 -+less 0x56 -+greater 0x56 shift - backslash 0x56 altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+ISO_Level3_Shift 0xb8 -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/fr-ca b/pc-bios/keymaps/fr-ca -index 13a0306..736897b 100644 ---- a/pc-bios/keymaps/fr-ca -+++ b/pc-bios/keymaps/fr-ca -@@ -1,60 +1,768 @@ --# Canadian French --# By Simon Germain --include common --map 0xc0c -+# -+# generated by qemu-keymap -+# model : pc105 -+# layout : ca -+# variant : fr -+# options : - - --backslash 0x29 altgr --plusminus 0x2 altgr --at 0x3 altgr --sterling 0x4 altgr --cent 0x5 altgr --currency 0x6 altgr --notsign 0x7 altgr --numbersign 0x29 --bar 0x29 shift --twosuperior 0x9 altgr --threesuperior 0xa altgr --onequarter 0xb altgr --onehalf 0xc altgr --threequarters 0xd altgr -+# name: "French (Canada)" -+ -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+1 0x02 -+exclam 0x02 shift -+plusminus 0x02 altgr -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+2 0x03 -+quotedbl 0x03 shift -+at 0x03 altgr -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+3 0x04 -+slash 0x04 shift -+sterling 0x04 altgr -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+4 0x05 -+dollar 0x05 shift -+cent 0x05 altgr -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+5 0x06 -+percent 0x06 shift -+currency 0x06 altgr -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+6 0x07 -+question 0x07 shift -+notsign 0x07 altgr -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+7 0x08 -+ampersand 0x08 shift -+brokenbar 0x08 altgr -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+8 0x09 -+asterisk 0x09 shift -+twosuperior 0x09 altgr -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+9 0x0a -+parenleft 0x0a shift -+threesuperior 0x0a altgr -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+0 0x0b -+parenright 0x0b shift -+onequarter 0x0b altgr -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc -+minus 0x0c -+underscore 0x0c shift -+onehalf 0x0c altgr -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd -+equal 0x0d -+plus 0x0d shift -+threequarters 0x0d altgr -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+q 0x10 -+Q 0x10 shift -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+w 0x11 -+W 0x11 shift -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+e 0x12 -+E 0x12 shift -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+r 0x13 -+R 0x13 shift -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+t 0x14 -+T 0x14 shift -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+y 0x15 -+Y 0x15 shift -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+u 0x16 -+U 0x16 shift -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+i 0x17 -+I 0x17 shift -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+o 0x18 -+O 0x18 shift - section 0x18 altgr -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+p 0x19 -+P 0x19 shift - paragraph 0x19 altgr -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a -+dead_circumflex 0x1a - bracketleft 0x1a altgr -+ -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b -+dead_cedilla 0x1b -+dead_diaeresis 0x1b shift - bracketright 0x1b altgr -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+a 0x1e -+A 0x1e shift -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+s 0x1f -+S 0x1f shift -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+d 0x20 -+D 0x20 shift -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+f 0x21 -+F 0x21 shift -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+g 0x22 -+G 0x22 shift -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+h 0x23 -+H 0x23 shift -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+j 0x24 -+J 0x24 shift -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+k 0x25 -+K 0x25 shift -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+l 0x26 -+L 0x26 shift -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 -+semicolon 0x27 -+colon 0x27 shift - asciitilde 0x27 altgr -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 -+dead_grave 0x28 - braceleft 0x28 altgr --braceright 0x2b altgr -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 -+numbersign 0x29 -+bar 0x29 shift -+backslash 0x29 altgr -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b - less 0x2b - greater 0x2b shift --guillemotleft 0x56 --guillemotright 0x56 shift --degree 0x56 altgr -+braceright 0x2b altgr -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+z 0x2c -+Z 0x2c shift -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+x 0x2d -+X 0x2d shift -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+c 0x2e -+C 0x2e shift -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+v 0x2f -+V 0x2f shift -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+b 0x30 -+B 0x30 shift -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+n 0x31 -+N 0x31 shift -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+m 0x32 -+M 0x32 shift - mu 0x32 altgr --eacute 0x35 --dead_acute 0x35 altgr --dead_grave 0x28 --dead_circumflex 0x1a --dead_circumflex 0x1a shift --dead_cedilla 0x1b --dead_diaeresis 0x1b shift --exclam 0x2 shift --quotedbl 0x3 shift -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 - comma 0x33 - apostrophe 0x33 shift -+macron 0x33 altgr -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 - period 0x34 --period 0x34 shift --slash 0x4 shift --dollar 0x5 shift --percent 0x6 shift --question 0x7 shift --ampersand 0x8 shift --asterisk 0x9 shift --parenleft 0xa shift --parenright 0xb shift --underscore 0xc shift --minus 0xc --underscore 0xc shift --equal 0xd --plus 0xd shift --semicolon 0x27 --colon 0x27 shift -+hyphen 0x34 altgr -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 -+eacute 0x35 -+Eacute 0x35 shift -+dead_acute 0x35 altgr -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+nobreakspace 0x39 altgr -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Decimal 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 -+guillemotleft 0x56 -+guillemotright 0x56 shift -+degree 0x56 altgr -+brokenbar 0x56 shift altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+ISO_Level3_Shift 0xb8 -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/fr-ch b/pc-bios/keymaps/fr-ch -index 4620d20..40e1fef 100644 ---- a/pc-bios/keymaps/fr-ch -+++ b/pc-bios/keymaps/fr-ch -@@ -1,114 +1,836 @@ --# generated from XKB map fr_CH --include common --map 0x100c --exclam 0x02 shift --onesuperior 0x02 altgr -+# -+# generated by qemu-keymap -+# model : pc105 -+# layout : ch -+# variant : fr -+# options : - -+ -+# name: "French (Switzerland)" -+ -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+1 0x02 -+plus 0x02 shift -+bar 0x02 altgr - exclamdown 0x02 shift altgr -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+2 0x03 - quotedbl 0x03 shift --twosuperior 0x03 altgr -+at 0x03 altgr - oneeighth 0x03 shift altgr --section 0x04 shift --threesuperior 0x04 altgr -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+3 0x04 -+asterisk 0x04 shift -+numbersign 0x04 altgr - sterling 0x04 shift altgr --dollar 0x05 shift -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+4 0x05 -+ccedilla 0x05 shift - onequarter 0x05 altgr --currency 0x05 shift altgr -+dollar 0x05 shift altgr -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+5 0x06 - percent 0x06 shift - onehalf 0x06 altgr - threeeighths 0x06 shift altgr -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+6 0x07 - ampersand 0x07 shift --threequarters 0x07 altgr -+notsign 0x07 altgr - fiveeighths 0x07 shift altgr -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+7 0x08 - slash 0x08 shift --braceleft 0x08 altgr -+bar 0x08 altgr - seveneighths 0x08 shift altgr -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+8 0x09 - parenleft 0x09 shift --bracketleft 0x09 altgr -+cent 0x09 altgr - trademark 0x09 shift altgr -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+9 0x0a - parenright 0x0a shift - bracketright 0x0a altgr - plusminus 0x0a shift altgr -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+0 0x0b - equal 0x0b shift - braceright 0x0b altgr --ssharp 0x0c -+degree 0x0b shift altgr -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc -+apostrophe 0x0c - question 0x0c shift --backslash 0x0c altgr -+dead_acute 0x0c altgr - questiondown 0x0c shift altgr --acute 0x0d --dead_acute 0x0d --grave 0x0d shift -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd -+dead_circumflex 0x0d - dead_grave 0x0d shift --dead_cedilla 0x0d altgr -+dead_tilde 0x0d altgr - dead_ogonek 0x0d shift altgr -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+q 0x10 -+Q 0x10 shift - at 0x10 altgr - Greek_OMEGA 0x10 shift altgr -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+w 0x11 -+W 0x11 shift -+lstroke 0x11 altgr -+Lstroke 0x11 shift altgr -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+e 0x12 -+E 0x12 shift - EuroSign 0x12 altgr -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+r 0x13 -+R 0x13 shift - paragraph 0x13 altgr - registered 0x13 shift altgr -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+t 0x14 -+T 0x14 shift - tslash 0x14 altgr - Tslash 0x14 shift altgr --z 0x15 addupper -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+z 0x15 -+Z 0x15 shift - leftarrow 0x15 altgr - yen 0x15 shift altgr -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+u 0x16 -+U 0x16 shift - downarrow 0x16 altgr - uparrow 0x16 shift altgr -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+i 0x17 -+I 0x17 shift - rightarrow 0x17 altgr - idotless 0x17 shift altgr --oslash 0x18 altgr --Ooblique 0x18 shift altgr -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+o 0x18 -+O 0x18 shift -+oe 0x18 altgr -+OE 0x18 shift altgr -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+p 0x19 -+P 0x19 shift - thorn 0x19 altgr - THORN 0x19 shift altgr --udiaeresis 0x1a --Udiaeresis 0x1a shift --dead_diaeresis 0x1a altgr -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a -+egrave 0x1a -+udiaeresis 0x1a shift -+bracketleft 0x1a altgr - dead_abovering 0x1a shift altgr --plus 0x1b --asterisk 0x1b shift --asciitilde 0x1b altgr --dead_tilde 0x1b altgr -+ -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b -+dead_diaeresis 0x1b -+exclam 0x1b shift -+bracketright 0x1b altgr - dead_macron 0x1b shift altgr -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+a 0x1e -+A 0x1e shift - ae 0x1e altgr - AE 0x1e shift altgr -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+s 0x1f -+S 0x1f shift -+ssharp 0x1f altgr -+section 0x1f shift altgr -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+d 0x20 -+D 0x20 shift - eth 0x20 altgr - ETH 0x20 shift altgr -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+f 0x21 -+F 0x21 shift - dstroke 0x21 altgr - ordfeminine 0x21 shift altgr -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+g 0x22 -+G 0x22 shift - eng 0x22 altgr - ENG 0x22 shift altgr -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+h 0x23 -+H 0x23 shift - hstroke 0x23 altgr - Hstroke 0x23 shift altgr -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+j 0x24 -+J 0x24 shift -+dead_hook 0x24 altgr -+dead_horn 0x24 shift altgr -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+k 0x25 -+K 0x25 shift - kra 0x25 altgr --odiaeresis 0x27 --Odiaeresis 0x27 shift --dead_doubleacute 0x27 altgr --adiaeresis 0x28 --Adiaeresis 0x28 shift -+ampersand 0x25 shift altgr -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+l 0x26 -+L 0x26 shift -+lstroke 0x26 altgr -+Lstroke 0x26 shift altgr -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 -+eacute 0x27 -+odiaeresis 0x27 shift -+dead_acute 0x27 altgr -+dead_doubleacute 0x27 shift altgr -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 -+agrave 0x28 -+adiaeresis 0x28 shift -+braceleft 0x28 altgr - dead_caron 0x28 shift altgr --asciicircum 0x29 --dead_circumflex 0x29 -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 -+section 0x29 - degree 0x29 shift - notsign 0x29 altgr --numbersign 0x2b --apostrophe 0x2b shift -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b -+dollar 0x2b -+sterling 0x2b shift -+braceright 0x2b altgr - dead_breve 0x2b shift altgr --y 0x2c addupper -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+y 0x2c -+Y 0x2c shift - guillemotleft 0x2c altgr -+less 0x2c shift altgr -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+x 0x2d -+X 0x2d shift - guillemotright 0x2d altgr -+greater 0x2d shift altgr -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+c 0x2e -+C 0x2e shift - cent 0x2e altgr - copyright 0x2e shift altgr -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+v 0x2f -+V 0x2f shift - leftdoublequotemark 0x2f altgr -+leftsinglequotemark 0x2f shift altgr -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+b 0x30 -+B 0x30 shift - rightdoublequotemark 0x30 altgr -+rightsinglequotemark 0x30 shift altgr -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+n 0x31 -+N 0x31 shift -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+m 0x32 -+M 0x32 shift - mu 0x32 altgr - masculine 0x32 shift altgr -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 - comma 0x33 - semicolon 0x33 shift - horizconnector 0x33 altgr - multiply 0x33 shift altgr -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 - period 0x34 - colon 0x34 shift - periodcentered 0x34 altgr - division 0x34 shift altgr -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 - minus 0x35 - underscore 0x35 shift - dead_belowdot 0x35 altgr - dead_abovedot 0x35 shift altgr -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Decimal 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 -+less 0x56 -+greater 0x56 shift -+backslash 0x56 altgr -+brokenbar 0x56 shift altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+ISO_Level3_Shift 0xb8 -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/hr b/pc-bios/keymaps/hr -index 613aa69..6b89f09 100644 ---- a/pc-bios/keymaps/hr -+++ b/pc-bios/keymaps/hr -@@ -1,125 +1,837 @@ --# generated from XKB map hr --include common --map 0x41a -+# -+# generated by qemu-keymap -+# model : pc105 -+# layout : hr -+# variant : - -+# options : - -+ -+# name: "Croatian" -+ -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+1 0x02 - exclam 0x02 shift - asciitilde 0x02 altgr - dead_tilde 0x02 shift altgr -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+2 0x03 - quotedbl 0x03 shift - dead_caron 0x03 altgr - caron 0x03 shift altgr -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+3 0x04 - numbersign 0x04 shift - asciicircum 0x04 altgr - dead_circumflex 0x04 shift altgr -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+4 0x05 - dollar 0x05 shift - dead_breve 0x05 altgr - breve 0x05 shift altgr -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+5 0x06 - percent 0x06 shift - degree 0x06 altgr - dead_abovering 0x06 shift altgr -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+6 0x07 - ampersand 0x07 shift - dead_ogonek 0x07 altgr - ogonek 0x07 shift altgr -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+7 0x08 - slash 0x08 shift - grave 0x08 altgr - dead_grave 0x08 shift altgr -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+8 0x09 - parenleft 0x09 shift - dead_abovedot 0x09 altgr - abovedot 0x09 shift altgr -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+9 0x0a - parenright 0x0a shift - dead_acute 0x0a altgr - apostrophe 0x0a shift altgr -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+0 0x0b - equal 0x0b shift - dead_doubleacute 0x0b altgr - doubleacute 0x0b shift altgr -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc - apostrophe 0x0c - question 0x0c shift - dead_diaeresis 0x0c altgr - diaeresis 0x0c shift altgr -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd - plus 0x0d - asterisk 0x0d shift - dead_cedilla 0x0d altgr - cedilla 0x0d shift altgr -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+q 0x10 -+Q 0x10 shift - backslash 0x10 altgr - Greek_OMEGA 0x10 shift altgr -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+w 0x11 -+W 0x11 shift - bar 0x11 altgr - Lstroke 0x11 shift altgr -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+e 0x12 -+E 0x12 shift - EuroSign 0x12 altgr -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+r 0x13 -+R 0x13 shift - paragraph 0x13 altgr - registered 0x13 shift altgr -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+t 0x14 -+T 0x14 shift - tslash 0x14 altgr - Tslash 0x14 shift altgr --z 0x15 addupper -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+z 0x15 -+Z 0x15 shift - leftarrow 0x15 altgr - yen 0x15 shift altgr -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+u 0x16 -+U 0x16 shift - downarrow 0x16 altgr - uparrow 0x16 shift altgr -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+i 0x17 -+I 0x17 shift - rightarrow 0x17 altgr - idotless 0x17 shift altgr -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+o 0x18 -+O 0x18 shift - oslash 0x18 altgr --Ooblique 0x18 shift altgr -+Oslash 0x18 shift altgr -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+p 0x19 -+P 0x19 shift - thorn 0x19 altgr - THORN 0x19 shift altgr -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a - scaron 0x1a - Scaron 0x1a shift - division 0x1a altgr - dead_abovering 0x1a shift altgr -+ -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b - dstroke 0x1b - Dstroke 0x1b shift - multiply 0x1b altgr - dead_macron 0x1b shift altgr -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+a 0x1e -+A 0x1e shift - ae 0x1e altgr - AE 0x1e shift altgr --ssharp 0x1f altgr --section 0x1f shift altgr --eth 0x20 altgr --ETH 0x20 shift altgr -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+s 0x1f -+S 0x1f shift -+doublelowquotemark 0x1f altgr -+guillemotright 0x1f shift altgr -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+d 0x20 -+D 0x20 shift -+leftdoublequotemark 0x20 altgr -+guillemotleft 0x20 shift altgr -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+f 0x21 -+F 0x21 shift - bracketleft 0x21 altgr - ordfeminine 0x21 shift altgr -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+g 0x22 -+G 0x22 shift - bracketright 0x22 altgr - ENG 0x22 shift altgr -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+h 0x23 -+H 0x23 shift - hstroke 0x23 altgr - Hstroke 0x23 shift altgr -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+j 0x24 -+J 0x24 shift -+dead_hook 0x24 altgr -+dead_horn 0x24 shift altgr -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+k 0x25 -+K 0x25 shift - lstroke 0x25 altgr - ampersand 0x25 shift altgr --Lstroke 0x26 altgr -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+l 0x26 -+L 0x26 shift -+lstroke 0x26 altgr -+Lstroke 0x26 shift altgr -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 - ccaron 0x27 - Ccaron 0x27 shift - dead_acute 0x27 altgr - dead_doubleacute 0x27 shift altgr -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 - cacute 0x28 - Cacute 0x28 shift - ssharp 0x28 altgr - dead_caron 0x28 shift altgr --dead_cedilla 0x29 --dead_diaeresis 0x29 shift -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 -+grave 0x29 -+asciitilde 0x29 shift - notsign 0x29 altgr -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b - zcaron 0x2b - Zcaron 0x2b shift - currency 0x2b altgr - dead_breve 0x2b shift altgr --y 0x2c addupper --guillemotleft 0x2c altgr --less 0x2c shift altgr --guillemotright 0x2d altgr --greater 0x2d shift altgr -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+y 0x2c -+Y 0x2c shift -+leftsinglequotemark 0x2c altgr -+guillemotright 0x2c shift altgr -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+x 0x2d -+X 0x2d shift -+rightsinglequotemark 0x2d altgr -+guillemotleft 0x2d shift altgr -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+c 0x2e -+C 0x2e shift - cent 0x2e altgr - copyright 0x2e shift altgr -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+v 0x2f -+V 0x2f shift - at 0x2f altgr - grave 0x2f shift altgr -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+b 0x30 -+B 0x30 shift - braceleft 0x30 altgr - apostrophe 0x30 shift altgr -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+n 0x31 -+N 0x31 shift - braceright 0x31 altgr --section 0x32 altgr -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+m 0x32 -+M 0x32 shift -+asciicircum 0x32 altgr - masculine 0x32 shift altgr -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 - comma 0x33 - semicolon 0x33 shift --horizconnector 0x33 altgr -+less 0x33 altgr - multiply 0x33 shift altgr -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 - period 0x34 - colon 0x34 shift --periodcentered 0x34 altgr -+greater 0x34 altgr - division 0x34 shift altgr -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 - minus 0x35 - underscore 0x35 shift - dead_belowdot 0x35 altgr - dead_abovedot 0x35 shift altgr -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Separator 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 -+less 0x56 -+greater 0x56 shift -+bar 0x56 altgr -+brokenbar 0x56 shift altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+ISO_Level3_Shift 0xb8 -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/hu b/pc-bios/keymaps/hu -index 8aba444..a6bd66d 100644 ---- a/pc-bios/keymaps/hu -+++ b/pc-bios/keymaps/hu -@@ -1,115 +1,836 @@ --# Hungarian keyboard layout (QWERTZ) --# Created by: The NeverGone -+# -+# generated by qemu-keymap -+# model : pc105 -+# layout : hu -+# variant : - -+# options : - - --include common --map 0x40e -+# name: "Hungarian" - -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper - --# AltGr keys: --notsign 0x29 altgr -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+1 0x02 -+apostrophe 0x02 shift - asciitilde 0x02 altgr --caron 0x03 altgr -+dead_tilde 0x02 shift altgr -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+2 0x03 -+quotedbl 0x03 shift -+dead_caron 0x03 altgr -+caron 0x03 shift altgr -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+3 0x04 -+plus 0x04 shift - asciicircum 0x04 altgr --breve 0x05 altgr --degree 0x06 altgr --ogonek 0x07 altgr -+dead_circumflex 0x04 shift altgr -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+4 0x05 -+exclam 0x05 shift -+dead_breve 0x05 altgr -+breve 0x05 shift altgr -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+5 0x06 -+percent 0x06 shift -+dead_abovering 0x06 altgr -+degree 0x06 shift altgr -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+6 0x07 -+slash 0x07 shift -+dead_ogonek 0x07 altgr -+ogonek 0x07 shift altgr -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+7 0x08 -+equal 0x08 shift - grave 0x08 altgr --abovedot 0x09 altgr --acute 0x0a altgr --doubleacute 0x0b altgr --diaeresis 0x0c altgr --cedilla 0x0d altgr -+dead_grave 0x08 shift altgr -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+8 0x09 -+parenleft 0x09 shift -+dead_abovedot 0x09 altgr -+abovedot 0x09 shift altgr -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+9 0x0a -+parenright 0x0a shift -+dead_acute 0x0a altgr -+acute 0x0a shift altgr -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+odiaeresis 0x0b -+Odiaeresis 0x0b shift -+dead_doubleacute 0x0b altgr -+doubleacute 0x0b shift altgr -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc -+udiaeresis 0x0c -+Udiaeresis 0x0c shift -+dead_diaeresis 0x0c altgr -+diaeresis 0x0c shift altgr -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd -+oacute 0x0d -+Oacute 0x0d shift -+dead_cedilla 0x0d altgr -+cedilla 0x0d shift altgr -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+q 0x10 -+Q 0x10 shift - backslash 0x10 altgr -+Greek_OMEGA 0x10 shift altgr -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+w 0x11 -+W 0x11 shift - bar 0x11 altgr --EuroSign 0x12 altgr -+Lstroke 0x11 shift altgr -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+e 0x12 -+E 0x12 shift -+Adiaeresis 0x12 altgr -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+r 0x13 -+R 0x13 shift -+paragraph 0x13 altgr -+registered 0x13 shift altgr -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+t 0x14 -+T 0x14 shift -+tslash 0x14 altgr -+Tslash 0x14 shift altgr -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+z 0x15 -+Z 0x15 shift -+endash 0x15 altgr -+yen 0x15 shift altgr -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+u 0x16 -+U 0x16 shift -+EuroSign 0x16 altgr -+uparrow 0x16 shift altgr -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+i 0x17 -+I 0x17 shift - Iacute 0x17 altgr -+iacute 0x17 shift altgr -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+o 0x18 -+O 0x18 shift -+doublelowquotemark 0x18 altgr -+Oslash 0x18 shift altgr -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+p 0x19 -+P 0x19 shift -+rightdoublequotemark 0x19 altgr -+THORN 0x19 shift altgr -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a -+odoubleacute 0x1a -+Odoubleacute 0x1a shift - division 0x1a altgr -+dead_abovering 0x1a shift altgr -+ -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b -+uacute 0x1b -+Uacute 0x1b shift - multiply 0x1b altgr -+dead_macron 0x1b shift altgr -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+a 0x1e -+A 0x1e shift -+adiaeresis 0x1e altgr -+Adiaeresis 0x1e shift altgr -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+s 0x1f -+S 0x1f shift - dstroke 0x1f altgr -+section 0x1f shift altgr -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+d 0x20 -+D 0x20 shift - Dstroke 0x20 altgr -+ETH 0x20 shift altgr -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+f 0x21 -+F 0x21 shift - bracketleft 0x21 altgr -+ordfeminine 0x21 shift altgr -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+g 0x22 -+G 0x22 shift - bracketright 0x22 altgr -+ENG 0x22 shift altgr -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+h 0x23 -+H 0x23 shift -+hstroke 0x23 altgr -+Hstroke 0x23 shift altgr -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+j 0x24 -+J 0x24 shift - iacute 0x24 altgr -+Iacute 0x24 shift altgr -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+k 0x25 -+K 0x25 shift - lstroke 0x25 altgr -+ampersand 0x25 shift altgr -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+l 0x26 -+L 0x26 shift - Lstroke 0x26 altgr -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 -+eacute 0x27 -+Eacute 0x27 shift - dollar 0x27 altgr -+cent 0x27 shift altgr -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 -+aacute 0x28 -+Aacute 0x28 shift - ssharp 0x28 altgr -+dead_caron 0x28 shift altgr -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 -+0 0x29 -+section 0x29 shift -+notsign 0x29 altgr -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b -+udoubleacute 0x2b -+Udoubleacute 0x2b shift - currency 0x2b altgr --less 0x56 altgr -+dead_breve 0x2b shift altgr -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+y 0x2c -+Y 0x2c shift - greater 0x2c altgr -+less 0x2c shift altgr -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+x 0x2d -+X 0x2d shift - numbersign 0x2d altgr -+greater 0x2d shift altgr -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+c 0x2e -+C 0x2e shift - ampersand 0x2e altgr -+copyright 0x2e shift altgr -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+v 0x2f -+V 0x2f shift - at 0x2f altgr -+leftsinglequotemark 0x2f shift altgr -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+b 0x30 -+B 0x30 shift - braceleft 0x30 altgr -+rightsinglequotemark 0x30 shift altgr -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+n 0x31 -+N 0x31 shift - braceright 0x31 altgr --semicolon 0x33 altgr --asterisk 0x35 altgr - -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+m 0x32 -+M 0x32 shift -+less 0x32 altgr -+masculine 0x32 shift altgr - --# Shift keys: --section 0x29 shift --apostrophe 0x02 shift --quotedbl 0x03 shift --plus 0x04 shift --exclam 0x05 shift --percent 0x06 shift --slash 0x07 shift --equal 0x08 shift --parenleft 0x09 shift --parenright 0x0a shift --Odiaeresis 0x0b shift --Udiaeresis 0x0c shift --Oacute 0x0d shift --Z 0x15 shift --Odoubleacute 0x1a shift --Uacute 0x1b shift --Eacute 0x27 shift --Aacute 0x28 shift --Udoubleacute 0x2b shift --Y 0x2c shift -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 -+comma 0x33 - question 0x33 shift -+semicolon 0x33 altgr -+multiply 0x33 shift altgr -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 -+period 0x34 - colon 0x34 shift -+greater 0x34 altgr -+division 0x34 shift altgr -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 -+minus 0x35 - underscore 0x35 shift --F13 0x3b shift --F14 0x3c shift --F15 0x3d shift --F16 0x3e shift --F17 0x3f shift --F18 0x40 shift --F19 0x41 shift --F20 0x42 shift --F21 0x43 shift --F22 0x44 shift --F23 0x57 shift --F24 0x58 shift -- -- --# Ctrl keys: --F25 0x3b ctrl --F26 0x3c ctrl --F27 0x3d ctrl --F28 0x3e ctrl --F29 0x3f ctrl --F30 0x40 ctrl --F31 0x41 ctrl --F32 0x42 ctrl --F33 0x43 ctrl --F34 0x44 ctrl --F35 0x57 ctrl --#NoSymbol 0x58 ctrl -+asterisk 0x35 altgr -+dead_abovedot 0x35 shift altgr - -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 - --0 0x29 --odiaeresis 0x0b --udiaeresis 0x0c --oacute 0x0d --z 0x15 --odoubleacute 0x1a --uacute 0x1b --eacute 0x27 --aacute 0x28 --udoubleacute 0x2b --y 0x2c --comma 0x33 --period 0x34 --minus 0x35 -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Separator 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 -+iacute 0x56 -+Iacute 0x56 shift -+less 0x56 altgr -+greater 0x56 shift altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+ISO_Level3_Shift 0xb8 -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/is b/pc-bios/keymaps/is -index 935ac1d..063675d 100644 ---- a/pc-bios/keymaps/is -+++ b/pc-bios/keymaps/is -@@ -1,139 +1,837 @@ --# 2004-03-16 Halldór Guðmundsson and Morten Lange --# Keyboard definition file for the Icelandic keyboard --# to be used in rdesktop 1.3.x ( See rdesktop.org) --# generated from XKB map de, and changed manually --# Location for example /usr/local/share/rdesktop/keymaps/is --include common --map 0x40f -+# -+# generated by qemu-keymap -+# model : pc105 -+# layout : is -+# variant : - -+# options : - -+ -+# name: "Icelandic" -+ -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+1 0x02 - exclam 0x02 shift - onesuperior 0x02 altgr - exclamdown 0x02 shift altgr -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+2 0x03 - quotedbl 0x03 shift - twosuperior 0x03 altgr - oneeighth 0x03 shift altgr --#section 0x04 shift -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+3 0x04 - numbersign 0x04 shift - threesuperior 0x04 altgr - sterling 0x04 shift altgr -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+4 0x05 - dollar 0x05 shift - onequarter 0x05 altgr - currency 0x05 shift altgr -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+5 0x06 - percent 0x06 shift - onehalf 0x06 altgr - threeeighths 0x06 shift altgr -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+6 0x07 - ampersand 0x07 shift --threequarters 0x07 altgr -+notsign 0x07 altgr - fiveeighths 0x07 shift altgr -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+7 0x08 - slash 0x08 shift - braceleft 0x08 altgr - seveneighths 0x08 shift altgr -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+8 0x09 - parenleft 0x09 shift - bracketleft 0x09 altgr - trademark 0x09 shift altgr -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+9 0x0a - parenright 0x0a shift - bracketright 0x0a altgr - plusminus 0x0a shift altgr -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+0 0x0b - equal 0x0b shift - braceright 0x0b altgr --#ssharp 0x0c -+degree 0x0b shift altgr -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc - odiaeresis 0x0c --#question 0x0c shift - Odiaeresis 0x0c shift - backslash 0x0c altgr - questiondown 0x0c shift altgr --#acute 0x0d --minus 0x0d --#dead_acute 0x0d --#grave 0x0d shift --#dead_grave 0x0d shift -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd -+minus 0x0d - underscore 0x0d shift - dead_cedilla 0x0d altgr - dead_ogonek 0x0d shift altgr -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+q 0x10 -+Q 0x10 shift - at 0x10 altgr - Greek_OMEGA 0x10 shift altgr -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+w 0x11 -+W 0x11 shift -+lstroke 0x11 altgr -+Lstroke 0x11 shift altgr -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+e 0x12 -+E 0x12 shift - EuroSign 0x12 altgr -+cent 0x12 shift altgr -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+r 0x13 -+R 0x13 shift - paragraph 0x13 altgr - registered 0x13 shift altgr -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+t 0x14 -+T 0x14 shift - tslash 0x14 altgr - Tslash 0x14 shift altgr --#z 0x15 addupper -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+y 0x15 -+Y 0x15 shift - leftarrow 0x15 altgr - yen 0x15 shift altgr -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+u 0x16 -+U 0x16 shift - downarrow 0x16 altgr - uparrow 0x16 shift altgr -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+i 0x17 -+I 0x17 shift - rightarrow 0x17 altgr - idotless 0x17 shift altgr -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+o 0x18 -+O 0x18 shift - oslash 0x18 altgr --Ooblique 0x18 shift altgr --#thorn 0x19 altgr --#THORN 0x19 shift altgr --#udiaeresis 0x1a --#Udiaeresis 0x1a shift --#dead_diaeresis 0x1a altgr --#dead_abovering 0x1a shift altgr -+Oslash 0x18 shift altgr -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+p 0x19 -+P 0x19 shift -+thorn 0x19 altgr -+THORN 0x19 shift altgr -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a - eth 0x1a - ETH 0x1a shift -+dead_diaeresis 0x1a altgr -+dead_abovering 0x1a shift altgr -+ -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b - apostrophe 0x1b - question 0x1b shift --#plus 0x1b --#asterisk 0x1b shift - asciitilde 0x1b altgr --#grave 0x1b altgr --#dead_tilde 0x1b altgr --#dead_macron 0x1b shift altgr --#ae 0x1e altgr --#AE 0x1e shift altgr --#eth 0x20 altgr --#eth 0x20 --#ETH 0x20 shift altgr --#ETH 0x20 shift -+dead_macron 0x1b shift altgr -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+a 0x1e -+A 0x1e shift -+ae 0x1e altgr -+AE 0x1e shift altgr -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+s 0x1f -+S 0x1f shift -+ssharp 0x1f altgr -+section 0x1f shift altgr -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+d 0x20 -+D 0x20 shift -+U201E 0x20 altgr -+U201C 0x20 shift altgr -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+f 0x21 -+F 0x21 shift - dstroke 0x21 altgr - ordfeminine 0x21 shift altgr -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+g 0x22 -+G 0x22 shift - eng 0x22 altgr - ENG 0x22 shift altgr -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+h 0x23 -+H 0x23 shift - hstroke 0x23 altgr - Hstroke 0x23 shift altgr -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+j 0x24 -+J 0x24 shift -+dead_hook 0x24 altgr -+dead_horn 0x24 shift altgr -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+k 0x25 -+K 0x25 shift - kra 0x25 altgr --#adiaeresis 0x27 --#Adiaeresis 0x27 shift -+ampersand 0x25 shift altgr -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+l 0x26 -+L 0x26 shift -+lstroke 0x26 altgr -+Lstroke 0x26 shift altgr -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 - ae 0x27 - AE 0x27 shift --dead_doubleacute 0x27 altgr --#adiaeresis 0x28 --#Adiaeresis 0x28 shift --#dead_caron 0x28 shift altgr --#asciicircum 0x29 --acute 0x28 -+asciicircum 0x27 altgr -+dead_doubleacute 0x27 shift altgr -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 - dead_acute 0x28 --#dead_circumflex 0x29 --#degree 0x29 shift --#notsign 0x29 altgr -+dead_circumflex 0x28 altgr -+dead_caron 0x28 shift altgr -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 -+dead_abovering 0x29 -+dead_diaeresis 0x29 shift -+notsign 0x29 altgr -+hyphen 0x29 shift altgr -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b - plus 0x2b - asterisk 0x2b shift - grave 0x2b altgr --#numbersign 0x2b --#apostrophe 0x2b shift --#dead_breve 0x2b shift altgr --#y 0x2c addupper -+dead_breve 0x2b shift altgr -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+z 0x2c -+Z 0x2c shift - guillemotleft 0x2c altgr -+less 0x2c shift altgr -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+x 0x2d -+X 0x2d shift - guillemotright 0x2d altgr -+greater 0x2d shift altgr -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+c 0x2e -+C 0x2e shift - cent 0x2e altgr - copyright 0x2e shift altgr -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+v 0x2f -+V 0x2f shift - leftdoublequotemark 0x2f altgr -+leftsinglequotemark 0x2f shift altgr -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+b 0x30 -+B 0x30 shift - rightdoublequotemark 0x30 altgr -+rightsinglequotemark 0x30 shift altgr -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+n 0x31 -+N 0x31 shift -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+m 0x32 -+M 0x32 shift - mu 0x32 altgr - masculine 0x32 shift altgr -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 - comma 0x33 - semicolon 0x33 shift - horizconnector 0x33 altgr - multiply 0x33 shift altgr -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 - period 0x34 - colon 0x34 shift - periodcentered 0x34 altgr - division 0x34 shift altgr --#minus 0x35 --#underscore 0x35 shift -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 - thorn 0x35 - THORN 0x35 shift - dead_belowdot 0x35 altgr - dead_abovedot 0x35 shift altgr -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Decimal 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 -+less 0x56 -+greater 0x56 shift -+bar 0x56 altgr -+brokenbar 0x56 shift altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+ISO_Level3_Shift 0xb8 -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/it b/pc-bios/keymaps/it -index 00ca73a..abc3ed1 100644 ---- a/pc-bios/keymaps/it -+++ b/pc-bios/keymaps/it -@@ -1,115 +1,840 @@ --# generated from XKB map it --include common --map 0x410 -+# -+# generated by qemu-keymap -+# model : pc105 -+# layout : it -+# variant : - -+# options : - -+ -+# name: "Italian" -+ -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+1 0x02 - exclam 0x02 shift - onesuperior 0x02 altgr - exclamdown 0x02 shift altgr -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+2 0x03 - quotedbl 0x03 shift - twosuperior 0x03 altgr --oneeighth 0x03 shift altgr -+dead_doubleacute 0x03 shift altgr -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+3 0x04 - sterling 0x04 shift - threesuperior 0x04 altgr -+dead_tilde 0x04 shift altgr -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+4 0x05 - dollar 0x05 shift - onequarter 0x05 altgr -+oneeighth 0x05 shift altgr -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+5 0x06 - percent 0x06 shift - onehalf 0x06 altgr - threeeighths 0x06 shift altgr -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+6 0x07 - ampersand 0x07 shift --threequarters 0x07 altgr -+notsign 0x07 altgr - fiveeighths 0x07 shift altgr -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+7 0x08 - slash 0x08 shift - braceleft 0x08 altgr - seveneighths 0x08 shift altgr -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+8 0x09 - parenleft 0x09 shift -+bracketleft 0x09 altgr - trademark 0x09 shift altgr -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+9 0x0a - parenright 0x0a shift -+bracketright 0x0a altgr - plusminus 0x0a shift altgr -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+0 0x0b - equal 0x0b shift - braceright 0x0b altgr --degree 0x0b shift altgr -+dead_ogonek 0x0b shift altgr -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc - apostrophe 0x0c - question 0x0c shift - grave 0x0c altgr - questiondown 0x0c shift altgr -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd - igrave 0x0d - asciicircum 0x0d shift - asciitilde 0x0d altgr --dead_ogonek 0x0d shift altgr -+dead_circumflex 0x0d shift altgr -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+q 0x10 -+Q 0x10 shift - at 0x10 altgr - Greek_OMEGA 0x10 shift altgr -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+w 0x11 -+W 0x11 shift - lstroke 0x11 altgr - Lstroke 0x11 shift altgr -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+e 0x12 -+E 0x12 shift - EuroSign 0x12 altgr - cent 0x12 shift altgr -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+r 0x13 -+R 0x13 shift - paragraph 0x13 altgr - registered 0x13 shift altgr -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+t 0x14 -+T 0x14 shift - tslash 0x14 altgr - Tslash 0x14 shift altgr -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+y 0x15 -+Y 0x15 shift - leftarrow 0x15 altgr - yen 0x15 shift altgr -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+u 0x16 -+U 0x16 shift - downarrow 0x16 altgr - uparrow 0x16 shift altgr -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+i 0x17 -+I 0x17 shift - rightarrow 0x17 altgr - idotless 0x17 shift altgr -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+o 0x18 -+O 0x18 shift - oslash 0x18 altgr --Ooblique 0x18 shift altgr -+Oslash 0x18 shift altgr -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+p 0x19 -+P 0x19 shift - thorn 0x19 altgr - THORN 0x19 shift altgr -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a - egrave 0x1a - eacute 0x1a shift - bracketleft 0x1a altgr --dead_abovering 0x1a shift altgr -+braceleft 0x1a shift altgr -+ -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b - plus 0x1b - asterisk 0x1b shift - bracketright 0x1b altgr --dead_macron 0x1b shift altgr -+braceright 0x1b shift altgr -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+a 0x1e -+A 0x1e shift - ae 0x1e altgr - AE 0x1e shift altgr -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+s 0x1f -+S 0x1f shift - ssharp 0x1f altgr - section 0x1f shift altgr -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+d 0x20 -+D 0x20 shift - eth 0x20 altgr - ETH 0x20 shift altgr -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+f 0x21 -+F 0x21 shift - dstroke 0x21 altgr - ordfeminine 0x21 shift altgr -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+g 0x22 -+G 0x22 shift - eng 0x22 altgr - ENG 0x22 shift altgr -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+h 0x23 -+H 0x23 shift - hstroke 0x23 altgr - Hstroke 0x23 shift altgr -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+j 0x24 -+J 0x24 shift -+dead_hook 0x24 altgr -+dead_horn 0x24 shift altgr -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+k 0x25 -+K 0x25 shift - kra 0x25 altgr -+ampersand 0x25 shift altgr -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+l 0x26 -+L 0x26 shift - lstroke 0x26 altgr - Lstroke 0x26 shift altgr -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 - ograve 0x27 - ccedilla 0x27 shift - at 0x27 altgr --dead_doubleacute 0x27 shift altgr -+dead_cedilla 0x27 shift altgr -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 - agrave 0x28 - degree 0x28 shift - numbersign 0x28 altgr -+dead_abovering 0x28 shift altgr -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 - backslash 0x29 - bar 0x29 shift - notsign 0x29 altgr -+brokenbar 0x29 shift altgr -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b - ugrave 0x2b - section 0x2b shift - dead_grave 0x2b altgr - dead_breve 0x2b shift altgr -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+z 0x2c -+Z 0x2c shift - guillemotleft 0x2c altgr -+less 0x2c shift altgr -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+x 0x2d -+X 0x2d shift - guillemotright 0x2d altgr -+greater 0x2d shift altgr -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+c 0x2e -+C 0x2e shift - cent 0x2e altgr - copyright 0x2e shift altgr -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+v 0x2f -+V 0x2f shift - leftdoublequotemark 0x2f altgr --grave 0x2f shift altgr -+leftsinglequotemark 0x2f shift altgr -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+b 0x30 -+B 0x30 shift - rightdoublequotemark 0x30 altgr -+rightsinglequotemark 0x30 shift altgr -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+n 0x31 -+N 0x31 shift -+ntilde 0x31 altgr -+Ntilde 0x31 shift altgr -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+m 0x32 -+M 0x32 shift - mu 0x32 altgr - masculine 0x32 shift altgr -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 - comma 0x33 - semicolon 0x33 shift --horizconnector 0x33 altgr -+dead_acute 0x33 altgr - multiply 0x33 shift altgr -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 - period 0x34 - colon 0x34 shift - periodcentered 0x34 altgr --division 0x34 shift altgr -+dead_diaeresis 0x34 shift altgr -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 - minus 0x35 - underscore 0x35 shift --dead_belowdot 0x35 altgr --dead_abovedot 0x35 shift altgr -+dead_macron 0x35 altgr -+division 0x35 shift altgr -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Decimal 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 -+less 0x56 -+greater 0x56 shift -+guillemotleft 0x56 altgr -+guillemotright 0x56 shift altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+ISO_Level3_Shift 0xb8 -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/ja b/pc-bios/keymaps/ja -index 9d90a78..aae93e8 100644 ---- a/pc-bios/keymaps/ja -+++ b/pc-bios/keymaps/ja -@@ -1,109 +1,751 @@ --# generated from XKB map jp106 --include common --map 0x411 -+# -+# generated by qemu-keymap -+# model : jp106 -+# layout : jp -+# variant : - -+# options : - -+ -+# name: "Japanese" -+ -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+1 0x02 - exclam 0x02 shift --kana_NU 0x02 altgr -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+2 0x03 - quotedbl 0x03 shift --kana_FU 0x03 altgr -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+3 0x04 - numbersign 0x04 shift --kana_A 0x04 altgr --kana_a 0x04 shift altgr -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+4 0x05 - dollar 0x05 shift --kana_U 0x05 altgr --kana_u 0x05 shift altgr -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+5 0x06 - percent 0x06 shift --kana_E 0x06 altgr --kana_e 0x06 shift altgr -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+6 0x07 - ampersand 0x07 shift --kana_O 0x07 altgr --kana_o 0x07 shift altgr -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+7 0x08 - apostrophe 0x08 shift --kana_YA 0x08 altgr --kana_ya 0x08 shift altgr -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+8 0x09 - parenleft 0x09 shift --kana_YU 0x09 altgr --kana_yu 0x09 shift altgr -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+9 0x0a - parenright 0x0a shift --kana_YO 0x0a altgr --kana_yo 0x0a shift altgr -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+0 0x0b - asciitilde 0x0b shift --kana_WA 0x0b altgr --kana_WO 0x0b shift altgr -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc - minus 0x0c - equal 0x0c shift --kana_HO 0x0c altgr -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd - asciicircum 0x0d - asciitilde 0x0d shift --kana_HE 0x0d altgr --kana_TA 0x10 altgr --kana_TE 0x11 altgr --kana_I 0x12 altgr --kana_i 0x12 shift altgr --kana_SU 0x13 altgr --kana_KA 0x14 altgr --kana_N 0x15 altgr --kana_NA 0x16 altgr --kana_NI 0x17 altgr --kana_RA 0x18 altgr --kana_SE 0x19 altgr -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+q 0x10 -+Q 0x10 shift -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+w 0x11 -+W 0x11 shift -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+e 0x12 -+E 0x12 shift -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+r 0x13 -+R 0x13 shift -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+t 0x14 -+T 0x14 shift -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+y 0x15 -+Y 0x15 shift -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+u 0x16 -+U 0x16 shift -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+i 0x17 -+I 0x17 shift -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+o 0x18 -+O 0x18 shift -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+p 0x19 -+P 0x19 shift -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a - at 0x1a - grave 0x1a shift --voicedsound 0x1a altgr -+ -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b - bracketleft 0x1b - braceleft 0x1b shift --semivoicedsound 0x1b altgr --kana_openingbracket 0x1b shift altgr --kana_CHI 0x1e altgr --kana_TO 0x1f altgr --kana_SHI 0x20 altgr --kana_HA 0x21 altgr --kana_KI 0x22 altgr --kana_KU 0x23 altgr --kana_MA 0x24 altgr --kana_NO 0x25 altgr --kana_RI 0x26 altgr -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+a 0x1e -+A 0x1e shift -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+s 0x1f -+S 0x1f shift -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+d 0x20 -+D 0x20 shift -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+f 0x21 -+F 0x21 shift -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+g 0x22 -+G 0x22 shift -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+h 0x23 -+H 0x23 shift -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+j 0x24 -+J 0x24 shift -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+k 0x25 -+K 0x25 shift -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+l 0x26 -+L 0x26 shift -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 - semicolon 0x27 - plus 0x27 shift --kana_RE 0x27 altgr -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 - colon 0x28 - asterisk 0x28 shift --kana_KE 0x28 altgr -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 - Zenkaku_Hankaku 0x29 -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b - bracketright 0x2b - braceright 0x2b shift --kana_MU 0x2b altgr --kana_closingbracket 0x2b shift altgr --kana_TSU 0x2c altgr --kana_tsu 0x2c shift altgr --kana_SA 0x2d altgr --kana_SO 0x2e altgr --kana_HI 0x2f altgr --kana_KO 0x30 altgr --kana_MI 0x31 altgr --kana_MO 0x32 altgr -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+z 0x2c -+Z 0x2c shift -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+x 0x2d -+X 0x2d shift -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+c 0x2e -+C 0x2e shift -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+v 0x2f -+V 0x2f shift -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+b 0x30 -+B 0x30 shift -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+n 0x31 -+N 0x31 shift -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+m 0x32 -+M 0x32 shift -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 - comma 0x33 - less 0x33 shift --kana_NE 0x33 altgr --kana_comma 0x33 shift altgr -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 - period 0x34 - greater 0x34 shift --kana_RU 0x34 altgr --kana_fullstop 0x34 shift altgr -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 - slash 0x35 - question 0x35 shift --kana_ME 0x35 altgr --kana_conjunctive 0x35 shift altgr --Eisu_toggle 0x3a shift --Execute 0x54 shift --Kanji 0x70 -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Eisu_toggle 0x3a -+Caps_Lock 0x3a shift -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Decimal 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 -+less 0x56 -+greater 0x56 shift -+bar 0x56 altgr -+brokenbar 0x56 shift altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 - backslash 0x73 --yen 0x7d --bar 0x7d shift - underscore 0x73 shift -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 - Henkan_Mode 0x79 --Katakana_Real 0x70 --Katakana 0x70 --Muhenkan 0x7b --Henkan_Mode_Real 0x79 --Henkan_Mode_Ultra 0x79 --backslash_ja 0x73 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+Alt_R 0xb8 -+Meta_R 0xb8 shift -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+backslash 0x7d -+bar 0x7d shift -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/lt b/pc-bios/keymaps/lt -index 3d9d619..4101367 100644 ---- a/pc-bios/keymaps/lt -+++ b/pc-bios/keymaps/lt -@@ -1,57 +1,835 @@ --# generated from XKB map lt --include common --map 0x427 --exclam 0x02 shift --aogonek 0x02 altgr --Aogonek 0x02 shift altgr --at 0x03 shift --ccaron 0x03 altgr --Ccaron 0x03 shift altgr --numbersign 0x04 shift --eogonek 0x04 altgr --Eogonek 0x04 shift altgr --dollar 0x05 shift --eabovedot 0x05 altgr --Eabovedot 0x05 shift altgr --percent 0x06 shift --iogonek 0x06 altgr --Iogonek 0x06 shift altgr --asciicircum 0x07 shift --scaron 0x07 altgr --Scaron 0x07 shift altgr --ampersand 0x08 shift --uogonek 0x08 altgr --Uogonek 0x08 shift altgr --asterisk 0x09 shift --umacron 0x09 altgr --Umacron 0x09 shift altgr -+# -+# generated by qemu-keymap -+# model : pc105 -+# layout : lt -+# variant : - -+# options : - -+ -+# name: "Lithuanian" -+ -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+aogonek 0x02 -+Aogonek 0x02 shift -+1 0x02 altgr -+exclam 0x02 shift altgr -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+ccaron 0x03 -+Ccaron 0x03 shift -+2 0x03 altgr -+at 0x03 shift altgr -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+eogonek 0x04 -+Eogonek 0x04 shift -+3 0x04 altgr -+numbersign 0x04 shift altgr -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+eabovedot 0x05 -+Eabovedot 0x05 shift -+4 0x05 altgr -+dollar 0x05 shift altgr -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+iogonek 0x06 -+Iogonek 0x06 shift -+5 0x06 altgr -+percent 0x06 shift altgr -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+scaron 0x07 -+Scaron 0x07 shift -+6 0x07 altgr -+asciicircum 0x07 shift altgr -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+uogonek 0x08 -+Uogonek 0x08 shift -+7 0x08 altgr -+ampersand 0x08 shift altgr -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+umacron 0x09 -+Umacron 0x09 shift -+8 0x09 altgr -+asterisk 0x09 shift altgr -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+doublelowquotemark 0x0a - parenleft 0x0a shift --doublelowquotemark 0x0a altgr -+9 0x0a altgr -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+leftdoublequotemark 0x0b - parenright 0x0b shift --leftdoublequotemark 0x0b altgr -+0 0x0b altgr -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc - minus 0x0c - underscore 0x0c shift --equal 0x0d --plus 0x0d shift --zcaron 0x0d altgr --Zcaron 0x0d shift altgr -+endash 0x0c altgr -+questiondown 0x0c shift altgr -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd -+zcaron 0x0d -+Zcaron 0x0d shift -+equal 0x0d altgr -+plus 0x0d shift altgr -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+q 0x10 -+Q 0x10 shift -+at 0x10 altgr -+Greek_OMEGA 0x10 shift altgr -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+w 0x11 -+W 0x11 shift -+lstroke 0x11 altgr -+Lstroke 0x11 shift altgr -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+e 0x12 -+E 0x12 shift -+EuroSign 0x12 altgr -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+r 0x13 -+R 0x13 shift -+paragraph 0x13 altgr -+registered 0x13 shift altgr -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+t 0x14 -+T 0x14 shift -+tslash 0x14 altgr -+Tslash 0x14 shift altgr -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+y 0x15 -+Y 0x15 shift -+leftarrow 0x15 altgr -+yen 0x15 shift altgr -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+u 0x16 -+U 0x16 shift -+downarrow 0x16 altgr -+uparrow 0x16 shift altgr -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+i 0x17 -+I 0x17 shift -+rightarrow 0x17 altgr -+idotless 0x17 shift altgr -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+o 0x18 -+O 0x18 shift -+oslash 0x18 altgr -+Oslash 0x18 shift altgr -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+p 0x19 -+P 0x19 shift -+thorn 0x19 altgr -+THORN 0x19 shift altgr -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a - bracketleft 0x1a - braceleft 0x1a shift -+dead_diaeresis 0x1a altgr -+dead_abovering 0x1a shift altgr -+ -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b - bracketright 0x1b - braceright 0x1b shift -+dead_tilde 0x1b altgr -+dead_macron 0x1b shift altgr -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+a 0x1e -+A 0x1e shift -+ae 0x1e altgr -+AE 0x1e shift altgr -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+s 0x1f -+S 0x1f shift -+ssharp 0x1f altgr -+section 0x1f shift altgr -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+d 0x20 -+D 0x20 shift -+eth 0x20 altgr -+ETH 0x20 shift altgr -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+f 0x21 -+F 0x21 shift -+dstroke 0x21 altgr -+ordfeminine 0x21 shift altgr -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+g 0x22 -+G 0x22 shift -+eng 0x22 altgr -+ENG 0x22 shift altgr -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+h 0x23 -+H 0x23 shift -+hstroke 0x23 altgr -+Hstroke 0x23 shift altgr -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+j 0x24 -+J 0x24 shift -+dead_hook 0x24 altgr -+dead_horn 0x24 shift altgr -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+k 0x25 -+K 0x25 shift -+kra 0x25 altgr -+ampersand 0x25 shift altgr -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+l 0x26 -+L 0x26 shift -+lstroke 0x26 altgr -+Lstroke 0x26 shift altgr -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 - semicolon 0x27 - colon 0x27 shift -+dead_acute 0x27 altgr -+dead_doubleacute 0x27 shift altgr -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 - apostrophe 0x28 - quotedbl 0x28 shift -+dead_circumflex 0x28 altgr -+dead_caron 0x28 shift altgr -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 - grave 0x29 - asciitilde 0x29 shift -+acute 0x29 altgr -+notsign 0x29 shift altgr -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b - backslash 0x2b - bar 0x2b shift -+dead_grave 0x2b altgr -+dead_breve 0x2b shift altgr -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+z 0x2c -+Z 0x2c shift -+guillemotleft 0x2c altgr -+less 0x2c shift altgr -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+x 0x2d -+X 0x2d shift -+guillemotright 0x2d altgr -+greater 0x2d shift altgr -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+c 0x2e -+C 0x2e shift -+cent 0x2e altgr -+copyright 0x2e shift altgr -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+v 0x2f -+V 0x2f shift -+leftdoublequotemark 0x2f altgr -+leftsinglequotemark 0x2f shift altgr -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+b 0x30 -+B 0x30 shift -+rightdoublequotemark 0x30 altgr -+rightsinglequotemark 0x30 shift altgr -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+n 0x31 -+N 0x31 shift -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+m 0x32 -+M 0x32 shift -+mu 0x32 altgr -+masculine 0x32 shift altgr -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 - comma 0x33 - less 0x33 shift -+horizconnector 0x33 altgr -+multiply 0x33 shift altgr -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 - period 0x34 - greater 0x34 shift -+periodcentered 0x34 altgr -+division 0x34 shift altgr -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 - slash 0x35 - question 0x35 shift -+dead_belowdot 0x35 altgr -+dead_abovedot 0x35 shift altgr -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Decimal 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 - endash 0x56 - EuroSign 0x56 shift -+bar 0x56 altgr -+brokenbar 0x56 shift altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+ISO_Level3_Shift 0xb8 -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/lv b/pc-bios/keymaps/lv -index 1d91727..27260ce 100644 ---- a/pc-bios/keymaps/lv -+++ b/pc-bios/keymaps/lv -@@ -1,128 +1,810 @@ --# generated from XKB map lv --include common --map 0x426 -+# -+# generated by qemu-keymap -+# model : pc105 -+# layout : lv -+# variant : - -+# options : - -+ -+# name: "Latvian" -+ -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+1 0x02 - exclam 0x02 shift - onesuperior 0x02 altgr - exclamdown 0x02 shift altgr -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+2 0x03 - at 0x03 shift - twosuperior 0x03 altgr - oneeighth 0x03 shift altgr -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+3 0x04 - numbersign 0x04 shift - threesuperior 0x04 altgr - sterling 0x04 shift altgr -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+4 0x05 - dollar 0x05 shift - EuroSign 0x05 altgr - cent 0x05 shift altgr -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+5 0x06 - percent 0x06 shift - onehalf 0x06 altgr - threeeighths 0x06 shift altgr -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+6 0x07 - asciicircum 0x07 shift - threequarters 0x07 altgr - fiveeighths 0x07 shift altgr -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+7 0x08 - ampersand 0x08 shift - braceleft 0x08 altgr - seveneighths 0x08 shift altgr -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+8 0x09 - asterisk 0x09 shift - bracketleft 0x09 altgr - trademark 0x09 shift altgr -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+9 0x0a - parenleft 0x0a shift - bracketright 0x0a altgr - plusminus 0x0a shift altgr -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+0 0x0b - parenright 0x0b shift - braceright 0x0b altgr - degree 0x0b shift altgr -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc - minus 0x0c - underscore 0x0c shift - backslash 0x0c altgr - questiondown 0x0c shift altgr -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd - equal 0x0d - plus 0x0d shift --dead_cedilla 0x0d altgr --dead_ogonek 0x0d shift altgr --at 0x10 altgr --Greek_OMEGA 0x10 shift altgr --lstroke 0x11 altgr --Lstroke 0x11 shift altgr -+endash 0x0d altgr -+emdash 0x0d shift altgr -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+q 0x10 -+Q 0x10 shift -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+w 0x11 -+W 0x11 shift -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+e 0x12 -+E 0x12 shift - emacron 0x12 altgr - Emacron 0x12 shift altgr -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+r 0x13 -+R 0x13 shift - rcedilla 0x13 altgr - Rcedilla 0x13 shift altgr --tslash 0x14 altgr --Tslash 0x14 shift altgr --leftarrow 0x15 altgr --yen 0x15 shift altgr -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+t 0x14 -+T 0x14 shift -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+y 0x15 -+Y 0x15 shift -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+u 0x16 -+U 0x16 shift - umacron 0x16 altgr - Umacron 0x16 shift altgr -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+i 0x17 -+I 0x17 shift - imacron 0x17 altgr - Imacron 0x17 shift altgr -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+o 0x18 -+O 0x18 shift - omacron 0x18 altgr - Omacron 0x18 shift altgr --thorn 0x19 altgr --THORN 0x19 shift altgr -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+p 0x19 -+P 0x19 shift -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a - bracketleft 0x1a - braceleft 0x1a shift --dead_diaeresis 0x1a altgr --dead_abovering 0x1a shift altgr -+guillemotleft 0x1a altgr -+leftdoublequotemark 0x1a shift altgr -+ -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b - bracketright 0x1b - braceright 0x1b shift --dead_tilde 0x1b altgr --dead_macron 0x1b shift altgr --ISO_Next_Group 0x1c shift -+guillemotright 0x1b altgr -+rightdoublequotemark 0x1b shift altgr -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+a 0x1e -+A 0x1e shift - amacron 0x1e altgr - Amacron 0x1e shift altgr -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+s 0x1f -+S 0x1f shift - scaron 0x1f altgr - Scaron 0x1f shift altgr --eth 0x20 altgr --ETH 0x20 shift altgr --dstroke 0x21 altgr --ordfeminine 0x21 shift altgr -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+d 0x20 -+D 0x20 shift -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+f 0x21 -+F 0x21 shift -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+g 0x22 -+G 0x22 shift - gcedilla 0x22 altgr - Gcedilla 0x22 shift altgr --hstroke 0x23 altgr --Hstroke 0x23 shift altgr -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+h 0x23 -+H 0x23 shift -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+j 0x24 -+J 0x24 shift -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+k 0x25 -+K 0x25 shift - kcedilla 0x25 altgr - Kcedilla 0x25 shift altgr -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+l 0x26 -+L 0x26 shift - lcedilla 0x26 altgr - Lcedilla 0x26 shift altgr -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 - semicolon 0x27 - colon 0x27 shift --dead_acute 0x27 altgr --dead_doubleacute 0x27 shift altgr -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 - apostrophe 0x28 - quotedbl 0x28 shift - leftdoublequotemark 0x28 altgr - doublelowquotemark 0x28 shift altgr -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 - grave 0x29 - asciitilde 0x29 shift --notsign 0x29 altgr -+acute 0x29 altgr -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b - backslash 0x2b - bar 0x2b shift --dead_grave 0x2b altgr --dead_breve 0x2b shift altgr -+grave 0x2b altgr -+breve 0x2b shift altgr -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+z 0x2c -+Z 0x2c shift - zcaron 0x2c altgr - Zcaron 0x2c shift altgr --guillemotright 0x2d altgr --greater 0x2d shift altgr -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+x 0x2d -+X 0x2d shift -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+c 0x2e -+C 0x2e shift - ccaron 0x2e altgr - Ccaron 0x2e shift altgr --leftdoublequotemark 0x2f altgr --grave 0x2f shift altgr --rightdoublequotemark 0x30 altgr --apostrophe 0x30 shift altgr -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+v 0x2f -+V 0x2f shift -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+b 0x30 -+B 0x30 shift -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+n 0x31 -+N 0x31 shift - ncedilla 0x31 altgr - Ncedilla 0x31 shift altgr --mu 0x32 altgr --masculine 0x32 shift altgr -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+m 0x32 -+M 0x32 shift -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 - comma 0x33 - less 0x33 shift - horizconnector 0x33 altgr - multiply 0x33 shift altgr -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 - period 0x34 - greater 0x34 shift - periodcentered 0x34 altgr - division 0x34 shift altgr -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 - slash 0x35 - question 0x35 shift --dead_belowdot 0x35 altgr --dead_abovedot 0x35 shift altgr --nobreakspace 0x39 altgr -+abovedot 0x35 shift altgr -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Decimal 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 -+less 0x56 -+greater 0x56 shift -+bar 0x56 altgr -+brokenbar 0x56 shift altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+ISO_Level3_Shift 0xb8 -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/mk b/pc-bios/keymaps/mk -index 18c1504..30a597c 100644 ---- a/pc-bios/keymaps/mk -+++ b/pc-bios/keymaps/mk -@@ -1,101 +1,747 @@ --# generated from XKB map mk --include common --map 0x42f -+# -+# generated by qemu-keymap -+# model : pc105 -+# layout : mk -+# variant : - -+# options : - -+ -+# name: "Macedonian" -+ -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+1 0x02 - exclam 0x02 shift --at 0x03 shift --doublelowquotemark 0x03 shift altgr --numbersign 0x04 shift --leftdoublequotemark 0x04 shift altgr -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+2 0x03 -+doublelowquotemark 0x03 shift -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+3 0x04 -+leftdoublequotemark 0x04 shift -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+4 0x05 - dollar 0x05 shift -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+5 0x06 - percent 0x06 shift -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+6 0x07 - asciicircum 0x07 shift -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+7 0x08 - ampersand 0x08 shift -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+8 0x09 - asterisk 0x09 shift -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+9 0x0a - parenleft 0x0a shift -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+0 0x0b - parenright 0x0b shift -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc - minus 0x0c - underscore 0x0c shift -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd - equal 0x0d - plus 0x0d shift --Cyrillic_lje 0x10 altgr --Cyrillic_LJE 0x10 shift altgr --Cyrillic_nje 0x11 altgr --Cyrillic_NJE 0x11 shift altgr --Cyrillic_ie 0x12 altgr --Cyrillic_IE 0x12 shift altgr --Cyrillic_er 0x13 altgr --Cyrillic_ER 0x13 shift altgr --Cyrillic_te 0x14 altgr --Cyrillic_TE 0x14 shift altgr --Macedonia_dse 0x15 altgr --Macedonia_DSE 0x15 shift altgr --Cyrillic_u 0x16 altgr --Cyrillic_U 0x16 shift altgr --Cyrillic_i 0x17 altgr --Cyrillic_I 0x17 shift altgr --Cyrillic_o 0x18 altgr --Cyrillic_O 0x18 shift altgr --Cyrillic_pe 0x19 altgr --Cyrillic_PE 0x19 shift altgr --bracketleft 0x1a --braceleft 0x1a shift --Cyrillic_sha 0x1a altgr --Cyrillic_SHA 0x1a shift altgr --bracketright 0x1b --braceright 0x1b shift --Macedonia_gje 0x1b altgr --Macedonia_GJE 0x1b shift altgr --Cyrillic_a 0x1e altgr --Cyrillic_A 0x1e shift altgr --Cyrillic_es 0x1f altgr --Cyrillic_ES 0x1f shift altgr --Cyrillic_de 0x20 altgr --Cyrillic_DE 0x20 shift altgr --Cyrillic_ef 0x21 altgr --Cyrillic_EF 0x21 shift altgr --Cyrillic_ghe 0x22 altgr --Cyrillic_GHE 0x22 shift altgr --Cyrillic_ha 0x23 altgr --Cyrillic_HA 0x23 shift altgr --Cyrillic_je 0x24 altgr --Cyrillic_JE 0x24 shift altgr --Cyrillic_ka 0x25 altgr --Cyrillic_KA 0x25 shift altgr --Cyrillic_el 0x26 altgr --Cyrillic_EL 0x26 shift altgr --semicolon 0x27 --colon 0x27 shift --Cyrillic_che 0x27 altgr --Cyrillic_CHE 0x27 shift altgr --apostrophe 0x28 --quotedbl 0x28 shift --Macedonia_kje 0x28 altgr --Macedonia_KJE 0x28 shift altgr --grave 0x29 -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+Cyrillic_lje 0x10 -+Cyrillic_LJE 0x10 shift -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+Cyrillic_nje 0x11 -+Cyrillic_NJE 0x11 shift -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+Cyrillic_ie 0x12 -+Cyrillic_IE 0x12 shift -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+Cyrillic_er 0x13 -+Cyrillic_ER 0x13 shift -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+Cyrillic_te 0x14 -+Cyrillic_TE 0x14 shift -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+Macedonia_dse 0x15 -+Macedonia_DSE 0x15 shift -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+Cyrillic_u 0x16 -+Cyrillic_U 0x16 shift -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+Cyrillic_i 0x17 -+Cyrillic_I 0x17 shift -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+Cyrillic_o 0x18 -+Cyrillic_O 0x18 shift -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+Cyrillic_pe 0x19 -+Cyrillic_PE 0x19 shift -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a -+Cyrillic_sha 0x1a -+Cyrillic_SHA 0x1a shift -+ -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b -+Macedonia_gje 0x1b -+Macedonia_GJE 0x1b shift -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+Cyrillic_a 0x1e -+Cyrillic_A 0x1e shift -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+Cyrillic_es 0x1f -+Cyrillic_ES 0x1f shift -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+Cyrillic_de 0x20 -+Cyrillic_DE 0x20 shift -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+Cyrillic_ef 0x21 -+Cyrillic_EF 0x21 shift -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+Cyrillic_ghe 0x22 -+Cyrillic_GHE 0x22 shift -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+Cyrillic_ha 0x23 -+Cyrillic_HA 0x23 shift -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+Cyrillic_je 0x24 -+Cyrillic_JE 0x24 shift -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+Cyrillic_ka 0x25 -+Cyrillic_KA 0x25 shift -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+Cyrillic_el 0x26 -+Cyrillic_EL 0x26 shift -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 -+Cyrillic_che 0x27 -+Cyrillic_CHE 0x27 shift -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 -+Macedonia_kje 0x28 -+Macedonia_KJE 0x28 shift -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 -+dead_grave 0x29 - asciitilde 0x29 shift --backslash 0x2b --bar 0x2b shift --Cyrillic_zhe 0x2b altgr --Cyrillic_ZHE 0x2b shift altgr --Cyrillic_ze 0x2c altgr --Cyrillic_ZE 0x2c shift altgr --Cyrillic_dzhe 0x2d altgr --Cyrillic_DZHE 0x2d shift altgr --Cyrillic_tse 0x2e altgr --Cyrillic_TSE 0x2e shift altgr --Cyrillic_ve 0x2f altgr --Cyrillic_VE 0x2f shift altgr --Cyrillic_be 0x30 altgr --Cyrillic_BE 0x30 shift altgr --Cyrillic_en 0x31 altgr --Cyrillic_EN 0x31 shift altgr --Cyrillic_em 0x32 altgr --Cyrillic_EM 0x32 shift altgr -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b -+Cyrillic_zhe 0x2b -+Cyrillic_ZHE 0x2b shift -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+Cyrillic_ze 0x2c -+Cyrillic_ZE 0x2c shift -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+Cyrillic_dzhe 0x2d -+Cyrillic_DZHE 0x2d shift -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+Cyrillic_tse 0x2e -+Cyrillic_TSE 0x2e shift -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+Cyrillic_ve 0x2f -+Cyrillic_VE 0x2f shift -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+Cyrillic_be 0x30 -+Cyrillic_BE 0x30 shift -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+Cyrillic_en 0x31 -+Cyrillic_EN 0x31 shift -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+Cyrillic_em 0x32 -+Cyrillic_EM 0x32 shift -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 - comma 0x33 --less 0x33 shift --semicolon 0x33 shift altgr -+semicolon 0x33 shift -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 - period 0x34 --greater 0x34 shift --colon 0x34 shift altgr -+colon 0x34 shift -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 - slash 0x35 - question 0x35 shift -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Separator 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 -+less 0x56 -+greater 0x56 shift -+bar 0x56 altgr -+brokenbar 0x56 shift altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+Alt_R 0xb8 -+Meta_R 0xb8 shift -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/nl b/pc-bios/keymaps/nl -index b4892f9..ae7c8f5 100644 ---- a/pc-bios/keymaps/nl -+++ b/pc-bios/keymaps/nl -@@ -1,59 +1,837 @@ --# Dutch (Netherlands) --include common --map 0x413 -+# -+# generated by qemu-keymap -+# model : pc105 -+# layout : nl -+# variant : - -+# options : - - -+# name: "Dutch" -+ -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+1 0x02 - exclam 0x02 shift - onesuperior 0x02 altgr --quotebl 0x03 shift -+exclamdown 0x02 shift altgr -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+2 0x03 -+quotedbl 0x03 shift - twosuperior 0x03 altgr -+oneeighth 0x03 shift altgr -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+3 0x04 - numbersign 0x04 shift - threesuperior 0x04 altgr -+sterling 0x04 shift altgr -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+4 0x05 - dollar 0x05 shift - onequarter 0x05 altgr -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+5 0x06 - percent 0x06 shift - onehalf 0x06 altgr -+threeeighths 0x06 shift altgr -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+6 0x07 - ampersand 0x07 shift - threequarters 0x07 altgr -+fiveeighths 0x07 shift altgr -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+7 0x08 - underscore 0x08 shift - sterling 0x08 altgr -+seveneighths 0x08 shift altgr -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+8 0x09 - parenleft 0x09 shift - braceleft 0x09 altgr -+bracketleft 0x09 shift altgr -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+9 0x0a - parenright 0x0a shift - braceright 0x0a altgr -+bracketright 0x0a shift altgr -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+0 0x0b - apostrophe 0x0b shift -+degree 0x0b altgr -+trademark 0x0b shift altgr -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc - slash 0x0c - question 0x0c shift - backslash 0x0c altgr -+questiondown 0x0c shift altgr -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd - degree 0x0d - dead_tilde 0x0d shift - dead_cedilla 0x0d altgr -+dead_ogonek 0x0d shift altgr -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+q 0x10 -+Q 0x10 shift -+at 0x10 altgr -+Greek_OMEGA 0x10 shift altgr -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+w 0x11 -+W 0x11 shift -+lstroke 0x11 altgr -+Lstroke 0x11 shift altgr -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+e 0x12 -+E 0x12 shift - EuroSign 0x12 altgr -+cent 0x12 shift altgr -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+r 0x13 -+R 0x13 shift - paragraph 0x13 altgr -+registered 0x13 shift altgr -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+t 0x14 -+T 0x14 shift -+thorn 0x14 altgr -+THORN 0x14 shift altgr -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+y 0x15 -+Y 0x15 shift -+ydiaeresis 0x15 altgr -+yen 0x15 shift altgr -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+u 0x16 -+U 0x16 shift -+udiaeresis 0x16 altgr -+Udiaeresis 0x16 shift altgr -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+i 0x17 -+I 0x17 shift -+idiaeresis 0x17 altgr -+Idiaeresis 0x17 shift altgr -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+o 0x18 -+O 0x18 shift -+ograve 0x18 altgr -+Ograve 0x18 shift altgr -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+p 0x19 -+P 0x19 shift -+paragraph 0x19 altgr -+THORN 0x19 shift altgr -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a - dead_diaeresis 0x1a - dead_circumflex 0x1a shift -+asciitilde 0x1a altgr -+asciicircum 0x1a shift altgr -+ -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b - asterisk 0x1b - bar 0x1b shift -+dead_tilde 0x1b altgr -+dead_macron 0x1b shift altgr -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+a 0x1e -+A 0x1e shift -+aacute 0x1e altgr -+Aacute 0x1e shift altgr -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+s 0x1f -+S 0x1f shift - ssharp 0x1f altgr -+section 0x1f shift altgr -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+d 0x20 -+D 0x20 shift -+eth 0x20 altgr -+ETH 0x20 shift altgr -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+f 0x21 -+F 0x21 shift -+ordfeminine 0x21 altgr -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+g 0x22 -+G 0x22 shift -+eng 0x22 altgr -+ENG 0x22 shift altgr -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+h 0x23 -+H 0x23 shift -+hstroke 0x23 altgr -+Hstroke 0x23 shift altgr -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+j 0x24 -+J 0x24 shift -+dead_hook 0x24 altgr -+dead_horn 0x24 shift altgr -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+k 0x25 -+K 0x25 shift -+kra 0x25 altgr -+ampersand 0x25 shift altgr -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+l 0x26 -+L 0x26 shift -+lstroke 0x26 altgr -+Lstroke 0x26 shift altgr -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 - plus 0x27 - plusminus 0x27 shift -+dead_acute 0x27 altgr -+dead_doubleacute 0x27 shift altgr -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 - dead_acute 0x28 - dead_grave 0x28 shift -+apostrophe 0x28 altgr -+grave 0x28 shift altgr -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 - at 0x29 - section 0x29 shift - notsign 0x29 altgr -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b - less 0x2b - greater 0x2b shift -+dead_grave 0x2b altgr -+dead_breve 0x2b shift altgr -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+z 0x2c -+Z 0x2c shift - guillemotleft 0x2c altgr -+less 0x2c shift altgr -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+x 0x2d -+X 0x2d shift - guillemotright 0x2d altgr --copyright 0x2e altgr --mu 0x32 altgr -+greater 0x2d shift altgr -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+c 0x2e -+C 0x2e shift -+cent 0x2e altgr -+copyright 0x2e shift altgr -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+v 0x2f -+V 0x2f shift -+leftdoublequotemark 0x2f altgr -+leftsinglequotemark 0x2f shift altgr -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+b 0x30 -+B 0x30 shift -+rightdoublequotemark 0x30 altgr -+rightsinglequotemark 0x30 shift altgr -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+n 0x31 -+N 0x31 shift -+ntilde 0x31 altgr -+Ntilde 0x31 shift altgr -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+m 0x32 -+M 0x32 shift -+Greek_mu 0x32 altgr -+masculine 0x32 shift altgr -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 - comma 0x33 - semicolon 0x33 shift -+cedilla 0x33 altgr -+guillemotleft 0x33 shift altgr -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 - period 0x34 - colon 0x34 shift - periodcentered 0x34 altgr --hyphen 0x35 -+guillemotright 0x34 shift altgr -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 -+minus 0x35 - equal 0x35 shift -+hyphen 0x35 altgr -+dead_abovedot 0x35 shift altgr -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Decimal 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 - bracketright 0x56 - bracketleft 0x56 shift --brokenbar 0x56 altgr -+bar 0x56 altgr -+brokenbar 0x56 shift altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+ISO_Level3_Shift 0xb8 -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/no b/pc-bios/keymaps/no -index 40a6479..8afd199 100644 ---- a/pc-bios/keymaps/no -+++ b/pc-bios/keymaps/no -@@ -1,119 +1,851 @@ --# generated from XKB map no --include common --map 0x414 -+# -+# generated by qemu-keymap -+# model : pc105 -+# layout : no -+# variant : - -+# options : - -+ -+# name: "Norwegian" -+ -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+1 0x02 - exclam 0x02 shift - exclamdown 0x02 altgr - onesuperior 0x02 shift altgr -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+2 0x03 - quotedbl 0x03 shift - at 0x03 altgr - twosuperior 0x03 shift altgr -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+3 0x04 - numbersign 0x04 shift - sterling 0x04 altgr - threesuperior 0x04 shift altgr -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+4 0x05 - currency 0x05 shift - dollar 0x05 altgr - onequarter 0x05 shift altgr -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+5 0x06 - percent 0x06 shift - onehalf 0x06 altgr --cent 0x06 shift altgr -+U2030 0x06 shift altgr -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+6 0x07 - ampersand 0x07 shift - yen 0x07 altgr - fiveeighths 0x07 shift altgr -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+7 0x08 - slash 0x08 shift - braceleft 0x08 altgr - division 0x08 shift altgr -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+8 0x09 - parenleft 0x09 shift - bracketleft 0x09 altgr - guillemotleft 0x09 shift altgr -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+9 0x0a - parenright 0x0a shift - bracketright 0x0a altgr - guillemotright 0x0a shift altgr -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+0 0x0b - equal 0x0b shift - braceright 0x0b altgr - degree 0x0b shift altgr -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc - plus 0x0c - question 0x0c shift - plusminus 0x0c altgr - questiondown 0x0c shift altgr -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd - backslash 0x0d - dead_grave 0x0d shift - dead_acute 0x0d altgr - notsign 0x0d shift altgr -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+q 0x10 -+Q 0x10 shift -+at 0x10 altgr - Greek_OMEGA 0x10 shift altgr -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+w 0x11 -+W 0x11 shift - lstroke 0x11 altgr - Lstroke 0x11 shift altgr -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+e 0x12 -+E 0x12 shift - EuroSign 0x12 altgr - cent 0x12 shift altgr -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+r 0x13 -+R 0x13 shift - registered 0x13 altgr -+trademark 0x13 shift altgr -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+t 0x14 -+T 0x14 shift - thorn 0x14 altgr - THORN 0x14 shift altgr -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+y 0x15 -+Y 0x15 shift - leftarrow 0x15 altgr - yen 0x15 shift altgr -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+u 0x16 -+U 0x16 shift - downarrow 0x16 altgr - uparrow 0x16 shift altgr -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+i 0x17 -+I 0x17 shift - rightarrow 0x17 altgr - idotless 0x17 shift altgr -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+o 0x18 -+O 0x18 shift - oe 0x18 altgr - OE 0x18 shift altgr --thorn 0x19 altgr --THORN 0x19 shift altgr -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+p 0x19 -+P 0x19 shift -+Greek_pi 0x19 altgr -+Greek_PI 0x19 shift altgr -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a - aring 0x1a - Aring 0x1a shift - dead_diaeresis 0x1a altgr - dead_abovering 0x1a shift altgr -+ -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b - dead_diaeresis 0x1b - dead_circumflex 0x1b shift --asciicircum 0x01b shift - dead_tilde 0x1b altgr --asciitilde 0x1b altgr - dead_caron 0x1b shift altgr -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+a 0x1e -+A 0x1e shift - ordfeminine 0x1e altgr - masculine 0x1e shift altgr -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+s 0x1f -+S 0x1f shift - ssharp 0x1f altgr - section 0x1f shift altgr -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+d 0x20 -+D 0x20 shift - eth 0x20 altgr - ETH 0x20 shift altgr -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+f 0x21 -+F 0x21 shift - dstroke 0x21 altgr - ordfeminine 0x21 shift altgr -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+g 0x22 -+G 0x22 shift - eng 0x22 altgr - ENG 0x22 shift altgr -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+h 0x23 -+H 0x23 shift - hstroke 0x23 altgr - Hstroke 0x23 shift altgr -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+j 0x24 -+J 0x24 shift -+dead_hook 0x24 altgr -+dead_horn 0x24 shift altgr -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+k 0x25 -+K 0x25 shift - kra 0x25 altgr -+ampersand 0x25 shift altgr -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+l 0x26 -+L 0x26 shift - lstroke 0x26 altgr - Lstroke 0x26 shift altgr -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 - oslash 0x27 --Ooblique 0x27 shift -+Oslash 0x27 shift -+dead_acute 0x27 altgr - dead_doubleacute 0x27 shift altgr -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 - ae 0x28 - AE 0x28 shift -+dead_circumflex 0x28 altgr - dead_caron 0x28 shift altgr -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 - bar 0x29 - section 0x29 shift - brokenbar 0x29 altgr - paragraph 0x29 shift altgr -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b - apostrophe 0x2b - asterisk 0x2b shift -+dead_doubleacute 0x2b altgr - multiply 0x2b shift altgr -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+z 0x2c -+Z 0x2c shift - guillemotleft 0x2c altgr -+less 0x2c shift altgr -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+x 0x2d -+X 0x2d shift - guillemotright 0x2d altgr -+greater 0x2d shift altgr -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+c 0x2e -+C 0x2e shift - copyright 0x2e altgr -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+v 0x2f -+V 0x2f shift - leftdoublequotemark 0x2f altgr -+leftsinglequotemark 0x2f shift altgr -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+b 0x30 -+B 0x30 shift - rightdoublequotemark 0x30 altgr -+rightsinglequotemark 0x30 shift altgr -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+n 0x31 -+N 0x31 shift -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+m 0x32 -+M 0x32 shift - mu 0x32 altgr - masculine 0x32 shift altgr -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 - comma 0x33 - semicolon 0x33 shift - dead_cedilla 0x33 altgr - dead_ogonek 0x33 shift altgr -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 - period 0x34 - colon 0x34 shift --periodcentered 0x34 altgr --dead_abovedot 0x34 shift altgr -+ellipsis 0x34 altgr -+periodcentered 0x34 shift altgr -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 - minus 0x35 - underscore 0x35 shift --hyphen 0x35 altgr --macron 0x35 shift altgr -+endash 0x35 altgr -+emdash 0x35 shift altgr -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+U22C5 0x37 shift -+0x010000d7 0x37 altgr -+VoidSymbol 0x37 shift altgr -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 - nobreakspace 0x39 altgr -+U202F 0x39 shift altgr -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+U2212 0x4a shift -+U2212 0x4a altgr -+VoidSymbol 0x4a shift altgr -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+0x0100002b 0x4e shift -+0x0100002b 0x4e altgr -+VoidSymbol 0x4e shift altgr -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Separator 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 -+less 0x56 -+greater 0x56 shift - onehalf 0x56 altgr - threequarters 0x56 shift altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+U2215 0xb5 shift -+0x010000f7 0xb5 altgr -+VoidSymbol 0xb5 shift altgr -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+ISO_Level3_Shift 0xb8 -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/pl b/pc-bios/keymaps/pl -index 09c600d..df27206 100644 ---- a/pc-bios/keymaps/pl -+++ b/pc-bios/keymaps/pl -@@ -1,122 +1,841 @@ --# generated from XKB map pl --include common --map 0x415 -+# -+# generated by qemu-keymap -+# model : pc105 -+# layout : pl -+# variant : - -+# options : - -+ -+# name: "Polish" -+ -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+1 0x02 - exclam 0x02 shift --onesuperior 0x02 altgr -+notequal 0x02 altgr - exclamdown 0x02 shift altgr -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+2 0x03 - at 0x03 shift - twosuperior 0x03 altgr --oneeighth 0x03 shift altgr -+questiondown 0x03 shift altgr -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+3 0x04 - numbersign 0x04 shift - threesuperior 0x04 altgr - sterling 0x04 shift altgr -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+4 0x05 - dollar 0x05 shift --onequarter 0x05 altgr -+cent 0x05 altgr -+onequarter 0x05 shift altgr -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+5 0x06 - percent 0x06 shift --onehalf 0x06 altgr --threeeighths 0x06 shift altgr -+EuroSign 0x06 altgr -+U2030 0x06 shift altgr -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+6 0x07 - asciicircum 0x07 shift --threequarters 0x07 altgr --fiveeighths 0x07 shift altgr -+onehalf 0x07 altgr -+logicaland 0x07 shift altgr -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+7 0x08 - ampersand 0x08 shift --braceleft 0x08 altgr --seveneighths 0x08 shift altgr -+section 0x08 altgr -+approxeq 0x08 shift altgr -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+8 0x09 - asterisk 0x09 shift --bracketleft 0x09 altgr --trademark 0x09 shift altgr -+periodcentered 0x09 altgr -+threequarters 0x09 shift altgr -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+9 0x0a - parenleft 0x0a shift --bracketright 0x0a altgr -+guillemotleft 0x0a altgr - plusminus 0x0a shift altgr -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+0 0x0b - parenright 0x0b shift --braceright 0x0b altgr -+guillemotright 0x0b altgr - degree 0x0b shift altgr -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc - minus 0x0c - underscore 0x0c shift --backslash 0x0c altgr --questiondown 0x0c shift altgr -+endash 0x0c altgr -+emdash 0x0c shift altgr -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd - equal 0x0d - plus 0x0d shift - dead_cedilla 0x0d altgr - dead_ogonek 0x0d shift altgr -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+q 0x10 -+Q 0x10 shift -+Greek_pi 0x10 altgr - Greek_OMEGA 0x10 shift altgr --lstroke 0x11 altgr --Lstroke 0x11 shift altgr -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+w 0x11 -+W 0x11 shift -+oe 0x11 altgr -+OE 0x11 shift altgr -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+e 0x12 -+E 0x12 shift - eogonek 0x12 altgr - Eogonek 0x12 shift altgr --paragraph 0x13 altgr -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+r 0x13 -+R 0x13 shift -+copyright 0x13 altgr - registered 0x13 shift altgr --tslash 0x14 altgr --Tslash 0x14 shift altgr -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+t 0x14 -+T 0x14 shift -+ssharp 0x14 altgr -+trademark 0x14 shift altgr -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+y 0x15 -+Y 0x15 shift - leftarrow 0x15 altgr - yen 0x15 shift altgr --EuroSign 0x16 altgr -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+u 0x16 -+U 0x16 shift -+downarrow 0x16 altgr - uparrow 0x16 shift altgr -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+i 0x17 -+I 0x17 shift - rightarrow 0x17 altgr --idotless 0x17 shift altgr -+U2194 0x17 shift altgr -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+o 0x18 -+O 0x18 shift - oacute 0x18 altgr - Oacute 0x18 shift altgr -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+p 0x19 -+P 0x19 shift - thorn 0x19 altgr - THORN 0x19 shift altgr -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a - bracketleft 0x1a - braceleft 0x1a shift - dead_diaeresis 0x1a altgr - dead_abovering 0x1a shift altgr -+ -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b - bracketright 0x1b - braceright 0x1b shift - dead_tilde 0x1b altgr - dead_macron 0x1b shift altgr -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+a 0x1e -+A 0x1e shift - aogonek 0x1e altgr - Aogonek 0x1e shift altgr -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+s 0x1f -+S 0x1f shift - sacute 0x1f altgr - Sacute 0x1f shift altgr -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+d 0x20 -+D 0x20 shift - eth 0x20 altgr - ETH 0x20 shift altgr --dstroke 0x21 altgr --ordfeminine 0x21 shift altgr -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+f 0x21 -+F 0x21 shift -+ae 0x21 altgr -+AE 0x21 shift altgr -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+g 0x22 -+G 0x22 shift - eng 0x22 altgr - ENG 0x22 shift altgr --hstroke 0x23 altgr --Hstroke 0x23 shift altgr --kra 0x25 altgr -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+h 0x23 -+H 0x23 shift -+rightsinglequotemark 0x23 altgr -+U2022 0x23 shift altgr -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+j 0x24 -+J 0x24 shift -+schwa 0x24 altgr -+SCHWA 0x24 shift altgr -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+k 0x25 -+K 0x25 shift -+ellipsis 0x25 altgr -+dead_stroke 0x25 shift altgr -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+l 0x26 -+L 0x26 shift - lstroke 0x26 altgr - Lstroke 0x26 shift altgr -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 - semicolon 0x27 - colon 0x27 shift - dead_acute 0x27 altgr - dead_doubleacute 0x27 shift altgr -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 - apostrophe 0x28 - quotedbl 0x28 shift - dead_circumflex 0x28 altgr - dead_caron 0x28 shift altgr -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 - grave 0x29 - asciitilde 0x29 shift - notsign 0x29 altgr -+logicalor 0x29 shift altgr -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b - backslash 0x2b - bar 0x2b shift - dead_grave 0x2b altgr - dead_breve 0x2b shift altgr -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+z 0x2c -+Z 0x2c shift - zabovedot 0x2c altgr - Zabovedot 0x2c shift altgr -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+x 0x2d -+X 0x2d shift - zacute 0x2d altgr - Zacute 0x2d shift altgr -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+c 0x2e -+C 0x2e shift - cacute 0x2e altgr - Cacute 0x2e shift altgr --leftdoublequotemark 0x2f altgr --grave 0x2f shift altgr -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+v 0x2f -+V 0x2f shift -+doublelowquotemark 0x2f altgr -+leftsinglequotemark 0x2f shift altgr -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+b 0x30 -+B 0x30 shift - rightdoublequotemark 0x30 altgr -+leftdoublequotemark 0x30 shift altgr -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+n 0x31 -+N 0x31 shift - nacute 0x31 altgr - Nacute 0x31 shift altgr -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+m 0x32 -+M 0x32 shift - mu 0x32 altgr --masculine 0x32 shift altgr -+infinity 0x32 shift altgr -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 - comma 0x33 - less 0x33 shift --horizconnector 0x33 altgr -+lessthanequal 0x33 altgr - multiply 0x33 shift altgr -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 - period 0x34 - greater 0x34 shift --periodcentered 0x34 altgr -+greaterthanequal 0x34 altgr - division 0x34 shift altgr -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 - slash 0x35 - question 0x35 shift - dead_belowdot 0x35 altgr - dead_abovedot 0x35 shift altgr -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+nobreakspace 0x39 altgr -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Separator 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 -+less 0x56 -+greater 0x56 shift -+bar 0x56 altgr -+brokenbar 0x56 shift altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+ISO_Level3_Shift 0xb8 -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/pt b/pc-bios/keymaps/pt -index c6941f6..ab59001 100644 ---- a/pc-bios/keymaps/pt -+++ b/pc-bios/keymaps/pt -@@ -1,113 +1,834 @@ --# generated from XKB map pt --include common --map 0x816 -+# -+# generated by qemu-keymap -+# model : pc105 -+# layout : pt -+# variant : - -+# options : - -+ -+# name: "Portuguese" -+ -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+1 0x02 - exclam 0x02 shift - onesuperior 0x02 altgr - exclamdown 0x02 shift altgr -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+2 0x03 - quotedbl 0x03 shift - at 0x03 altgr - oneeighth 0x03 shift altgr -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+3 0x04 - numbersign 0x04 shift - sterling 0x04 altgr -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+4 0x05 - dollar 0x05 shift - section 0x05 altgr -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+5 0x06 - percent 0x06 shift - onehalf 0x06 altgr - threeeighths 0x06 shift altgr -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+6 0x07 - ampersand 0x07 shift --threequarters 0x07 altgr -+notsign 0x07 altgr - fiveeighths 0x07 shift altgr -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+7 0x08 - slash 0x08 shift - braceleft 0x08 altgr - seveneighths 0x08 shift altgr -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+8 0x09 - parenleft 0x09 shift - bracketleft 0x09 altgr - trademark 0x09 shift altgr -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+9 0x0a - parenright 0x0a shift - bracketright 0x0a altgr - plusminus 0x0a shift altgr -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+0 0x0b - equal 0x0b shift - braceright 0x0b altgr - degree 0x0b shift altgr -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc - apostrophe 0x0c - question 0x0c shift - backslash 0x0c altgr - questiondown 0x0c shift altgr -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd - guillemotleft 0x0d - guillemotright 0x0d shift - dead_cedilla 0x0d altgr - dead_ogonek 0x0d shift altgr -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+q 0x10 -+Q 0x10 shift -+at 0x10 altgr - Greek_OMEGA 0x10 shift altgr -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+w 0x11 -+W 0x11 shift - lstroke 0x11 altgr - Lstroke 0x11 shift altgr -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+e 0x12 -+E 0x12 shift - EuroSign 0x12 altgr - cent 0x12 shift altgr -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+r 0x13 -+R 0x13 shift - paragraph 0x13 altgr - registered 0x13 shift altgr -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+t 0x14 -+T 0x14 shift - tslash 0x14 altgr - Tslash 0x14 shift altgr -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+y 0x15 -+Y 0x15 shift - leftarrow 0x15 altgr - yen 0x15 shift altgr -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+u 0x16 -+U 0x16 shift - downarrow 0x16 altgr - uparrow 0x16 shift altgr -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+i 0x17 -+I 0x17 shift - rightarrow 0x17 altgr - idotless 0x17 shift altgr -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+o 0x18 -+O 0x18 shift - oslash 0x18 altgr --Ooblique 0x18 shift altgr -+Oslash 0x18 shift altgr -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+p 0x19 -+P 0x19 shift - thorn 0x19 altgr - THORN 0x19 shift altgr -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a - plus 0x1a - asterisk 0x1a shift - dead_diaeresis 0x1a altgr - dead_abovering 0x1a shift altgr -+ -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b - dead_acute 0x1b - dead_grave 0x1b shift - dead_tilde 0x1b altgr - dead_macron 0x1b shift altgr -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+a 0x1e -+A 0x1e shift - ae 0x1e altgr - AE 0x1e shift altgr -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+s 0x1f -+S 0x1f shift - ssharp 0x1f altgr -+section 0x1f shift altgr -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+d 0x20 -+D 0x20 shift - eth 0x20 altgr - ETH 0x20 shift altgr -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+f 0x21 -+F 0x21 shift - dstroke 0x21 altgr - ordfeminine 0x21 shift altgr -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+g 0x22 -+G 0x22 shift - eng 0x22 altgr - ENG 0x22 shift altgr -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+h 0x23 -+H 0x23 shift - hstroke 0x23 altgr - Hstroke 0x23 shift altgr -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+j 0x24 -+J 0x24 shift -+dead_hook 0x24 altgr -+dead_horn 0x24 shift altgr -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+k 0x25 -+K 0x25 shift - kra 0x25 altgr -+ampersand 0x25 shift altgr -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+l 0x26 -+L 0x26 shift - lstroke 0x26 altgr - Lstroke 0x26 shift altgr -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 - ccedilla 0x27 - Ccedilla 0x27 shift -+dead_acute 0x27 altgr - dead_doubleacute 0x27 shift altgr -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 - masculine 0x28 - ordfeminine 0x28 shift - dead_circumflex 0x28 altgr - dead_caron 0x28 shift altgr -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 - backslash 0x29 - bar 0x29 shift - notsign 0x29 altgr -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b - dead_tilde 0x2b - dead_circumflex 0x2b shift -+dead_grave 0x2b altgr - dead_breve 0x2b shift altgr --less 0x56 --greater 0x56 shift -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+z 0x2c -+Z 0x2c shift -+guillemotleft 0x2c altgr -+less 0x2c shift altgr -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+x 0x2d -+X 0x2d shift -+guillemotright 0x2d altgr -+greater 0x2d shift altgr -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+c 0x2e -+C 0x2e shift - cent 0x2e altgr - copyright 0x2e shift altgr -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+v 0x2f -+V 0x2f shift - leftdoublequotemark 0x2f altgr --grave 0x2f shift altgr -+leftsinglequotemark 0x2f shift altgr -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+b 0x30 -+B 0x30 shift - rightdoublequotemark 0x30 altgr -+rightsinglequotemark 0x30 shift altgr -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+n 0x31 -+N 0x31 shift -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+m 0x32 -+M 0x32 shift - mu 0x32 altgr -+masculine 0x32 shift altgr -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 - comma 0x33 - semicolon 0x33 shift - horizconnector 0x33 altgr - multiply 0x33 shift altgr -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 - period 0x34 - colon 0x34 shift - periodcentered 0x34 altgr - division 0x34 shift altgr -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 - minus 0x35 - underscore 0x35 shift - dead_belowdot 0x35 altgr - dead_abovedot 0x35 shift altgr -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Decimal 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 -+less 0x56 -+greater 0x56 shift -+backslash 0x56 altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+ISO_Level3_Shift 0xb8 -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/pt-br b/pc-bios/keymaps/pt-br -index 54bafc5..fe9ec81 100644 ---- a/pc-bios/keymaps/pt-br -+++ b/pc-bios/keymaps/pt-br -@@ -1,69 +1,834 @@ --# generated from XKB map br --include common --map 0x416 -+# -+# generated by qemu-keymap -+# model : pc105 -+# layout : br -+# variant : - -+# options : - -+ -+# name: "Portuguese (Brazil)" -+ -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+1 0x02 - exclam 0x02 shift - onesuperior 0x02 altgr - exclamdown 0x02 shift altgr -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+2 0x03 - at 0x03 shift - twosuperior 0x03 altgr - onehalf 0x03 shift altgr -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+3 0x04 - numbersign 0x04 shift - threesuperior 0x04 altgr - threequarters 0x04 shift altgr -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+4 0x05 - dollar 0x05 shift - sterling 0x05 altgr - onequarter 0x05 shift altgr -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+5 0x06 - percent 0x06 shift - cent 0x06 altgr -+threeeighths 0x06 shift altgr -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+6 0x07 - dead_diaeresis 0x07 shift - notsign 0x07 altgr - diaeresis 0x07 shift altgr -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+7 0x08 - ampersand 0x08 shift - braceleft 0x08 altgr -+seveneighths 0x08 shift altgr -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+8 0x09 - asterisk 0x09 shift - bracketleft 0x09 altgr -+trademark 0x09 shift altgr -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+9 0x0a - parenleft 0x0a shift - bracketright 0x0a altgr -+plusminus 0x0a shift altgr -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+0 0x0b - parenright 0x0b shift - braceright 0x0b altgr -+degree 0x0b shift altgr -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc - minus 0x0c - underscore 0x0c shift - backslash 0x0c altgr -+questiondown 0x0c shift altgr -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd - equal 0x0d - plus 0x0d shift - section 0x0d altgr -+dead_ogonek 0x0d shift altgr -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+q 0x10 -+Q 0x10 shift -+slash 0x10 altgr -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+w 0x11 -+W 0x11 shift -+question 0x11 altgr -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+e 0x12 -+E 0x12 shift - EuroSign 0x12 altgr -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+r 0x13 -+R 0x13 shift - registered 0x13 altgr -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+t 0x14 -+T 0x14 shift -+tslash 0x14 altgr -+Tslash 0x14 shift altgr -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+y 0x15 -+Y 0x15 shift -+leftarrow 0x15 altgr -+yen 0x15 shift altgr -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+u 0x16 -+U 0x16 shift -+downarrow 0x16 altgr -+uparrow 0x16 shift altgr -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+i 0x17 -+I 0x17 shift -+rightarrow 0x17 altgr -+idotless 0x17 shift altgr -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+o 0x18 -+O 0x18 shift -+oslash 0x18 altgr -+Oslash 0x18 shift altgr -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+p 0x19 -+P 0x19 shift -+thorn 0x19 altgr -+THORN 0x19 shift altgr -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a - dead_acute 0x1a - dead_grave 0x1a shift - acute 0x1a altgr - grave 0x1a shift altgr -+ -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b - bracketleft 0x1b - braceleft 0x1b shift - ordfeminine 0x1b altgr -+dead_macron 0x1b shift altgr -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+a 0x1e -+A 0x1e shift -+ae 0x1e altgr -+AE 0x1e shift altgr -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+s 0x1f -+S 0x1f shift -+ssharp 0x1f altgr -+section 0x1f shift altgr -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+d 0x20 -+D 0x20 shift -+eth 0x20 altgr -+ETH 0x20 shift altgr -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+f 0x21 -+F 0x21 shift -+dstroke 0x21 altgr -+ordfeminine 0x21 shift altgr -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+g 0x22 -+G 0x22 shift -+eng 0x22 altgr -+ENG 0x22 shift altgr -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+h 0x23 -+H 0x23 shift -+hstroke 0x23 altgr -+Hstroke 0x23 shift altgr -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+j 0x24 -+J 0x24 shift -+dead_hook 0x24 altgr -+dead_horn 0x24 shift altgr -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+k 0x25 -+K 0x25 shift -+kra 0x25 altgr -+ampersand 0x25 shift altgr -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+l 0x26 -+L 0x26 shift -+lstroke 0x26 altgr -+Lstroke 0x26 shift altgr -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 - ccedilla 0x27 - Ccedilla 0x27 shift -+dead_acute 0x27 altgr -+dead_doubleacute 0x27 shift altgr -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 - dead_tilde 0x28 - dead_circumflex 0x28 shift - asciitilde 0x28 altgr - asciicircum 0x28 shift altgr -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 - apostrophe 0x29 - quotedbl 0x29 shift -+notsign 0x29 altgr -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b - bracketright 0x2b - braceright 0x2b shift - masculine 0x2b altgr -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+z 0x2c -+Z 0x2c shift -+guillemotleft 0x2c altgr -+less 0x2c shift altgr -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+x 0x2d -+X 0x2d shift -+guillemotright 0x2d altgr -+greater 0x2d shift altgr -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+c 0x2e -+C 0x2e shift - copyright 0x2e altgr -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+v 0x2f -+V 0x2f shift -+leftdoublequotemark 0x2f altgr -+leftsinglequotemark 0x2f shift altgr -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+b 0x30 -+B 0x30 shift -+rightdoublequotemark 0x30 altgr -+rightsinglequotemark 0x30 shift altgr -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+n 0x31 -+N 0x31 shift -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+m 0x32 -+M 0x32 shift - mu 0x32 altgr -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 - comma 0x33 - less 0x33 shift -+horizconnector 0x33 altgr -+multiply 0x33 shift altgr -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 - period 0x34 - greater 0x34 shift -+periodcentered 0x34 altgr -+division 0x34 shift altgr -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 - semicolon 0x35 - colon 0x35 shift --comma 0x53 numlock -+dead_belowdot 0x35 altgr -+dead_abovedot 0x35 shift altgr -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Separator 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 - backslash 0x56 - bar 0x56 shift -+masculine 0x56 altgr -+dead_breve 0x56 shift altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 - slash 0x73 - question 0x73 shift - degree 0x73 altgr --KP_Decimal 0x34 -+questiondown 0x73 shift altgr -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+ISO_Level3_Shift 0xb8 -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/ru b/pc-bios/keymaps/ru -index 8f652d5..7566052 100644 ---- a/pc-bios/keymaps/ru -+++ b/pc-bios/keymaps/ru -@@ -1,109 +1,748 @@ --# generated from XKB map ru --include common --map 0x419 -+# -+# generated by qemu-keymap -+# model : pc105 -+# layout : ru -+# variant : - -+# options : - -+ -+# name: "Russian" -+ -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+1 0x02 - exclam 0x02 shift --at 0x03 shift --quotedbl 0x03 shift altgr -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+2 0x03 -+quotedbl 0x03 shift -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+3 0x04 - numerosign 0x04 shift --dollar 0x05 shift --asterisk 0x05 shift altgr -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+4 0x05 -+semicolon 0x05 shift -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+5 0x06 - percent 0x06 shift --colon 0x06 shift altgr --asciicircum 0x07 shift --comma 0x07 shift altgr --ampersand 0x08 shift --period 0x08 shift altgr -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+6 0x07 -+colon 0x07 shift -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+7 0x08 -+question 0x08 shift -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+8 0x09 - asterisk 0x09 shift --semicolon 0x09 shift altgr -+U20BD 0x09 altgr -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+9 0x0a - parenleft 0x0a shift -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+0 0x0b - parenright 0x0b shift -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc - minus 0x0c - underscore 0x0c shift -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd - equal 0x0d - plus 0x0d shift --Cyrillic_shorti 0x10 altgr --Cyrillic_SHORTI 0x10 shift altgr --Cyrillic_tse 0x11 altgr --Cyrillic_TSE 0x11 shift altgr --Cyrillic_u 0x12 altgr --Cyrillic_U 0x12 shift altgr --Cyrillic_ka 0x13 altgr --Cyrillic_KA 0x13 shift altgr --Cyrillic_ie 0x14 altgr --Cyrillic_IE 0x14 shift altgr --Cyrillic_en 0x15 altgr --Cyrillic_EN 0x15 shift altgr --Cyrillic_ghe 0x16 altgr --Cyrillic_GHE 0x16 shift altgr --Cyrillic_sha 0x17 altgr --Cyrillic_SHA 0x17 shift altgr --Cyrillic_shcha 0x18 altgr --Cyrillic_SHCHA 0x18 shift altgr --Cyrillic_ze 0x19 altgr --Cyrillic_ZE 0x19 shift altgr --bracketleft 0x1a --braceleft 0x1a shift --Cyrillic_ha 0x1a altgr --Cyrillic_HA 0x1a shift altgr --bracketright 0x1b --braceright 0x1b shift --Cyrillic_hardsign 0x1b altgr --Cyrillic_HARDSIGN 0x1b shift altgr --Cyrillic_ef 0x1e altgr --Cyrillic_EF 0x1e shift altgr --Cyrillic_yeru 0x1f altgr --Cyrillic_YERU 0x1f shift altgr --Cyrillic_ve 0x20 altgr --Cyrillic_VE 0x20 shift altgr --Cyrillic_a 0x21 altgr --Cyrillic_A 0x21 shift altgr --Cyrillic_pe 0x22 altgr --Cyrillic_PE 0x22 shift altgr --Cyrillic_er 0x23 altgr --Cyrillic_ER 0x23 shift altgr --Cyrillic_o 0x24 altgr --Cyrillic_O 0x24 shift altgr --Cyrillic_el 0x25 altgr --Cyrillic_EL 0x25 shift altgr --Cyrillic_de 0x26 altgr --Cyrillic_DE 0x26 shift altgr --semicolon 0x27 --colon 0x27 shift --Cyrillic_zhe 0x27 altgr --Cyrillic_ZHE 0x27 shift altgr --apostrophe 0x28 --quotedbl 0x28 shift --Cyrillic_e 0x28 altgr --Cyrillic_E 0x28 shift altgr --grave 0x29 --asciitilde 0x29 shift --Cyrillic_io 0x29 altgr --Cyrillic_IO 0x29 shift altgr -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+Cyrillic_shorti 0x10 -+Cyrillic_SHORTI 0x10 shift -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+Cyrillic_tse 0x11 -+Cyrillic_TSE 0x11 shift -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+Cyrillic_u 0x12 -+Cyrillic_U 0x12 shift -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+Cyrillic_ka 0x13 -+Cyrillic_KA 0x13 shift -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+Cyrillic_ie 0x14 -+Cyrillic_IE 0x14 shift -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+Cyrillic_en 0x15 -+Cyrillic_EN 0x15 shift -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+Cyrillic_ghe 0x16 -+Cyrillic_GHE 0x16 shift -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+Cyrillic_sha 0x17 -+Cyrillic_SHA 0x17 shift -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+Cyrillic_shcha 0x18 -+Cyrillic_SHCHA 0x18 shift -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+Cyrillic_ze 0x19 -+Cyrillic_ZE 0x19 shift -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a -+Cyrillic_ha 0x1a -+Cyrillic_HA 0x1a shift -+ -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b -+Cyrillic_hardsign 0x1b -+Cyrillic_HARDSIGN 0x1b shift -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+Cyrillic_ef 0x1e -+Cyrillic_EF 0x1e shift -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+Cyrillic_yeru 0x1f -+Cyrillic_YERU 0x1f shift -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+Cyrillic_ve 0x20 -+Cyrillic_VE 0x20 shift -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+Cyrillic_a 0x21 -+Cyrillic_A 0x21 shift -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+Cyrillic_pe 0x22 -+Cyrillic_PE 0x22 shift -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+Cyrillic_er 0x23 -+Cyrillic_ER 0x23 shift -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+Cyrillic_o 0x24 -+Cyrillic_O 0x24 shift -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+Cyrillic_el 0x25 -+Cyrillic_EL 0x25 shift -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+Cyrillic_de 0x26 -+Cyrillic_DE 0x26 shift -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 -+Cyrillic_zhe 0x27 -+Cyrillic_ZHE 0x27 shift -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 -+Cyrillic_e 0x28 -+Cyrillic_E 0x28 shift -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 -+Cyrillic_io 0x29 -+Cyrillic_IO 0x29 shift -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b - backslash 0x2b --bar 0x2b shift --Cyrillic_ya 0x2c altgr --Cyrillic_YA 0x2c shift altgr --Cyrillic_che 0x2d altgr --Cyrillic_CHE 0x2d shift altgr --Cyrillic_es 0x2e altgr --Cyrillic_ES 0x2e shift altgr --Cyrillic_em 0x2f altgr --Cyrillic_EM 0x2f shift altgr --Cyrillic_i 0x30 altgr --Cyrillic_I 0x30 shift altgr --Cyrillic_te 0x31 altgr --Cyrillic_TE 0x31 shift altgr --Cyrillic_softsign 0x32 altgr --Cyrillic_SOFTSIGN 0x32 shift altgr --comma 0x33 --less 0x33 shift --Cyrillic_be 0x33 altgr --Cyrillic_BE 0x33 shift altgr --period 0x34 --greater 0x34 shift --Cyrillic_yu 0x34 altgr --Cyrillic_YU 0x34 shift altgr --slash 0x35 --question 0x35 shift --slash 0x56 altgr --bar 0x56 shift altgr -+slash 0x2b shift -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+Cyrillic_ya 0x2c -+Cyrillic_YA 0x2c shift -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+Cyrillic_che 0x2d -+Cyrillic_CHE 0x2d shift -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+Cyrillic_es 0x2e -+Cyrillic_ES 0x2e shift -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+Cyrillic_em 0x2f -+Cyrillic_EM 0x2f shift -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+Cyrillic_i 0x30 -+Cyrillic_I 0x30 shift -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+Cyrillic_te 0x31 -+Cyrillic_TE 0x31 shift -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+Cyrillic_softsign 0x32 -+Cyrillic_SOFTSIGN 0x32 shift -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 -+Cyrillic_be 0x33 -+Cyrillic_BE 0x33 shift -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 -+Cyrillic_yu 0x34 -+Cyrillic_YU 0x34 shift -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 -+period 0x35 -+comma 0x35 shift -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Separator 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 -+slash 0x56 -+bar 0x56 shift -+bar 0x56 altgr -+brokenbar 0x56 shift altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+Alt_R 0xb8 -+Meta_R 0xb8 shift -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/th b/pc-bios/keymaps/th -index b65b6da..56a0135 100644 ---- a/pc-bios/keymaps/th -+++ b/pc-bios/keymaps/th -@@ -1,131 +1,747 @@ --# generated from XKB map th --include common --map 0x41e --exclam 0x02 shift --Thai_lakkhangyao 0x02 altgr --plus 0x02 shift altgr --at 0x03 shift --slash 0x03 altgr --Thai_leknung 0x03 shift altgr --numbersign 0x04 shift --minus 0x04 altgr --Thai_leksong 0x04 shift altgr --dollar 0x05 shift --Thai_phosamphao 0x05 altgr --Thai_leksam 0x05 shift altgr --percent 0x06 shift --Thai_thothung 0x06 altgr --Thai_leksi 0x06 shift altgr --asciicircum 0x07 shift --Thai_sarau 0x07 altgr --Thai_sarauu 0x07 shift altgr --ampersand 0x08 shift --Thai_saraue 0x08 altgr --Thai_baht 0x08 shift altgr --asterisk 0x09 shift --Thai_khokhwai 0x09 altgr --Thai_lekha 0x09 shift altgr --parenleft 0x0a shift --Thai_totao 0x0a altgr --Thai_lekhok 0x0a shift altgr --parenright 0x0b shift --Thai_chochan 0x0b altgr --Thai_lekchet 0x0b shift altgr --minus 0x0c --underscore 0x0c shift --Thai_khokhai 0x0c altgr --Thai_lekpaet 0x0c shift altgr --equal 0x0d --plus 0x0d shift --Thai_chochang 0x0d altgr --Thai_lekkao 0x0d shift altgr --Thai_maiyamok 0x10 altgr --Thai_leksun 0x10 shift altgr --Thai_saraaimaimalai 0x11 altgr --quotedbl 0x11 shift altgr --Thai_saraam 0x12 altgr --Thai_dochada 0x12 shift altgr --Thai_phophan 0x13 altgr --Thai_thonangmontho 0x13 shift altgr --Thai_saraa 0x14 altgr --Thai_thothong 0x14 shift altgr --Thai_maihanakat 0x15 altgr --Thai_nikhahit 0x15 shift altgr --Thai_saraii 0x16 altgr --Thai_maitri 0x16 shift altgr --Thai_rorua 0x17 altgr --Thai_nonen 0x17 shift altgr --Thai_nonu 0x18 altgr --Thai_paiyannoi 0x18 shift altgr --Thai_yoyak 0x19 altgr --Thai_yoying 0x19 shift altgr --bracketleft 0x1a --braceleft 0x1a shift --Thai_bobaimai 0x1a altgr --Thai_thothan 0x1a shift altgr --bracketright 0x1b --braceright 0x1b shift --Thai_loling 0x1b altgr --comma 0x1b shift altgr --Thai_fofan 0x1e altgr --Thai_ru 0x1e shift altgr --Thai_hohip 0x1f altgr --Thai_khorakhang 0x1f shift altgr --Thai_kokai 0x20 altgr --Thai_topatak 0x20 shift altgr --Thai_dodek 0x21 altgr --Thai_sarao 0x21 shift altgr --Thai_sarae 0x22 altgr --Thai_chochoe 0x22 shift altgr --Thai_maitho 0x23 altgr --Thai_maitaikhu 0x23 shift altgr --Thai_maiek 0x24 altgr --Thai_maichattawa 0x24 shift altgr --Thai_saraaa 0x25 altgr --Thai_sorusi 0x25 shift altgr --Thai_sosua 0x26 altgr --Thai_sosala 0x26 shift altgr --semicolon 0x27 --colon 0x27 shift --Thai_wowaen 0x27 altgr --Thai_soso 0x27 shift altgr --apostrophe 0x28 --quotedbl 0x28 shift --Thai_ngongu 0x28 altgr --period 0x28 shift altgr --grave 0x29 --asciitilde 0x29 shift --underscore 0x29 altgr --percent 0x29 shift altgr --ISO_First_Group 0x2a shift --backslash 0x2b --bar 0x2b shift --Thai_khokhuat 0x2b altgr --Thai_khokhon 0x2b shift altgr --Thai_phophung 0x2c altgr --parenleft 0x2c shift altgr --Thai_popla 0x2d altgr --parenright 0x2d shift altgr --Thai_saraae 0x2e altgr --Thai_choching 0x2e shift altgr --Thai_oang 0x2f altgr --Thai_honokhuk 0x2f shift altgr --Thai_sarai 0x30 altgr --Thai_phinthu 0x30 shift altgr --Thai_sarauee 0x31 altgr --Thai_thanthakhat 0x31 shift altgr --Thai_thothahan 0x32 altgr --question 0x32 shift altgr --comma 0x33 --less 0x33 shift --Thai_moma 0x33 altgr --Thai_thophuthao 0x33 shift altgr --period 0x34 --greater 0x34 shift --Thai_saraaimaimuan 0x34 altgr --Thai_lochula 0x34 shift altgr --slash 0x35 --question 0x35 shift --Thai_fofa 0x35 altgr --Thai_lu 0x35 shift altgr --ISO_Last_Group 0x36 shift -+# -+# generated by qemu-keymap -+# model : pc105 -+# layout : th -+# variant : - -+# options : - -+ -+# name: "Thai" -+ -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+Thai_lakkhangyao 0x02 -+plus 0x02 shift -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+slash 0x03 -+Thai_leknung 0x03 shift -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+minus 0x04 -+Thai_leksong 0x04 shift -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+Thai_phosamphao 0x05 -+Thai_leksam 0x05 shift -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+Thai_thothung 0x06 -+Thai_leksi 0x06 shift -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+Thai_sarau 0x07 -+Thai_sarauu 0x07 shift -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+Thai_saraue 0x08 -+Thai_baht 0x08 shift -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+Thai_khokhwai 0x09 -+Thai_lekha 0x09 shift -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+Thai_totao 0x0a -+Thai_lekhok 0x0a shift -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+Thai_chochan 0x0b -+Thai_lekchet 0x0b shift -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc -+Thai_khokhai 0x0c -+Thai_lekpaet 0x0c shift -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd -+Thai_chochang 0x0d -+Thai_lekkao 0x0d shift -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+Thai_maiyamok 0x10 -+Thai_leksun 0x10 shift -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+Thai_saraaimaimalai 0x11 -+quotedbl 0x11 shift -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+Thai_saraam 0x12 -+Thai_dochada 0x12 shift -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+Thai_phophan 0x13 -+Thai_thonangmontho 0x13 shift -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+Thai_saraa 0x14 -+Thai_thothong 0x14 shift -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+Thai_maihanakat 0x15 -+Thai_nikhahit 0x15 shift -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+Thai_saraii 0x16 -+Thai_maitri 0x16 shift -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 -+Thai_rorua 0x17 -+Thai_nonen 0x17 shift -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+Thai_nonu 0x18 -+Thai_paiyannoi 0x18 shift -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+Thai_yoyak 0x19 -+Thai_yoying 0x19 shift -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a -+Thai_bobaimai 0x1a -+Thai_thothan 0x1a shift -+ -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b -+Thai_loling 0x1b -+comma 0x1b shift -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+Thai_fofan 0x1e -+Thai_ru 0x1e shift -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+Thai_hohip 0x1f -+Thai_khorakhang 0x1f shift -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+Thai_kokai 0x20 -+Thai_topatak 0x20 shift -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+Thai_dodek 0x21 -+Thai_sarao 0x21 shift -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+Thai_sarae 0x22 -+Thai_chochoe 0x22 shift -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+Thai_maitho 0x23 -+Thai_maitaikhu 0x23 shift -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+Thai_maiek 0x24 -+Thai_maichattawa 0x24 shift -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+Thai_saraaa 0x25 -+Thai_sorusi 0x25 shift -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+Thai_sosua 0x26 -+Thai_sosala 0x26 shift -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 -+Thai_wowaen 0x27 -+Thai_soso 0x27 shift -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 -+Thai_ngongu 0x28 -+period 0x28 shift -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 -+underscore 0x29 -+percent 0x29 shift -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b -+Thai_khokhuat 0x2b -+Thai_khokhon 0x2b shift -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+Thai_phophung 0x2c -+parenleft 0x2c shift -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+Thai_popla 0x2d -+parenright 0x2d shift -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+Thai_saraae 0x2e -+Thai_choching 0x2e shift -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+Thai_oang 0x2f -+Thai_honokhuk 0x2f shift -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+Thai_sarai 0x30 -+Thai_phinthu 0x30 shift -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+Thai_sarauee 0x31 -+Thai_thanthakhat 0x31 shift -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+Thai_thothahan 0x32 -+question 0x32 shift -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 -+Thai_moma 0x33 -+Thai_thophuthao 0x33 shift -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 -+Thai_saraaimaimuan 0x34 -+Thai_lochula 0x34 shift -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 -+Thai_fofa 0x35 -+Thai_lu 0x35 shift -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Decimal 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 -+less 0x56 -+greater 0x56 shift -+bar 0x56 altgr -+brokenbar 0x56 shift altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+Alt_R 0xb8 -+Meta_R 0xb8 shift -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end -diff --git a/pc-bios/keymaps/tr b/pc-bios/keymaps/tr -index 5650e1e..4d1a4c3 100644 ---- a/pc-bios/keymaps/tr -+++ b/pc-bios/keymaps/tr -@@ -1,123 +1,830 @@ --# generated from XKB map tr --include common --map 0x41f -+# -+# generated by qemu-keymap -+# model : pc105 -+# layout : tr -+# variant : - -+# options : - -+ -+# name: "Turkish" -+ -+# modifiers -+# 0: Shift -+# 1: Lock -+# 2: Control -+# 3: Mod1 -+# 4: Mod2 -+# 5: Mod3 -+# 6: Mod4 -+# 7: Mod5 -+# 8: NumLock -+# 9: Alt -+# 10: LevelThree -+# 11: LAlt -+# 12: RAlt -+# 13: RControl -+# 14: LControl -+# 15: ScrollLock -+# 16: LevelFive -+# 17: AltGr -+# 18: Meta -+# 19: Super -+# 20: Hyper -+ -+# evdev 1 (0x1), QKeyCode "esc", number 0x1 -+Escape 0x01 -+ -+# evdev 2 (0x2), QKeyCode "1", number 0x2 -+1 0x02 - exclam 0x02 shift --onesuperior 0x02 altgr -+greater 0x02 altgr - exclamdown 0x02 shift altgr -+ -+# evdev 3 (0x3), QKeyCode "2", number 0x3 -+2 0x03 - apostrophe 0x03 shift --at 0x03 altgr --oneeighth 0x03 shift altgr --dead_circumflex 0x04 shift -+sterling 0x03 altgr -+twosuperior 0x03 shift altgr -+ -+# evdev 4 (0x4), QKeyCode "3", number 0x4 -+3 0x04 -+asciicircum 0x04 shift - numbersign 0x04 altgr --sterling 0x04 shift altgr -+threesuperior 0x04 shift altgr -+ -+# evdev 5 (0x5), QKeyCode "4", number 0x5 -+4 0x05 - plus 0x05 shift - dollar 0x05 altgr -+onequarter 0x05 shift altgr -+ -+# evdev 6 (0x6), QKeyCode "5", number 0x6 -+5 0x06 - percent 0x06 shift - onehalf 0x06 altgr - threeeighths 0x06 shift altgr -+ -+# evdev 7 (0x7), QKeyCode "6", number 0x7 -+6 0x07 - ampersand 0x07 shift --asciicircum 0x07 altgr --fiveeighths 0x07 shift altgr -+threequarters 0x07 altgr -+VoidSymbol 0x07 shift altgr -+ -+# evdev 8 (0x8), QKeyCode "7", number 0x8 -+7 0x08 - slash 0x08 shift - braceleft 0x08 altgr --seveneighths 0x08 shift altgr -+VoidSymbol 0x08 shift altgr -+ -+# evdev 9 (0x9), QKeyCode "8", number 0x9 -+8 0x09 - parenleft 0x09 shift - bracketleft 0x09 altgr --trademark 0x09 shift altgr -+VoidSymbol 0x09 shift altgr -+ -+# evdev 10 (0xa), QKeyCode "9", number 0xa -+9 0x0a - parenright 0x0a shift - bracketright 0x0a altgr - plusminus 0x0a shift altgr -+ -+# evdev 11 (0xb), QKeyCode "0", number 0xb -+0 0x0b - equal 0x0b shift - braceright 0x0b altgr - degree 0x0b shift altgr -+ -+# evdev 12 (0xc), QKeyCode "minus", number 0xc - asterisk 0x0c - question 0x0c shift - backslash 0x0c altgr - questiondown 0x0c shift altgr -+ -+# evdev 13 (0xd), QKeyCode "equal", number 0xd - minus 0x0d - underscore 0x0d shift --dead_cedilla 0x0d altgr --dead_ogonek 0x0d shift altgr -+bar 0x0d altgr -+VoidSymbol 0x0d shift altgr -+ -+# evdev 14 (0xe), QKeyCode "backspace", number 0xe -+BackSpace 0x0e -+ -+# evdev 15 (0xf), QKeyCode "tab", number 0xf -+Tab 0x0f -+ISO_Left_Tab 0x0f shift -+ -+# evdev 16 (0x10), QKeyCode "q", number 0x10 -+q 0x10 -+Q 0x10 shift - at 0x10 altgr - Greek_OMEGA 0x10 shift altgr --lstroke 0x11 altgr --Lstroke 0x11 shift altgr -+ -+# evdev 17 (0x11), QKeyCode "w", number 0x11 -+w 0x11 -+W 0x11 shift -+VoidSymbol 0x11 altgr -+ -+# evdev 18 (0x12), QKeyCode "e", number 0x12 -+e 0x12 -+E 0x12 shift - EuroSign 0x12 altgr -+VoidSymbol 0x12 shift altgr -+ -+# evdev 19 (0x13), QKeyCode "r", number 0x13 -+r 0x13 -+R 0x13 shift - paragraph 0x13 altgr - registered 0x13 shift altgr --tslash 0x14 altgr --Tslash 0x14 shift altgr -+ -+# evdev 20 (0x14), QKeyCode "t", number 0x14 -+t 0x14 -+T 0x14 shift -+U20BA 0x14 altgr -+VoidSymbol 0x14 shift altgr -+ -+# evdev 21 (0x15), QKeyCode "y", number 0x15 -+y 0x15 -+Y 0x15 shift - leftarrow 0x15 altgr - yen 0x15 shift altgr --downarrow 0x16 altgr --uparrow 0x16 shift altgr -+ -+# evdev 22 (0x16), QKeyCode "u", number 0x16 -+u 0x16 -+U 0x16 shift -+ucircumflex 0x16 altgr -+Ucircumflex 0x16 shift altgr -+ -+# evdev 23 (0x17), QKeyCode "i", number 0x17 - idotless 0x17 - I 0x17 shift --rightarrow 0x17 altgr --oslash 0x18 altgr --Ooblique 0x18 shift altgr --thorn 0x19 altgr --THORN 0x19 shift altgr -+icircumflex 0x17 altgr -+Icircumflex 0x17 shift altgr -+ -+# evdev 24 (0x18), QKeyCode "o", number 0x18 -+o 0x18 -+O 0x18 shift -+ocircumflex 0x18 altgr -+Ocircumflex 0x18 shift altgr -+ -+# evdev 25 (0x19), QKeyCode "p", number 0x19 -+p 0x19 -+P 0x19 shift -+VoidSymbol 0x19 altgr -+ -+# evdev 26 (0x1a), QKeyCode "bracket_left", number 0x1a - gbreve 0x1a - Gbreve 0x1a shift - dead_diaeresis 0x1a altgr - dead_abovering 0x1a shift altgr -+ -+# evdev 27 (0x1b), QKeyCode "bracket_right", number 0x1b - udiaeresis 0x1b - Udiaeresis 0x1b shift - asciitilde 0x1b altgr - dead_macron 0x1b shift altgr --ae 0x1e altgr --AE 0x1e shift altgr --ssharp 0x1f altgr --section 0x1f shift altgr --eth 0x20 altgr --ETH 0x20 shift altgr --dstroke 0x21 altgr --ordfeminine 0x21 shift altgr --eng 0x22 altgr --ENG 0x22 shift altgr --hstroke 0x23 altgr --Hstroke 0x23 shift altgr --kra 0x25 altgr --ampersand 0x25 shift altgr --lstroke 0x26 altgr --Lstroke 0x26 shift altgr -+ -+# evdev 28 (0x1c), QKeyCode "ret", number 0x1c -+Return 0x1c -+ -+# evdev 29 (0x1d), QKeyCode "ctrl", number 0x1d -+Control_L 0x1d -+ -+# evdev 30 (0x1e), QKeyCode "a", number 0x1e -+a 0x1e -+A 0x1e shift -+acircumflex 0x1e altgr -+Acircumflex 0x1e shift altgr -+ -+# evdev 31 (0x1f), QKeyCode "s", number 0x1f -+s 0x1f -+S 0x1f shift -+section 0x1f altgr -+VoidSymbol 0x1f shift altgr -+ -+# evdev 32 (0x20), QKeyCode "d", number 0x20 -+d 0x20 -+D 0x20 shift -+VoidSymbol 0x20 altgr -+ -+# evdev 33 (0x21), QKeyCode "f", number 0x21 -+f 0x21 -+F 0x21 shift -+ordfeminine 0x21 altgr -+VoidSymbol 0x21 shift altgr -+ -+# evdev 34 (0x22), QKeyCode "g", number 0x22 -+g 0x22 -+G 0x22 shift -+VoidSymbol 0x22 altgr -+ -+# evdev 35 (0x23), QKeyCode "h", number 0x23 -+h 0x23 -+H 0x23 shift -+VoidSymbol 0x23 altgr -+ -+# evdev 36 (0x24), QKeyCode "j", number 0x24 -+j 0x24 -+J 0x24 shift -+dead_hook 0x24 altgr -+dead_horn 0x24 shift altgr -+ -+# evdev 37 (0x25), QKeyCode "k", number 0x25 -+k 0x25 -+K 0x25 shift -+VoidSymbol 0x25 altgr -+ -+# evdev 38 (0x26), QKeyCode "l", number 0x26 -+l 0x26 -+L 0x26 shift -+VoidSymbol 0x26 altgr -+ -+# evdev 39 (0x27), QKeyCode "semicolon", number 0x27 - scedilla 0x27 - Scedilla 0x27 shift --dead_acute 0x27 altgr --dead_doubleacute 0x27 shift altgr -+acute 0x27 altgr -+dead_acute 0x27 shift altgr -+ -+# evdev 40 (0x28), QKeyCode "apostrophe", number 0x28 - i 0x28 - Iabovedot 0x28 shift --dead_circumflex 0x28 altgr -+apostrophe 0x28 altgr - dead_caron 0x28 shift altgr --backslash 0x29 --quotedbl 0x29 shift --asciitilde 0x29 altgr -+ -+# evdev 41 (0x29), QKeyCode "grave_accent", number 0x29 -+quotedbl 0x29 -+eacute 0x29 shift -+less 0x29 altgr -+degree 0x29 shift altgr -+ -+# evdev 42 (0x2a), QKeyCode "shift", number 0x2a -+Shift_L 0x2a -+ -+# evdev 43 (0x2b), QKeyCode "backslash", number 0x2b - comma 0x2b - semicolon 0x2b shift --bar 0x2b altgr --dead_breve 0x2b shift altgr -+grave 0x2b altgr -+dead_grave 0x2b shift altgr -+ -+# evdev 44 (0x2c), QKeyCode "z", number 0x2c -+z 0x2c -+Z 0x2c shift - guillemotleft 0x2c altgr - less 0x2c shift altgr -+ -+# evdev 45 (0x2d), QKeyCode "x", number 0x2d -+x 0x2d -+X 0x2d shift - guillemotright 0x2d altgr - greater 0x2d shift altgr -+ -+# evdev 46 (0x2e), QKeyCode "c", number 0x2e -+c 0x2e -+C 0x2e shift - cent 0x2e altgr - copyright 0x2e shift altgr -+ -+# evdev 47 (0x2f), QKeyCode "v", number 0x2f -+v 0x2f -+V 0x2f shift - leftdoublequotemark 0x2f altgr --grave 0x2f shift altgr -+leftsinglequotemark 0x2f shift altgr -+ -+# evdev 48 (0x30), QKeyCode "b", number 0x30 -+b 0x30 -+B 0x30 shift - rightdoublequotemark 0x30 altgr --apostrophe 0x30 shift altgr -+rightsinglequotemark 0x30 shift altgr -+ -+# evdev 49 (0x31), QKeyCode "n", number 0x31 -+n 0x31 -+N 0x31 shift -+ -+# evdev 50 (0x32), QKeyCode "m", number 0x32 -+m 0x32 -+M 0x32 shift - mu 0x32 altgr - masculine 0x32 shift altgr -+ -+# evdev 51 (0x33), QKeyCode "comma", number 0x33 - odiaeresis 0x33 - Odiaeresis 0x33 shift --less 0x33 altgr --multiply 0x33 shift altgr -+multiply 0x33 altgr -+VoidSymbol 0x33 shift altgr -+ -+# evdev 52 (0x34), QKeyCode "dot", number 0x34 - ccedilla 0x34 - Ccedilla 0x34 shift --greater 0x34 altgr -+periodcentered 0x34 altgr - division 0x34 shift altgr -+ -+# evdev 53 (0x35), QKeyCode "slash", number 0x35 - period 0x35 - colon 0x35 shift --dead_belowdot 0x35 altgr --dead_abovedot 0x35 shift altgr -+dead_abovedot 0x35 altgr -+ -+# evdev 54 (0x36), QKeyCode "shift_r", number 0x36 -+Shift_R 0x36 -+ -+# evdev 55 (0x37), QKeyCode "kp_multiply", number 0x37 -+KP_Multiply 0x37 -+ -+# evdev 56 (0x38), QKeyCode "alt", number 0x38 -+Alt_L 0x38 -+Meta_L 0x38 shift -+ -+# evdev 57 (0x39), QKeyCode "spc", number 0x39 -+space 0x39 -+ -+# evdev 58 (0x3a), QKeyCode "caps_lock", number 0x3a -+Caps_Lock 0x3a -+ -+# evdev 59 (0x3b), QKeyCode "f1", number 0x3b -+F1 0x3b -+ -+# evdev 60 (0x3c), QKeyCode "f2", number 0x3c -+F2 0x3c -+ -+# evdev 61 (0x3d), QKeyCode "f3", number 0x3d -+F3 0x3d -+ -+# evdev 62 (0x3e), QKeyCode "f4", number 0x3e -+F4 0x3e -+ -+# evdev 63 (0x3f), QKeyCode "f5", number 0x3f -+F5 0x3f -+ -+# evdev 64 (0x40), QKeyCode "f6", number 0x40 -+F6 0x40 -+ -+# evdev 65 (0x41), QKeyCode "f7", number 0x41 -+F7 0x41 -+ -+# evdev 66 (0x42), QKeyCode "f8", number 0x42 -+F8 0x42 -+ -+# evdev 67 (0x43), QKeyCode "f9", number 0x43 -+F9 0x43 -+ -+# evdev 68 (0x44), QKeyCode "f10", number 0x44 -+F10 0x44 -+ -+# evdev 69 (0x45), QKeyCode "num_lock", number 0x45 -+Num_Lock 0x45 -+ -+# evdev 70 (0x46), QKeyCode "scroll_lock", number 0x46 -+Scroll_Lock 0x46 -+ -+# evdev 71 (0x47), QKeyCode "kp_7", number 0x47 -+KP_Home 0x47 -+KP_7 0x47 numlock -+ -+# evdev 72 (0x48), QKeyCode "kp_8", number 0x48 -+KP_Up 0x48 -+KP_8 0x48 numlock -+ -+# evdev 73 (0x49), QKeyCode "kp_9", number 0x49 -+KP_Prior 0x49 -+KP_9 0x49 numlock -+ -+# evdev 74 (0x4a), QKeyCode "kp_subtract", number 0x4a -+KP_Subtract 0x4a -+ -+# evdev 75 (0x4b), QKeyCode "kp_4", number 0x4b -+KP_Left 0x4b -+KP_4 0x4b numlock -+ -+# evdev 76 (0x4c), QKeyCode "kp_5", number 0x4c -+KP_Begin 0x4c -+KP_5 0x4c numlock -+ -+# evdev 77 (0x4d), QKeyCode "kp_6", number 0x4d -+KP_Right 0x4d -+KP_6 0x4d numlock -+ -+# evdev 78 (0x4e), QKeyCode "kp_add", number 0x4e -+KP_Add 0x4e -+ -+# evdev 79 (0x4f), QKeyCode "kp_1", number 0x4f -+KP_End 0x4f -+KP_1 0x4f numlock -+ -+# evdev 80 (0x50), QKeyCode "kp_2", number 0x50 -+KP_Down 0x50 -+KP_2 0x50 numlock -+ -+# evdev 81 (0x51), QKeyCode "kp_3", number 0x51 -+KP_Next 0x51 -+KP_3 0x51 numlock -+ -+# evdev 82 (0x52), QKeyCode "kp_0", number 0x52 -+KP_Insert 0x52 -+KP_0 0x52 numlock -+ -+# evdev 83 (0x53), QKeyCode "kp_decimal", number 0x53 -+KP_Delete 0x53 -+KP_Separator 0x53 numlock -+ -+# evdev 84 (0x54): no evdev -> QKeyCode mapping (xkb keysym ISO_Level3_Shift) -+ -+# evdev 85 (0x55): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 86 (0x56), QKeyCode "less", number 0x56 -+less 0x56 -+greater 0x56 shift -+bar 0x56 altgr -+brokenbar 0x56 shift altgr -+ -+# evdev 87 (0x57), QKeyCode "f11", number 0x57 -+F11 0x57 -+ -+# evdev 88 (0x58), QKeyCode "f12", number 0x58 -+F12 0x58 -+ -+# evdev 89 (0x59), QKeyCode "ro", number 0x73 -+ -+# evdev 90 (0x5a): no evdev -> QKeyCode mapping (xkb keysym Katakana) -+ -+# evdev 91 (0x5b), QKeyCode "hiragana", number 0x77 -+Hiragana 0x77 -+ -+# evdev 92 (0x5c), QKeyCode "henkan", number 0x79 -+Henkan_Mode 0x79 -+ -+# evdev 93 (0x5d): no evdev -> QKeyCode mapping (xkb keysym Hiragana_Katakana) -+ -+# evdev 94 (0x5e): no evdev -> QKeyCode mapping (xkb keysym Muhenkan) -+ -+# evdev 95 (0x5f): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 96 (0x60), QKeyCode "kp_enter", number 0x9c -+KP_Enter 0x9c -+ -+# evdev 97 (0x61), QKeyCode "ctrl_r", number 0x9d -+Control_R 0x9d -+ -+# evdev 98 (0x62), QKeyCode "kp_divide", number 0xb5 -+KP_Divide 0xb5 -+ -+# evdev 99 (0x63), QKeyCode "sysrq", number 0x54 -+Print 0x54 -+ -+# evdev 100 (0x64), QKeyCode "alt_r", number 0xb8 -+ISO_Level3_Shift 0xb8 -+ -+# evdev 101 (0x65), QKeyCode "lf", number 0x5b -+Linefeed 0x5b -+ -+# evdev 102 (0x66), QKeyCode "home", number 0xc7 -+Home 0xc7 -+ -+# evdev 103 (0x67), QKeyCode "up", number 0xc8 -+Up 0xc8 -+ -+# evdev 104 (0x68), QKeyCode "pgup", number 0xc9 -+Prior 0xc9 -+ -+# evdev 105 (0x69), QKeyCode "left", number 0xcb -+Left 0xcb -+ -+# evdev 106 (0x6a), QKeyCode "right", number 0xcd -+Right 0xcd -+ -+# evdev 107 (0x6b), QKeyCode "end", number 0xcf -+End 0xcf -+ -+# evdev 108 (0x6c), QKeyCode "down", number 0xd0 -+Down 0xd0 -+ -+# evdev 109 (0x6d), QKeyCode "pgdn", number 0xd1 -+Next 0xd1 -+ -+# evdev 110 (0x6e), QKeyCode "insert", number 0xd2 -+Insert 0xd2 -+ -+# evdev 111 (0x6f), QKeyCode "delete", number 0xd3 -+Delete 0xd3 -+ -+# evdev 112 (0x70): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 113 (0x71), QKeyCode "audiomute", number 0xa0 -+XF86AudioMute 0xa0 -+ -+# evdev 114 (0x72), QKeyCode "volumedown", number 0xae -+XF86AudioLowerVolume 0xae -+ -+# evdev 115 (0x73), QKeyCode "volumeup", number 0xb0 -+XF86AudioRaiseVolume 0xb0 -+ -+# evdev 116 (0x74), QKeyCode "power", number 0xde -+XF86PowerOff 0xde -+ -+# evdev 117 (0x75), QKeyCode "kp_equals", number 0x59 -+KP_Equal 0x59 -+ -+# evdev 118 (0x76): no evdev -> QKeyCode mapping (xkb keysym plusminus) -+ -+# evdev 119 (0x77), QKeyCode "pause", number 0xc6 -+Pause 0xc6 -+ -+# evdev 120 (0x78): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchA) -+ -+# evdev 121 (0x79), QKeyCode "kp_comma", number 0x7e -+KP_Decimal 0x7e -+ -+# evdev 122 (0x7a): no evdev -> QKeyCode mapping (xkb keysym Hangul) -+ -+# evdev 123 (0x7b): no evdev -> QKeyCode mapping (xkb keysym Hangul_Hanja) -+ -+# evdev 124 (0x7c), QKeyCode "yen", number 0x7d -+ -+# evdev 125 (0x7d), QKeyCode "meta_l", number 0xdb -+Super_L 0xdb -+ -+# evdev 126 (0x7e), QKeyCode "meta_r", number 0xdc -+Super_R 0xdc -+ -+# evdev 127 (0x7f), QKeyCode "compose", number 0xdd -+Menu 0xdd -+ -+# evdev 128 (0x80), QKeyCode "stop", number 0xe8 -+Cancel 0xe8 -+ -+# evdev 129 (0x81), QKeyCode "again", number 0x85 -+Redo 0x85 -+ -+# evdev 130 (0x82), QKeyCode "props", number 0x86 -+SunProps 0x86 -+ -+# evdev 131 (0x83), QKeyCode "undo", number 0x87 -+Undo 0x87 -+ -+# evdev 132 (0x84), QKeyCode "front", number 0x8c -+SunFront 0x8c -+ -+# evdev 133 (0x85), QKeyCode "copy", number 0xf8 -+XF86Copy 0xf8 -+ -+# evdev 134 (0x86), QKeyCode "open", number 0x64 -+XF86Open 0x64 -+ -+# evdev 135 (0x87), QKeyCode "paste", number 0x65 -+XF86Paste 0x65 -+ -+# evdev 136 (0x88), QKeyCode "find", number 0xc1 -+Find 0xc1 -+ -+# evdev 137 (0x89), QKeyCode "cut", number 0xbc -+XF86Cut 0xbc -+ -+# evdev 138 (0x8a), QKeyCode "help", number 0xf5 -+Help 0xf5 -+ -+# evdev 139 (0x8b), QKeyCode "menu", number 0x9e -+XF86MenuKB 0x9e -+ -+# evdev 140 (0x8c), QKeyCode "calculator", number 0xa1 -+XF86Calculator 0xa1 -+ -+# evdev 141 (0x8d): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 142 (0x8e), QKeyCode "sleep", number 0xdf -+XF86Sleep 0xdf -+ -+# evdev 143 (0x8f), QKeyCode "wake", number 0xe3 -+XF86WakeUp 0xe3 -+ -+# evdev 144 (0x90): no evdev -> QKeyCode mapping (xkb keysym XF86Explorer) -+ -+# evdev 145 (0x91): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 146 (0x92): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 147 (0x93): no evdev -> QKeyCode mapping (xkb keysym XF86Xfer) -+ -+# evdev 148 (0x94): no evdev -> QKeyCode mapping (xkb keysym XF86Launch1) -+ -+# evdev 149 (0x95): no evdev -> QKeyCode mapping (xkb keysym XF86Launch2) -+ -+# evdev 150 (0x96): no evdev -> QKeyCode mapping (xkb keysym XF86WWW) -+ -+# evdev 151 (0x97): no evdev -> QKeyCode mapping (xkb keysym XF86DOS) -+ -+# evdev 152 (0x98): no evdev -> QKeyCode mapping (xkb keysym XF86ScreenSaver) -+ -+# evdev 153 (0x99): no evdev -> QKeyCode mapping (xkb keysym XF86RotateWindows) -+ -+# evdev 154 (0x9a): no evdev -> QKeyCode mapping (xkb keysym XF86TaskPane) -+ -+# evdev 155 (0x9b), QKeyCode "mail", number 0xec -+XF86Mail 0xec -+ -+# evdev 156 (0x9c), QKeyCode "ac_bookmarks", number 0xe6 -+XF86Favorites 0xe6 -+ -+# evdev 157 (0x9d), QKeyCode "computer", number 0xeb -+XF86MyComputer 0xeb -+ -+# evdev 158 (0x9e), QKeyCode "ac_back", number 0xea -+XF86Back 0xea -+ -+# evdev 159 (0x9f), QKeyCode "ac_forward", number 0xe9 -+XF86Forward 0xe9 -+ -+# evdev 160 (0xa0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 161 (0xa1): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 162 (0xa2): no evdev -> QKeyCode mapping (xkb keysym XF86Eject) -+ -+# evdev 163 (0xa3), QKeyCode "audionext", number 0x99 -+XF86AudioNext 0x99 -+ -+# evdev 164 (0xa4), QKeyCode "audioplay", number 0xa2 -+XF86AudioPlay 0xa2 -+XF86AudioPause 0xa2 shift -+ -+# evdev 165 (0xa5), QKeyCode "audioprev", number 0x90 -+XF86AudioPrev 0x90 -+ -+# evdev 166 (0xa6), QKeyCode "audiostop", number 0xa4 -+XF86AudioStop 0xa4 -+XF86Eject 0xa4 shift -+ -+# evdev 167 (0xa7): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRecord) -+ -+# evdev 168 (0xa8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioRewind) -+ -+# evdev 169 (0xa9): no evdev -> QKeyCode mapping (xkb keysym XF86Phone) -+ -+# evdev 170 (0xaa): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 171 (0xab): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 172 (0xac), QKeyCode "ac_home", number 0xb2 -+XF86HomePage 0xb2 -+ -+# evdev 173 (0xad), QKeyCode "ac_refresh", number 0xe7 -+XF86Reload 0xe7 -+ -+# evdev 174 (0xae): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 175 (0xaf): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 176 (0xb0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 177 (0xb1): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollUp) -+ -+# evdev 178 (0xb2): no evdev -> QKeyCode mapping (xkb keysym XF86ScrollDown) -+ -+# evdev 179 (0xb3): no evdev -> QKeyCode mapping (xkb keysym parenleft) -+ -+# evdev 180 (0xb4): no evdev -> QKeyCode mapping (xkb keysym parenright) -+ -+# evdev 181 (0xb5): no evdev -> QKeyCode mapping (xkb keysym XF86New) -+ -+# evdev 182 (0xb6): no evdev -> QKeyCode mapping (xkb keysym Redo) -+ -+# evdev 183 (0xb7): no evdev -> QKeyCode mapping (xkb keysym XF86Tools) -+ -+# evdev 184 (0xb8): no evdev -> QKeyCode mapping (xkb keysym XF86Launch5) -+ -+# evdev 185 (0xb9): no evdev -> QKeyCode mapping (xkb keysym XF86Launch6) -+ -+# evdev 186 (0xba): no evdev -> QKeyCode mapping (xkb keysym XF86Launch7) -+ -+# evdev 187 (0xbb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch8) -+ -+# evdev 188 (0xbc): no evdev -> QKeyCode mapping (xkb keysym XF86Launch9) -+ -+# evdev 189 (0xbd): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 190 (0xbe): no evdev -> QKeyCode mapping (xkb keysym XF86AudioMicMute) -+ -+# evdev 191 (0xbf): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadToggle) -+ -+# evdev 192 (0xc0): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOn) -+ -+# evdev 193 (0xc1): no evdev -> QKeyCode mapping (xkb keysym XF86TouchpadOff) -+ -+# evdev 194 (0xc2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 195 (0xc3): no evdev -> QKeyCode mapping (xkb keysym Mode_switch) -+ -+# evdev 196 (0xc4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 197 (0xc5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 198 (0xc6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 199 (0xc7): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 200 (0xc8): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 201 (0xc9): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPause) -+ -+# evdev 202 (0xca): no evdev -> QKeyCode mapping (xkb keysym XF86Launch3) -+ -+# evdev 203 (0xcb): no evdev -> QKeyCode mapping (xkb keysym XF86Launch4) -+ -+# evdev 204 (0xcc): no evdev -> QKeyCode mapping (xkb keysym XF86LaunchB) -+ -+# evdev 205 (0xcd): no evdev -> QKeyCode mapping (xkb keysym XF86Suspend) -+ -+# evdev 206 (0xce): no evdev -> QKeyCode mapping (xkb keysym XF86Close) -+ -+# evdev 207 (0xcf): no evdev -> QKeyCode mapping (xkb keysym XF86AudioPlay) -+ -+# evdev 208 (0xd0): no evdev -> QKeyCode mapping (xkb keysym XF86AudioForward) -+ -+# evdev 209 (0xd1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 210 (0xd2): no evdev -> QKeyCode mapping (xkb keysym Print) -+ -+# evdev 211 (0xd3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 212 (0xd4): no evdev -> QKeyCode mapping (xkb keysym XF86WebCam) -+ -+# evdev 213 (0xd5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 214 (0xd6): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 215 (0xd7): no evdev -> QKeyCode mapping (xkb keysym XF86Mail) -+ -+# evdev 216 (0xd8): no evdev -> QKeyCode mapping (xkb keysym XF86Messenger) -+ -+# evdev 217 (0xd9): no evdev -> QKeyCode mapping (xkb keysym XF86Search) -+ -+# evdev 218 (0xda): no evdev -> QKeyCode mapping (xkb keysym XF86Go) -+ -+# evdev 219 (0xdb): no evdev -> QKeyCode mapping (xkb keysym XF86Finance) -+ -+# evdev 220 (0xdc): no evdev -> QKeyCode mapping (xkb keysym XF86Game) -+ -+# evdev 221 (0xdd): no evdev -> QKeyCode mapping (xkb keysym XF86Shop) -+ -+# evdev 222 (0xde): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 223 (0xdf): no evdev -> QKeyCode mapping (xkb keysym Cancel) -+ -+# evdev 224 (0xe0): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessDown) -+ -+# evdev 225 (0xe1): no evdev -> QKeyCode mapping (xkb keysym XF86MonBrightnessUp) -+ -+# evdev 226 (0xe2), QKeyCode "mediaselect", number 0xed -+XF86AudioMedia 0xed -+ -+# evdev 227 (0xe3): no evdev -> QKeyCode mapping (xkb keysym XF86Display) -+ -+# evdev 228 (0xe4): no evdev -> QKeyCode mapping (xkb keysym XF86KbdLightOnOff) -+ -+# evdev 229 (0xe5): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessDown) -+ -+# evdev 230 (0xe6): no evdev -> QKeyCode mapping (xkb keysym XF86KbdBrightnessUp) -+ -+# evdev 231 (0xe7): no evdev -> QKeyCode mapping (xkb keysym XF86Send) -+ -+# evdev 232 (0xe8): no evdev -> QKeyCode mapping (xkb keysym XF86Reply) -+ -+# evdev 233 (0xe9): no evdev -> QKeyCode mapping (xkb keysym XF86MailForward) -+ -+# evdev 234 (0xea): no evdev -> QKeyCode mapping (xkb keysym XF86Save) -+ -+# evdev 235 (0xeb): no evdev -> QKeyCode mapping (xkb keysym XF86Documents) -+ -+# evdev 236 (0xec): no evdev -> QKeyCode mapping (xkb keysym XF86Battery) -+ -+# evdev 237 (0xed): no evdev -> QKeyCode mapping (xkb keysym XF86Bluetooth) -+ -+# evdev 238 (0xee): no evdev -> QKeyCode mapping (xkb keysym XF86WLAN) -+ -+# evdev 239 (0xef): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 240 (0xf0): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 241 (0xf1): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 242 (0xf2): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 243 (0xf3): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 244 (0xf4): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# evdev 245 (0xf5): no evdev -> QKeyCode mapping (xkb keysym NoSymbol) -+ -+# -+# quirks section start -+# -+# Sometimes multiple keysyms map to the same keycodes. -+# The keycode -> keysym lookup finds only one of the -+# keysyms. So append them here. -+# -+ -+Print 0x54 -+Sys_Req 0x54 -+Execute 0x54 -+KP_Decimal 0x53 numlock -+KP_Separator 0x53 numlock -+Alt_R 0xb8 -+ISO_Level3_Shift 0xb8 -+Mode_switch 0xb8 -+ -+# quirks section end --- -1.8.3.1 - diff --git a/SOURCES/kvm-pc-bios-s390-ccw-Fix-problem-with-invalid-virtio-scs.patch b/SOURCES/kvm-pc-bios-s390-ccw-Fix-problem-with-invalid-virtio-scs.patch deleted file mode 100644 index 6876bd7..0000000 --- a/SOURCES/kvm-pc-bios-s390-ccw-Fix-problem-with-invalid-virtio-scs.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 544ee34c5f878c51e72d75d1384eed8ae38cf2a5 Mon Sep 17 00:00:00 2001 -From: Thomas Huth -Date: Wed, 22 Nov 2017 10:43:31 +0100 -Subject: [PATCH 14/15] pc-bios/s390-ccw: Fix problem with invalid virtio-scsi - LUN when rebooting - -RH-Author: Thomas Huth -Message-id: <1511347411-16226-4-git-send-email-thuth@redhat.com> -Patchwork-id: 77776 -O-Subject: [RHEL-7.5 qemu-kvm-ma PATCH 3/3] pc-bios/s390-ccw: Fix problem with invalid virtio-scsi LUN when rebooting -Bugzilla: 1514352 -RH-Acked-by: David Hildenbrand -RH-Acked-by: Cornelia Huck -RH-Acked-by: Miroslav Rezanina - -When rebooting a guest that has a virtio-scsi disk, the s390-ccw -bios sometimes bails out with an error message like this: - -! SCSI cannot report LUNs: STATUS=02 RSPN=70 KEY=05 CODE=25 QLFR=00, sure ! - -Enabling the scsi_req* tracing in QEMU shows that the ccw bios is -trying to execute the REPORT LUNS SCSI command with a LUN != 0, and -this causes the SCSI command to fail. -Looks like we neither clear the BSS of the s390-ccw bios during reboot, -nor do we explicitly set the default_scsi_device.lun value to 0, so -this variable can contain random values from the OS after the reboot. -By setting this variable explicitly to 0, the problem is fixed and -the reboots always succeed. - -Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1514352 -Signed-off-by: Thomas Huth -Message-Id: <1510942228-22822-1-git-send-email-thuth@redhat.com> -Acked-by: Christian Borntraeger -Reviewed-by: David Hildenbrand -Signed-off-by: Cornelia Huck -(cherry picked from commit 8775d91a0f42d016833330881bb587982db88a3c) -Signed-off-by: Miroslav Rezanina ---- - pc-bios/s390-ccw/virtio-scsi.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/pc-bios/s390-ccw/virtio-scsi.c b/pc-bios/s390-ccw/virtio-scsi.c -index c92f5d3..4fe4b9d 100644 ---- a/pc-bios/s390-ccw/virtio-scsi.c -+++ b/pc-bios/s390-ccw/virtio-scsi.c -@@ -223,7 +223,8 @@ static void virtio_scsi_locate_device(VDev *vdev) - - for (target = 0; target <= vdev->config.scsi.max_target; target++) { - sdev->channel = channel; -- sdev->target = target; /* sdev->lun will be 0 here */ -+ sdev->target = target; -+ sdev->lun = 0; /* LUN has to be 0 for REPORT LUNS */ - if (!scsi_report_luns(vdev, data, sizeof(data))) { - if (resp.response == VIRTIO_SCSI_S_BAD_TARGET) { - continue; --- -1.8.3.1 - diff --git a/SOURCES/kvm-pc-bios-s390-ccw-fix-loadparm-initialization-and-int.patch b/SOURCES/kvm-pc-bios-s390-ccw-fix-loadparm-initialization-and-int.patch new file mode 100644 index 0000000..875f3bc --- /dev/null +++ b/SOURCES/kvm-pc-bios-s390-ccw-fix-loadparm-initialization-and-int.patch @@ -0,0 +1,107 @@ +From eac5906d2b0edecae91115e41d899c6220ff1267 Mon Sep 17 00:00:00 2001 +From: Thomas Huth +Date: Mon, 7 May 2018 07:58:06 +0200 +Subject: [PATCH 10/13] pc-bios/s390-ccw: fix loadparm initialization and int + conversion + +RH-Author: Thomas Huth +Message-id: <1525679888-9234-5-git-send-email-thuth@redhat.com> +Patchwork-id: 80055 +O-Subject: [RHEL-7.6 qemu-kvm-ma PATCH 4/6] pc-bios/s390-ccw: fix loadparm initialization and int conversion +Bugzilla: 1523857 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Cornelia Huck +RH-Acked-by: Laszlo Ersek + +From: Collin Walling + +Rename the loadparm char array in main.c to loadparm_str and +increased the size by one byte to account for a null termination +when converting the loadparm string to an int via atoui. We +also allow the boot menu to be enabled when loadparm is set to +an empty string or a series of spaces. + +Signed-off-by: Collin Walling +Reported-by: Vasily Gorbik +Reviewed-by: Thomas Huth +Reviewed-by: Janosch Frank +Signed-off-by: Thomas Huth +(cherry picked from commit 074afe60d4c8167dcfaee7aca1065c6360449eaa) +Signed-off-by: Miroslav Rezanina +--- + hw/s390x/ipl.c | 4 ++++ + pc-bios/s390-ccw/main.c | 14 +++++++------- + 2 files changed, 11 insertions(+), 7 deletions(-) + +diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c +index fb554ab..150f6c0 100644 +--- a/hw/s390x/ipl.c ++++ b/hw/s390x/ipl.c +@@ -373,6 +373,10 @@ int s390_ipl_set_loadparm(uint8_t *loadparm) + loadparm[i] = ascii2ebcdic[(uint8_t) lp[i]]; + } + ++ if (i < 8) { ++ memset(loadparm + i, 0x40, 8 - i); /* fill with EBCDIC spaces */ ++ } ++ + g_free(lp); + return 0; + } +diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c +index 9d9f8cf..26f9adf 100644 +--- a/pc-bios/s390-ccw/main.c ++++ b/pc-bios/s390-ccw/main.c +@@ -15,11 +15,11 @@ + char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE))); + static SubChannelId blk_schid = { .one = 1 }; + IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE))); +-static char loadparm[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; ++static char loadparm_str[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + QemuIplParameters qipl; + + #define LOADPARM_PROMPT "PROMPT " +-#define LOADPARM_EMPTY "........" ++#define LOADPARM_EMPTY " " + #define BOOT_MENU_FLAG_MASK (QIPL_FLAG_BM_OPTS_CMD | QIPL_FLAG_BM_OPTS_ZIPL) + + /* +@@ -45,7 +45,7 @@ void panic(const char *string) + + unsigned int get_loadparm_index(void) + { +- return atoui(loadparm); ++ return atoui(loadparm_str); + } + + static bool find_dev(Schib *schib, int dev_no) +@@ -80,13 +80,13 @@ static bool find_dev(Schib *schib, int dev_no) + + static void menu_setup(void) + { +- if (memcmp(loadparm, LOADPARM_PROMPT, 8) == 0) { ++ if (memcmp(loadparm_str, LOADPARM_PROMPT, 8) == 0) { + menu_set_parms(QIPL_FLAG_BM_OPTS_CMD, 0); + return; + } + + /* If loadparm was set to any other value, then do not enable menu */ +- if (memcmp(loadparm, LOADPARM_EMPTY, 8) != 0) { ++ if (memcmp(loadparm_str, LOADPARM_EMPTY, 8) != 0) { + return; + } + +@@ -116,8 +116,8 @@ static void virtio_setup(void) + */ + enable_mss_facility(); + +- sclp_get_loadparm_ascii(loadparm); +- memcpy(ldp + 10, loadparm, 8); ++ sclp_get_loadparm_ascii(loadparm_str); ++ memcpy(ldp + 10, loadparm_str, 8); + sclp_print(ldp); + + memcpy(&qipl, early_qipl, sizeof(QemuIplParameters)); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pc-bios-s390-ccw-fix-non-sequential-boot-entries-eck.patch b/SOURCES/kvm-pc-bios-s390-ccw-fix-non-sequential-boot-entries-eck.patch new file mode 100644 index 0000000..a5be5b2 --- /dev/null +++ b/SOURCES/kvm-pc-bios-s390-ccw-fix-non-sequential-boot-entries-eck.patch @@ -0,0 +1,118 @@ +From 3ded1fcf70af2fa1a3a785b777e7f724bd285fc3 Mon Sep 17 00:00:00 2001 +From: Thomas Huth +Date: Mon, 7 May 2018 07:58:07 +0200 +Subject: [PATCH 11/13] pc-bios/s390-ccw: fix non-sequential boot entries + (eckd) + +RH-Author: Thomas Huth +Message-id: <1525679888-9234-6-git-send-email-thuth@redhat.com> +Patchwork-id: 80053 +O-Subject: [RHEL-7.6 qemu-kvm-ma PATCH 5/6] pc-bios/s390-ccw: fix non-sequential boot entries (eckd) +Bugzilla: 1523857 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Cornelia Huck +RH-Acked-by: Laszlo Ersek + +From: Collin Walling + +zIPL boot menu entries can be non-sequential. Let's account +for this issue for the s390 zIPL boot menu. Since this boot +menu is actually an imitation and is not completely capable +of everything the real zIPL menu can do, let's also print a +different banner to the user. + +Signed-off-by: Collin Walling +Reported-by: Vasily Gorbik +Reviewed-by: Thomas Huth +Reviewed-by: Janosch Frank +Signed-off-by: Thomas Huth +(cherry picked from commit 7385e947fc65a44dd05abb86c874beb915c1989c) +Signed-off-by: Miroslav Rezanina +--- + pc-bios/s390-ccw/menu.c | 29 ++++++++++++++++++++--------- + 1 file changed, 20 insertions(+), 9 deletions(-) + +diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c +index 96eec81..aaf5d61 100644 +--- a/pc-bios/s390-ccw/menu.c ++++ b/pc-bios/s390-ccw/menu.c +@@ -158,7 +158,7 @@ static void boot_menu_prompt(bool retry) + } + } + +-static int get_boot_index(int entries) ++static int get_boot_index(bool *valid_entries) + { + int boot_index; + bool retry = false; +@@ -168,7 +168,8 @@ static int get_boot_index(int entries) + boot_menu_prompt(retry); + boot_index = get_index(); + retry = true; +- } while (boot_index < 0 || boot_index >= entries); ++ } while (boot_index < 0 || boot_index >= MAX_BOOT_ENTRIES || ++ !valid_entries[boot_index]); + + sclp_print("\nBooting entry #"); + sclp_print(uitoa(boot_index, tmp, sizeof(tmp))); +@@ -176,7 +177,8 @@ static int get_boot_index(int entries) + return boot_index; + } + +-static void zipl_println(const char *data, size_t len) ++/* Returns the entry number that was printed */ ++static int zipl_print_entry(const char *data, size_t len) + { + char buf[len + 2]; + +@@ -185,12 +187,15 @@ static void zipl_println(const char *data, size_t len) + buf[len + 1] = '\0'; + + sclp_print(buf); ++ ++ return buf[0] == ' ' ? atoui(buf + 1) : atoui(buf); + } + + int menu_get_zipl_boot_index(const char *menu_data) + { + size_t len; +- int entries; ++ int entry; ++ bool valid_entries[MAX_BOOT_ENTRIES] = {false}; + uint16_t zipl_flag = *(uint16_t *)(menu_data - ZIPL_FLAG_OFFSET); + uint16_t zipl_timeout = *(uint16_t *)(menu_data - ZIPL_TIMEOUT_OFFSET); + +@@ -202,19 +207,25 @@ int menu_get_zipl_boot_index(const char *menu_data) + timeout = zipl_timeout * 1000; + } + +- /* Print and count all menu items, including the banner */ +- for (entries = 0; *menu_data; entries++) { ++ /* Print banner */ ++ sclp_print("s390-ccw zIPL Boot Menu\n\n"); ++ menu_data += strlen(menu_data) + 1; ++ ++ /* Print entries */ ++ while (*menu_data) { + len = strlen(menu_data); +- zipl_println(menu_data, len); ++ entry = zipl_print_entry(menu_data, len); + menu_data += len + 1; + +- if (entries < 2) { ++ valid_entries[entry] = true; ++ ++ if (entry == 0) { + sclp_print("\n"); + } + } + + sclp_print("\n"); +- return get_boot_index(entries - 1); /* subtract 1 to exclude banner */ ++ return get_boot_index(valid_entries); + } + + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pc-bios-s390-ccw-fix-non-sequential-boot-entries-enu.patch b/SOURCES/kvm-pc-bios-s390-ccw-fix-non-sequential-boot-entries-enu.patch new file mode 100644 index 0000000..32d078b --- /dev/null +++ b/SOURCES/kvm-pc-bios-s390-ccw-fix-non-sequential-boot-entries-enu.patch @@ -0,0 +1,148 @@ +From 81a0dae65a07d9323c78c6bc9adc7f8dbbb19145 Mon Sep 17 00:00:00 2001 +From: Thomas Huth +Date: Mon, 7 May 2018 07:58:08 +0200 +Subject: [PATCH 12/13] pc-bios/s390-ccw: fix non-sequential boot entries + (enum) + +RH-Author: Thomas Huth +Message-id: <1525679888-9234-7-git-send-email-thuth@redhat.com> +Patchwork-id: 80054 +O-Subject: [RHEL-7.6 qemu-kvm-ma PATCH 6/6] pc-bios/s390-ccw: fix non-sequential boot entries (enum) +Bugzilla: 1523857 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Cornelia Huck +RH-Acked-by: Laszlo Ersek + +From: Collin Walling + +zIPL boot menu entries can be non-sequential. Let's account +for this issue for the s390 enumerated boot menu. Since we +can no longer print a range of available entries to the +user, we have to present a list of each available entry. + +An example of this menu: + + s390-ccw Enumerated Boot Menu. + + [0] default + + [1] + [2] + [7] + [8] + [9] + [11] + [12] + + Please choose: + +Signed-off-by: Collin Walling +Reported-by: Vasily Gorbik +Reviewed-by: Thomas Huth +Reviewed-by: Janosch Frank +Signed-off-by: Thomas Huth +(cherry picked from commit 622b39178057289a1c8c1b5148f513e658e90ea1) +Signed-off-by: Miroslav Rezanina +--- + pc-bios/s390-ccw/bootmap.c | 12 +++++++----- + pc-bios/s390-ccw/menu.c | 29 ++++++++++++++++++++--------- + pc-bios/s390-ccw/s390-ccw.h | 2 +- + 3 files changed, 28 insertions(+), 15 deletions(-) + +diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c +index b767fa2..e41e715 100644 +--- a/pc-bios/s390-ccw/bootmap.c ++++ b/pc-bios/s390-ccw/bootmap.c +@@ -565,6 +565,8 @@ static void ipl_scsi(void) + int program_table_entries = 0; + BootMapTable *prog_table = (void *)sec; + unsigned int loadparm = get_loadparm_index(); ++ bool valid_entries[MAX_BOOT_ENTRIES] = {false}; ++ size_t i; + + /* Grab the MBR */ + memset(sec, FREE_SPACE_FILLER, sizeof(sec)); +@@ -585,18 +587,18 @@ static void ipl_scsi(void) + read_block(mbr->pt.blockno, sec, "Error reading Program Table"); + IPL_assert(magic_match(sec, ZIPL_MAGIC), "No zIPL magic in PT"); + +- while (program_table_entries < MAX_BOOT_ENTRIES) { +- if (!prog_table->entry[program_table_entries].scsi.blockno) { +- break; ++ for (i = 0; i < MAX_BOOT_ENTRIES; i++) { ++ if (prog_table->entry[i].scsi.blockno) { ++ valid_entries[i] = true; ++ program_table_entries++; + } +- program_table_entries++; + } + + debug_print_int("program table entries", program_table_entries); + IPL_assert(program_table_entries != 0, "Empty Program Table"); + + if (menu_is_enabled_enum()) { +- loadparm = menu_get_enum_boot_index(program_table_entries); ++ loadparm = menu_get_enum_boot_index(valid_entries); + } + + debug_print_int("loadparm", loadparm); +diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c +index aaf5d61..82a4ae6 100644 +--- a/pc-bios/s390-ccw/menu.c ++++ b/pc-bios/s390-ccw/menu.c +@@ -228,19 +228,30 @@ int menu_get_zipl_boot_index(const char *menu_data) + return get_boot_index(valid_entries); + } + +- +-int menu_get_enum_boot_index(int entries) ++int menu_get_enum_boot_index(bool *valid_entries) + { +- char tmp[4]; ++ char tmp[3]; ++ int i; + +- sclp_print("s390x Enumerated Boot Menu.\n\n"); ++ sclp_print("s390-ccw Enumerated Boot Menu.\n\n"); + +- sclp_print(uitoa(entries, tmp, sizeof(tmp))); +- sclp_print(" entries detected. Select from boot index 0 to "); +- sclp_print(uitoa(entries - 1, tmp, sizeof(tmp))); +- sclp_print(".\n\n"); ++ for (i = 0; i < MAX_BOOT_ENTRIES; i++) { ++ if (valid_entries[i]) { ++ if (i < 10) { ++ sclp_print(" "); ++ } ++ sclp_print("["); ++ sclp_print(uitoa(i, tmp, sizeof(tmp))); ++ sclp_print("]"); ++ if (i == 0) { ++ sclp_print(" default\n"); ++ } ++ sclp_print("\n"); ++ } ++ } + +- return get_boot_index(entries); ++ sclp_print("\n"); ++ return get_boot_index(valid_entries); + } + + void menu_set_parms(uint8_t boot_menu_flag, uint32_t boot_menu_timeout) +diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h +index 2c9e601..a1bdb4c 100644 +--- a/pc-bios/s390-ccw/s390-ccw.h ++++ b/pc-bios/s390-ccw/s390-ccw.h +@@ -91,7 +91,7 @@ void zipl_load(void); + void menu_set_parms(uint8_t boot_menu_flag, uint32_t boot_menu_timeout); + int menu_get_zipl_boot_index(const char *menu_data); + bool menu_is_enabled_zipl(void); +-int menu_get_enum_boot_index(int entries); ++int menu_get_enum_boot_index(bool *valid_entries); + bool menu_is_enabled_enum(void); + + #define MAX_BOOT_ENTRIES 31 +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pc-bios-s390-ccw-rename-MAX_TABLE_ENTRIES-to-MAX_BOO.patch b/SOURCES/kvm-pc-bios-s390-ccw-rename-MAX_TABLE_ENTRIES-to-MAX_BOO.patch new file mode 100644 index 0000000..d43581a --- /dev/null +++ b/SOURCES/kvm-pc-bios-s390-ccw-rename-MAX_TABLE_ENTRIES-to-MAX_BOO.patch @@ -0,0 +1,95 @@ +From cb2f6e00200df2c15a22f54196879c523fa610da Mon Sep 17 00:00:00 2001 +From: Thomas Huth +Date: Mon, 7 May 2018 07:58:05 +0200 +Subject: [PATCH 09/13] pc-bios/s390-ccw: rename MAX_TABLE_ENTRIES to + MAX_BOOT_ENTRIES + +RH-Author: Thomas Huth +Message-id: <1525679888-9234-4-git-send-email-thuth@redhat.com> +Patchwork-id: 80052 +O-Subject: [RHEL-7.6 qemu-kvm-ma PATCH 3/6] pc-bios/s390-ccw: rename MAX_TABLE_ENTRIES to MAX_BOOT_ENTRIES +Bugzilla: 1523857 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Cornelia Huck +RH-Acked-by: Laszlo Ersek + +From: Collin Walling + +The MAX_TABLE_ENTRIES constant has a name that is too generic. As we +want to declare a limit for boot menu entries, let's rename it to a more +fitting MAX_BOOT_ENTRIES and set its value to 31 (30 boot entries and +1 default entry). Also we move it from bootmap.h to s390-ccw.h to make +it available for menu.c in a later patch. + +Signed-off-by: Collin Walling +Reviewed-by: Thomas Huth +Reviewed-by: Janosch Frank +Signed-off-by: Thomas Huth +(cherry picked from commit 6df2a829dfacfbf10a78199ad4b023a7ea65d9cd) +Signed-off-by: Miroslav Rezanina +--- + pc-bios/s390-ccw/bootmap.c | 6 +++--- + pc-bios/s390-ccw/bootmap.h | 2 -- + pc-bios/s390-ccw/s390-ccw.h | 2 ++ + 3 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c +index 9287b7a..b767fa2 100644 +--- a/pc-bios/s390-ccw/bootmap.c ++++ b/pc-bios/s390-ccw/bootmap.c +@@ -297,7 +297,7 @@ static void run_eckd_boot_script(block_number_t bmt_block_nr, + } + + debug_print_int("loadparm", loadparm); +- IPL_assert(loadparm <= MAX_TABLE_ENTRIES, "loadparm value greater than" ++ IPL_assert(loadparm < MAX_BOOT_ENTRIES, "loadparm value greater than" + " maximum number of boot entries allowed"); + + memset(sec, FREE_SPACE_FILLER, sizeof(sec)); +@@ -585,7 +585,7 @@ static void ipl_scsi(void) + read_block(mbr->pt.blockno, sec, "Error reading Program Table"); + IPL_assert(magic_match(sec, ZIPL_MAGIC), "No zIPL magic in PT"); + +- while (program_table_entries <= MAX_TABLE_ENTRIES) { ++ while (program_table_entries < MAX_BOOT_ENTRIES) { + if (!prog_table->entry[program_table_entries].scsi.blockno) { + break; + } +@@ -600,7 +600,7 @@ static void ipl_scsi(void) + } + + debug_print_int("loadparm", loadparm); +- IPL_assert(loadparm <= MAX_TABLE_ENTRIES, "loadparm value greater than" ++ IPL_assert(loadparm < MAX_BOOT_ENTRIES, "loadparm value greater than" + " maximum number of boot entries allowed"); + + zipl_run(&prog_table->entry[loadparm].scsi); /* no return */ +diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h +index 07eb600..732c111 100644 +--- a/pc-bios/s390-ccw/bootmap.h ++++ b/pc-bios/s390-ccw/bootmap.h +@@ -57,8 +57,6 @@ typedef union BootMapPointer { + ExtEckdBlockPtr xeckd; + } __attribute__ ((packed)) BootMapPointer; + +-#define MAX_TABLE_ENTRIES 30 +- + /* aka Program Table */ + typedef struct BootMapTable { + uint8_t magic[4]; +diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h +index fd18da2..2c9e601 100644 +--- a/pc-bios/s390-ccw/s390-ccw.h ++++ b/pc-bios/s390-ccw/s390-ccw.h +@@ -94,6 +94,8 @@ bool menu_is_enabled_zipl(void); + int menu_get_enum_boot_index(int entries); + bool menu_is_enabled_enum(void); + ++#define MAX_BOOT_ENTRIES 31 ++ + static inline void fill_hex(char *out, unsigned char val) + { + const char hex[] = "0123456789abcdef"; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pc-bios-s390-ccw-size_t-should-be-unsigned.patch b/SOURCES/kvm-pc-bios-s390-ccw-size_t-should-be-unsigned.patch new file mode 100644 index 0000000..d0e6267 --- /dev/null +++ b/SOURCES/kvm-pc-bios-s390-ccw-size_t-should-be-unsigned.patch @@ -0,0 +1,60 @@ +From e25487ca5ac49460e5a0dcb802866f156485f188 Mon Sep 17 00:00:00 2001 +From: Thomas Huth +Date: Mon, 7 May 2018 07:58:04 +0200 +Subject: [PATCH 08/13] pc-bios/s390-ccw: size_t should be unsigned + +RH-Author: Thomas Huth +Message-id: <1525679888-9234-3-git-send-email-thuth@redhat.com> +Patchwork-id: 80050 +O-Subject: [RHEL-7.6 qemu-kvm-ma PATCH 2/6] pc-bios/s390-ccw: size_t should be unsigned +Bugzilla: 1523857 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Cornelia Huck +RH-Acked-by: Laszlo Ersek + +"size_t" should be an unsigned type according to the C standard. +Thus we should also use this convention in the s390-ccw firmware to avoid +confusion. I checked the sources, and apart from one spot in libc.c, the +code should all be fine with this change. + +Buglink: https://bugs.launchpad.net/qemu/+bug/1753437 +Reviewed-by: Christian Borntraeger +Reviewed-by: Halil Pasic +Reviewed-by: Collin Walling +Signed-off-by: Thomas Huth +(cherry picked from commit e4f869621203955761cf274c87d5595e9facd319) +Signed-off-by: Miroslav Rezanina +--- + pc-bios/s390-ccw/libc.c | 2 +- + pc-bios/s390-ccw/libc.h | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/pc-bios/s390-ccw/libc.c b/pc-bios/s390-ccw/libc.c +index 38ea77d..a786566 100644 +--- a/pc-bios/s390-ccw/libc.c ++++ b/pc-bios/s390-ccw/libc.c +@@ -63,7 +63,7 @@ uint64_t atoui(const char *str) + */ + char *uitoa(uint64_t num, char *str, size_t len) + { +- size_t num_idx = 1; /* account for NUL */ ++ long num_idx = 1; /* account for NUL */ + uint64_t tmp = num; + + IPL_assert(str != NULL, "uitoa: no space allocated to store string"); +diff --git a/pc-bios/s390-ccw/libc.h b/pc-bios/s390-ccw/libc.h +index 63ece70..818517f 100644 +--- a/pc-bios/s390-ccw/libc.h ++++ b/pc-bios/s390-ccw/libc.h +@@ -12,7 +12,7 @@ + #ifndef S390_CCW_LIBC_H + #define S390_CCW_LIBC_H + +-typedef long size_t; ++typedef unsigned long size_t; + typedef int bool; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pc-fix-crash-on-attempted-cpu-unplug.patch b/SOURCES/kvm-pc-fix-crash-on-attempted-cpu-unplug.patch deleted file mode 100644 index d523083..0000000 --- a/SOURCES/kvm-pc-fix-crash-on-attempted-cpu-unplug.patch +++ /dev/null @@ -1,58 +0,0 @@ -From f8394b69cee118293a1983ebc99492f113d57704 Mon Sep 17 00:00:00 2001 -From: Igor Mammedov -Date: Wed, 6 Dec 2017 13:47:58 +0100 -Subject: [PATCH 20/21] pc: fix crash on attempted cpu unplug - -RH-Author: Igor Mammedov -Message-id: <1512568078-280557-1-git-send-email-imammedo@redhat.com> -Patchwork-id: 78212 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH] pc: fix crash on attempted cpu unplug -Bugzilla: 1506856 -RH-Acked-by: Laurent Vivier -RH-Acked-by: Marcel Apfelbaum -RH-Acked-by: Miroslav Rezanina - -when qemu is started with '-no-acpi' CLI option, an attempt -to unplug a CPU using device_del results in null pointer -dereference at: - - #0 object_get_class - #1 pc_machine_device_unplug_request_cb - #2 qmp_marshal_device_del - -which is caused by pcms->acpi_dev == NULL due to ACPI support -being disabled. - -Considering that ACPI support is necessary for unplug to work, -check that it's enabled and fail unplug request gracefully -if no acpi device were found. - -Signed-off-by: Igor Mammedov -Reviewed-by: Eduardo Habkost -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 75ba2ddb188fa07c3442446766782036e3085cba) -Signed-off-by: Miroslav Rezanina ---- - hw/i386/pc.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/hw/i386/pc.c b/hw/i386/pc.c -index f37d60a..db57b51 100644 ---- a/hw/i386/pc.c -+++ b/hw/i386/pc.c -@@ -1879,6 +1879,11 @@ static void pc_cpu_unplug_request_cb(HotplugHandler *hotplug_dev, - X86CPU *cpu = X86_CPU(dev); - PCMachineState *pcms = PC_MACHINE(hotplug_dev); - -+ if (!pcms->acpi_dev) { -+ error_setg(&local_err, "CPU hot unplug not supported without ACPI"); -+ goto out; -+ } -+ - pc_find_cpu_slot(MACHINE(pcms), cpu->apic_id, &idx); - assert(idx != -1); - if (idx == 0) { --- -1.8.3.1 - diff --git a/SOURCES/kvm-pc-make-pc_rom-RO-only-on-new-machine-types.patch b/SOURCES/kvm-pc-make-pc_rom-RO-only-on-new-machine-types.patch deleted file mode 100644 index 61b1716..0000000 --- a/SOURCES/kvm-pc-make-pc_rom-RO-only-on-new-machine-types.patch +++ /dev/null @@ -1,104 +0,0 @@ -From c091cd7a1b3799d3d2d657bc3dc66dec90eb86f1 Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Wed, 11 Oct 2017 17:55:00 +0200 -Subject: [PATCH 15/69] pc: make pc_rom RO only on new machine types - -RH-Author: Dr. David Alan Gilbert -Message-id: <20171011175500.12390-3-dgilbert@redhat.com> -Patchwork-id: 77178 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH v3 2/2] pc: make pc_rom RO only on new machine types -Bugzilla: 1489800 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Gerd Hoffmann -RH-Acked-by: Igor Mammedov - -From: "Dr. David Alan Gilbert" - -Upstream lp 1715700 reported that the RO pc_rom settings caused -problems with Windows 7 under OVMF. -This is fixed in a new OVMF, but lets keep things stable on -older machine types. - -Signed-off-by: Dr. David Alan Gilbert -Signed-off-by: Miroslav Rezanina ---- - hw/i386/pc.c | 4 +++- - hw/i386/pc_piix.c | 2 ++ - hw/i386/pc_q35.c | 2 ++ - include/hw/i386/pc.h | 3 +++ - 4 files changed, 10 insertions(+), 1 deletion(-) - -diff --git a/hw/i386/pc.c b/hw/i386/pc.c -index ccaa832..83df57f 100644 ---- a/hw/i386/pc.c -+++ b/hw/i386/pc.c -@@ -1444,7 +1444,8 @@ void pc_memory_init(PCMachineState *pcms, - option_rom_mr = g_malloc(sizeof(*option_rom_mr)); - memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE, - &error_fatal); -- if (pcmc->pci_enabled) { -+ /* RH difference: See bz 1489800, explicitly make ROM ro */ -+ if (pcmc->pc_rom_ro) { - memory_region_set_readonly(option_rom_mr, true); - } - memory_region_add_subregion_overlap(rom_memory, -@@ -2350,6 +2351,7 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) - pcmc->acpi_data_size = 0x20000 + 0x8000; - pcmc->save_tsc_khz = true; - pcmc->linuxboot_dma_enabled = true; -+ pcmc->pc_rom_ro = true; - mc->get_hotplug_handler = pc_get_hotpug_handler; - mc->cpu_index_to_instance_props = pc_cpu_index_to_props; - mc->possible_cpu_arch_ids = pc_possible_cpu_arch_ids; -diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c -index 935391f..09bfc5a 100644 ---- a/hw/i386/pc_piix.c -+++ b/hw/i386/pc_piix.c -@@ -1164,11 +1164,13 @@ static void pc_init_rhel740(MachineState *machine) - - static void pc_machine_rhel740_options(MachineClass *m) - { -+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m); - pc_machine_rhel750_options(m); - m->alias = NULL; - m->is_default = 0; - m->desc = "RHEL 7.4.0 PC (i440FX + PIIX, 1996)"; - m->numa_auto_assign_ram = numa_legacy_auto_assign_ram; -+ pcmc->pc_rom_ro = false; - SET_MACHINE_COMPAT(m, PC_RHEL7_4_COMPAT); - } - -diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c -index e73097b..27c85c5 100644 ---- a/hw/i386/pc_q35.c -+++ b/hw/i386/pc_q35.c -@@ -416,10 +416,12 @@ static void pc_q35_init_rhel740(MachineState *machine) - - static void pc_q35_machine_rhel740_options(MachineClass *m) - { -+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m); - pc_q35_machine_rhel750_options(m); - m->alias = NULL; - m->desc = "RHEL-7.4.0 PC (Q35 + ICH9, 2009)"; - m->numa_auto_assign_ram = numa_legacy_auto_assign_ram; -+ pcmc->pc_rom_ro = false; - SET_MACHINE_COMPAT(m, PC_RHEL7_4_COMPAT); - } - -diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h -index a8d6857..6f65d79 100644 ---- a/include/hw/i386/pc.h -+++ b/include/hw/i386/pc.h -@@ -141,6 +141,9 @@ struct PCMachineClass { - - /* use DMA capable linuxboot option rom */ - bool linuxboot_dma_enabled; -+ -+ /* RH only, see bz 1489800 */ -+ bool pc_rom_ro; - }; - - #define TYPE_PC_MACHINE "generic-pc-machine" --- -1.8.3.1 - diff --git a/SOURCES/kvm-pc-pc-rhel75.5.0-compat-code.patch b/SOURCES/kvm-pc-pc-rhel75.5.0-compat-code.patch new file mode 100644 index 0000000..de19af0 --- /dev/null +++ b/SOURCES/kvm-pc-pc-rhel75.5.0-compat-code.patch @@ -0,0 +1,81 @@ +From e1e6a404ee2c4833a05356378da2ffc7bdb5e6fe Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Fri, 25 May 2018 23:38:16 +0200 +Subject: [PATCH 5/8] pc: pc-*-rhel75.5.0 compat code + +RH-Author: Eduardo Habkost +Message-id: <20180525233816.19506-2-ehabkost@redhat.com> +Patchwork-id: 80481 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/1] pc: pc-*-rhel75.5.0 compat code +Bugzilla: 1578068 +RH-Acked-by: Peter Xu +RH-Acked-by: Igor Mammedov +RH-Acked-by: Laurent Vivier + +Based on the pc-*-2.11 and pc-*-2.10 compat code from upstream. + +Signed-off-by: Eduardo Habkost +Signed-off-by: Miroslav Rezanina +--- + hw/i386/pc_piix.c | 2 ++ + hw/i386/pc_q35.c | 4 ++++ + include/hw/i386/pc.h | 13 +++++++++++++ + 3 files changed, 19 insertions(+) + +diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c +index 6794bb7..7b87ef6 100644 +--- a/hw/i386/pc_piix.c ++++ b/hw/i386/pc_piix.c +@@ -1166,6 +1166,8 @@ static void pc_machine_rhel750_options(MachineClass *m) + { + pc_machine_rhel7_options(m); + m->desc = "RHEL 7.5.0 PC (i440FX + PIIX, 1996)"; ++ m->auto_enable_numa_with_memhp = false; ++ SET_MACHINE_COMPAT(m, PC_RHEL7_5_COMPAT); + } + + DEFINE_PC_MACHINE(rhel750, "pc-i440fx-rhel7.5.0", pc_init_rhel750, +diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c +index ecd6255..1805f55 100644 +--- a/hw/i386/pc_q35.c ++++ b/hw/i386/pc_q35.c +@@ -430,8 +430,12 @@ static void pc_q35_init_rhel750(MachineState *machine) + + static void pc_q35_machine_rhel750_options(MachineClass *m) + { ++ PCMachineClass *pcmc = PC_MACHINE_CLASS(m); + pc_q35_machine_rhel7_options(m); + m->desc = "RHEL-7.5.0 PC (Q35 + ICH9, 2009)"; ++ m->auto_enable_numa_with_memhp = false; ++ pcmc->default_nic_model = "e1000"; ++ SET_MACHINE_COMPAT(m, PC_RHEL7_5_COMPAT); + } + + DEFINE_PC_MACHINE(q35_rhel750, "pc-q35-rhel7.5.0", pc_q35_init_rhel750, +diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h +index faddeba..e94424f 100644 +--- a/include/hw/i386/pc.h ++++ b/include/hw/i386/pc.h +@@ -969,6 +969,19 @@ extern void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id); + .value = "on",\ + }, + ++/* Similar to PC_COMPAT_2_11 + PC_COMPAT_2_10, but: ++ * - x-hv-max-vps was backported to 7.5 ++ * - x-pci-hole64-fix was backported to 7.5 ++ */ ++#define PC_RHEL7_5_COMPAT \ ++ HW_COMPAT_RHEL7_5 \ ++ { /* PC_RHEL7_5_COMPAT from PC_COMPAT_2_11 */ \ ++ .driver = "Skylake-Server" "-" TYPE_X86_CPU,\ ++ .property = "clflushopt",\ ++ .value = "off",\ ++ }, ++ ++ + #define PC_RHEL7_4_COMPAT \ + HW_COMPAT_RHEL7_4 \ + { /* PC_RHEL7_4_COMPAT from PC_COMPAT_2_9 */ \ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pci-Add-INTERFACE_CONVENTIONAL_PCI_DEVICE-to-Convent.patch b/SOURCES/kvm-pci-Add-INTERFACE_CONVENTIONAL_PCI_DEVICE-to-Convent.patch deleted file mode 100644 index 2e048c0..0000000 --- a/SOURCES/kvm-pci-Add-INTERFACE_CONVENTIONAL_PCI_DEVICE-to-Convent.patch +++ /dev/null @@ -1,1208 +0,0 @@ -From 54ed98827de5ad796b429aa2163d039cbf242c39 Mon Sep 17 00:00:00 2001 -From: Eduardo Habkost -Date: Fri, 20 Oct 2017 18:29:15 +0200 -Subject: [PATCH 10/19] pci: Add INTERFACE_CONVENTIONAL_PCI_DEVICE to - Conventional PCI devices - -RH-Author: Eduardo Habkost -Message-id: <20171020182917.10771-6-ehabkost@redhat.com> -Patchwork-id: 77424 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH v2 5/7] pci: Add INTERFACE_CONVENTIONAL_PCI_DEVICE to Conventional PCI devices -Bugzilla: 1390348 -RH-Acked-by: Marcel Apfelbaum -RH-Acked-by: Michael S. Tsirkin -RH-Acked-by: Laurent Vivier - -Add INTERFACE_CONVENTIONAL_PCI_DEVICE to all direct subtypes of -TYPE_PCI_DEVICE, except: - -1) The ones that already have INTERFACE_PCIE_DEVICE set: - -* base-xhci -* e1000e -* nvme -* pvscsi -* vfio-pci -* virtio-pci -* vmxnet3 - -2) base-pci-bridge - -Not all PCI bridges are Conventional PCI devices, so -INTERFACE_CONVENTIONAL_PCI_DEVICE is added only to the subtypes -that are actually Conventional PCI: - -* dec-21154-p2p-bridge -* i82801b11-bridge -* pbm-bridge -* pci-bridge - -The direct subtypes of base-pci-bridge not touched by this patch -are: - -* xilinx-pcie-root: Already marked as PCIe-only. -* pcie-pci-bridge: Already marked as PCIe-only. -* pcie-port: all non-abstract subtypes of pcie-port are already - marked as PCIe-only devices. - -3) megasas-base - -Not all megasas devices are Conventional PCI devices, so the -interface names are added to the subclasses registered by -megasas_register_types(), according to information in the -megasas_devices[] array. - -"megasas-gen2" already implements INTERFACE_PCIE_DEVICE, so add -INTERFACE_CONVENTIONAL_PCI_DEVICE only to "megasas". - -Backport notes: -* Trivial conflicts: - * hw/net/sungem.c - * hw/net/sunhme.c - * hw/pci-host/apb.c - -Acked-by: Alberto Garcia -Acked-by: John Snow -Acked-by: Anthony PERARD -Signed-off-by: Eduardo Habkost -Reviewed-by: David Gibson -Acked-by: David Gibson -Reviewed-by: Marcel Apfelbaum -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit fd3b02c8896d597dd8b9e053dec579cf0386aee1) -Signed-off-by: Eduardo Habkost ---- -Changes v1 -> v2: -* Removed hw/net/sungem.c and hw/net/sunhme.c - (Mistake spotted by David Gibson) - -Signed-off-by: Miroslav Rezanina ---- - hw/acpi/piix4.c | 1 + - hw/audio/ac97.c | 4 ++++ - hw/audio/es1370.c | 4 ++++ - hw/audio/intel-hda.c | 4 ++++ - hw/char/serial-pci.c | 12 ++++++++++++ - hw/display/cirrus_vga.c | 4 ++++ - hw/display/qxl.c | 4 ++++ - hw/display/sm501.c | 4 ++++ - hw/display/vga-pci.c | 4 ++++ - hw/display/vmware_vga.c | 4 ++++ - hw/i2c/smbus_ich9.c | 4 ++++ - hw/i386/amd_iommu.c | 4 ++++ - hw/i386/kvm/pci-assign.c | 4 ++++ - hw/i386/pc_piix.c | 4 ++++ - hw/i386/xen/xen_platform.c | 4 ++++ - hw/i386/xen/xen_pvdevice.c | 4 ++++ - hw/ide/ich.c | 4 ++++ - hw/ide/pci.c | 4 ++++ - hw/ipack/tpci200.c | 4 ++++ - hw/isa/i82378.c | 4 ++++ - hw/isa/lpc_ich9.c | 1 + - hw/isa/piix4.c | 4 ++++ - hw/isa/vt82c686.c | 16 ++++++++++++++++ - hw/mips/gt64xxx_pci.c | 4 ++++ - hw/misc/edu.c | 5 +++++ - hw/misc/ivshmem.c | 4 ++++ - hw/misc/macio/macio.c | 4 ++++ - hw/misc/pci-testdev.c | 4 ++++ - hw/net/e1000.c | 4 ++++ - hw/net/eepro100.c | 4 ++++ - hw/net/ne2000.c | 4 ++++ - hw/net/pcnet-pci.c | 4 ++++ - hw/net/rocker/rocker.c | 4 ++++ - hw/net/rtl8139.c | 4 ++++ - hw/pci-bridge/dec.c | 8 ++++++++ - hw/pci-bridge/i82801b11.c | 4 ++++ - hw/pci-bridge/pci_bridge_dev.c | 1 + - hw/pci-bridge/pci_expander_bridge.c | 8 ++++++++ - hw/pci-host/apb.c | 8 ++++++++ - hw/pci-host/bonito.c | 4 ++++ - hw/pci-host/gpex.c | 4 ++++ - hw/pci-host/grackle.c | 4 ++++ - hw/pci-host/piix.c | 8 ++++++++ - hw/pci-host/ppce500.c | 4 ++++ - hw/pci-host/prep.c | 4 ++++ - hw/pci-host/q35.c | 4 ++++ - hw/pci-host/uninorth.c | 16 ++++++++++++++++ - hw/pci-host/versatile.c | 4 ++++ - hw/ppc/ppc4xx_pci.c | 4 ++++ - hw/scsi/esp-pci.c | 4 ++++ - hw/scsi/lsi53c895a.c | 4 ++++ - hw/scsi/megasas.c | 4 ++++ - hw/scsi/mptsas.c | 4 ++++ - hw/sd/sdhci.c | 4 ++++ - hw/sh4/sh_pci.c | 4 ++++ - hw/sparc64/sun4u.c | 4 ++++ - hw/usb/hcd-ehci-pci.c | 4 ++++ - hw/usb/hcd-ohci.c | 4 ++++ - hw/usb/hcd-uhci.c | 4 ++++ - hw/vfio/pci-quirks.c | 4 ++++ - hw/watchdog/wdt_i6300esb.c | 4 ++++ - hw/xen/xen_pt.c | 4 ++++ - 62 files changed, 288 insertions(+) - -diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c -index efd80d1..34c6e22 100644 ---- a/hw/acpi/piix4.c -+++ b/hw/acpi/piix4.c -@@ -723,6 +723,7 @@ static const TypeInfo piix4_pm_info = { - .interfaces = (InterfaceInfo[]) { - { TYPE_HOTPLUG_HANDLER }, - { TYPE_ACPI_DEVICE_IF }, -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, - { } - } - }; -diff --git a/hw/audio/ac97.c b/hw/audio/ac97.c -index 959c786..337402e 100644 ---- a/hw/audio/ac97.c -+++ b/hw/audio/ac97.c -@@ -1431,6 +1431,10 @@ static const TypeInfo ac97_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof (AC97LinkState), - .class_init = ac97_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void ac97_register_types (void) -diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c -index dd7c23d..59cf252 100644 ---- a/hw/audio/es1370.c -+++ b/hw/audio/es1370.c -@@ -1082,6 +1082,10 @@ static const TypeInfo es1370_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof (ES1370State), - .class_init = es1370_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void es1370_register_types (void) -diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c -index 06acc98..b786491 100644 ---- a/hw/audio/intel-hda.c -+++ b/hw/audio/intel-hda.c -@@ -1299,6 +1299,10 @@ static const TypeInfo intel_hda_info = { - .instance_size = sizeof(IntelHDAState), - .class_init = intel_hda_class_init, - .abstract = true, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static const TypeInfo intel_hda_info_ich6 = { -diff --git a/hw/char/serial-pci.c b/hw/char/serial-pci.c -index 24ce17b..d426982 100644 ---- a/hw/char/serial-pci.c -+++ b/hw/char/serial-pci.c -@@ -254,6 +254,10 @@ static const TypeInfo serial_pci_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCISerialState), - .class_init = serial_pci_class_initfn, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static const TypeInfo multi_2x_serial_pci_info = { -@@ -261,6 +265,10 @@ static const TypeInfo multi_2x_serial_pci_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIMultiSerialState), - .class_init = multi_2x_serial_pci_class_initfn, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static const TypeInfo multi_4x_serial_pci_info = { -@@ -268,6 +276,10 @@ static const TypeInfo multi_4x_serial_pci_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIMultiSerialState), - .class_init = multi_4x_serial_pci_class_initfn, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void serial_pci_register_types(void) -diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c -index e53c6f2..633d555 100644 ---- a/hw/display/cirrus_vga.c -+++ b/hw/display/cirrus_vga.c -@@ -3162,6 +3162,10 @@ static const TypeInfo cirrus_vga_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCICirrusVGAState), - .class_init = cirrus_vga_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void cirrus_vga_register_types(void) -diff --git a/hw/display/qxl.c b/hw/display/qxl.c -index ae3677f..b20e259 100644 ---- a/hw/display/qxl.c -+++ b/hw/display/qxl.c -@@ -2430,6 +2430,10 @@ static const TypeInfo qxl_pci_type_info = { - .instance_size = sizeof(PCIQXLDevice), - .abstract = true, - .class_init = qxl_pci_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void qxl_primary_class_init(ObjectClass *klass, void *data) -diff --git a/hw/display/sm501.c b/hw/display/sm501.c -index 6f3dfe0..7f18224 100644 ---- a/hw/display/sm501.c -+++ b/hw/display/sm501.c -@@ -1843,6 +1843,10 @@ static const TypeInfo sm501_pci_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(SM501PCIState), - .class_init = sm501_pci_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void sm501_register_types(void) -diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c -index ac9a764..7adb89f 100644 ---- a/hw/display/vga-pci.c -+++ b/hw/display/vga-pci.c -@@ -338,6 +338,10 @@ static const TypeInfo vga_pci_type_info = { - .instance_size = sizeof(PCIVGAState), - .abstract = true, - .class_init = vga_pci_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void vga_class_init(ObjectClass *klass, void *data) -diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c -index 4a64b41..cdc3fed 100644 ---- a/hw/display/vmware_vga.c -+++ b/hw/display/vmware_vga.c -@@ -1350,6 +1350,10 @@ static const TypeInfo vmsvga_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(struct pci_vmsvga_state_s), - .class_init = vmsvga_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void vmsvga_register_types(void) -diff --git a/hw/i2c/smbus_ich9.c b/hw/i2c/smbus_ich9.c -index ea51e09..e47556c 100644 ---- a/hw/i2c/smbus_ich9.c -+++ b/hw/i2c/smbus_ich9.c -@@ -119,6 +119,10 @@ static const TypeInfo ich9_smb_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(ICH9SMBState), - .class_init = ich9_smb_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void ich9_smb_register(void) -diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c -index 334938a..ad8155c 100644 ---- a/hw/i386/amd_iommu.c -+++ b/hw/i386/amd_iommu.c -@@ -1227,6 +1227,10 @@ static const TypeInfo amdviPCI = { - .name = "AMDVI-PCI", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(AMDVIPCIState), -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void amdvi_iommu_memory_region_class_init(ObjectClass *klass, void *data) -diff --git a/hw/i386/kvm/pci-assign.c b/hw/i386/kvm/pci-assign.c -index 33e20cb..d8559d8 100644 ---- a/hw/i386/kvm/pci-assign.c -+++ b/hw/i386/kvm/pci-assign.c -@@ -1864,6 +1864,10 @@ static const TypeInfo assign_info = { - .instance_size = sizeof(AssignedDevice), - .class_init = assign_class_init, - .instance_init = assigned_dev_instance_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void assign_register_types(void) -diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c -index 09bfc5a..c10e462 100644 ---- a/hw/i386/pc_piix.c -+++ b/hw/i386/pc_piix.c -@@ -1051,6 +1051,10 @@ static TypeInfo isa_bridge_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIDevice), - .class_init = isa_bridge_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void pt_graphics_register_types(void) -diff --git a/hw/i386/xen/xen_platform.c b/hw/i386/xen/xen_platform.c -index 9ba7474..056b87d 100644 ---- a/hw/i386/xen/xen_platform.c -+++ b/hw/i386/xen/xen_platform.c -@@ -517,6 +517,10 @@ static const TypeInfo xen_platform_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIXenPlatformState), - .class_init = xen_platform_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void xen_platform_register_types(void) -diff --git a/hw/i386/xen/xen_pvdevice.c b/hw/i386/xen/xen_pvdevice.c -index c093b34..f748823 100644 ---- a/hw/i386/xen/xen_pvdevice.c -+++ b/hw/i386/xen/xen_pvdevice.c -@@ -127,6 +127,10 @@ static const TypeInfo xen_pv_type_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(XenPVDevice), - .class_init = xen_pv_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void xen_pv_register_types(void) -diff --git a/hw/ide/ich.c b/hw/ide/ich.c -index 9472a60..8dd0ced 100644 ---- a/hw/ide/ich.c -+++ b/hw/ide/ich.c -@@ -184,6 +184,10 @@ static const TypeInfo ich_ahci_info = { - .instance_size = sizeof(AHCIPCIState), - .instance_init = pci_ich9_ahci_init, - .class_init = ich_ahci_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void ich_ahci_register_types(void) -diff --git a/hw/ide/pci.c b/hw/ide/pci.c -index 3cfb510..428980b 100644 ---- a/hw/ide/pci.c -+++ b/hw/ide/pci.c -@@ -458,6 +458,10 @@ static const TypeInfo pci_ide_type_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIIDEState), - .abstract = true, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void pci_ide_register_types(void) -diff --git a/hw/ipack/tpci200.c b/hw/ipack/tpci200.c -index 4dfa6b3..da05c85 100644 ---- a/hw/ipack/tpci200.c -+++ b/hw/ipack/tpci200.c -@@ -646,6 +646,10 @@ static const TypeInfo tpci200_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(TPCI200State), - .class_init = tpci200_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void tpci200_register_types(void) -diff --git a/hw/isa/i82378.c b/hw/isa/i82378.c -index 4d29a99..d20ea4c 100644 ---- a/hw/isa/i82378.c -+++ b/hw/isa/i82378.c -@@ -138,6 +138,10 @@ static const TypeInfo i82378_type_info = { - .instance_size = sizeof(I82378State), - .instance_init = i82378_init, - .class_init = i82378_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void i82378_register_types(void) -diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c -index ac8416d..39f56ba 100644 ---- a/hw/isa/lpc_ich9.c -+++ b/hw/isa/lpc_ich9.c -@@ -823,6 +823,7 @@ static const TypeInfo ich9_lpc_info = { - .interfaces = (InterfaceInfo[]) { - { TYPE_HOTPLUG_HANDLER }, - { TYPE_ACPI_DEVICE_IF }, -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, - { } - } - }; -diff --git a/hw/isa/piix4.c b/hw/isa/piix4.c -index f811eba..6b8bc3f 100644 ---- a/hw/isa/piix4.c -+++ b/hw/isa/piix4.c -@@ -132,6 +132,10 @@ static const TypeInfo piix4_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PIIX4State), - .class_init = piix4_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void piix4_register_types(void) -diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c -index 50dc83d..c129985 100644 ---- a/hw/isa/vt82c686.c -+++ b/hw/isa/vt82c686.c -@@ -301,6 +301,10 @@ static const TypeInfo via_ac97_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(VT686AC97State), - .class_init = via_ac97_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void vt82c686b_mc97_realize(PCIDevice *dev, Error **errp) -@@ -341,6 +345,10 @@ static const TypeInfo via_mc97_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(VT686MC97State), - .class_init = via_mc97_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - /* vt82c686 pm init */ -@@ -419,6 +427,10 @@ static const TypeInfo via_pm_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(VT686PMState), - .class_init = via_pm_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static const VMStateDescription vmstate_via = { -@@ -502,6 +514,10 @@ static const TypeInfo via_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(VT82C686BState), - .class_init = via_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void vt82c686b_register_types(void) -diff --git a/hw/mips/gt64xxx_pci.c b/hw/mips/gt64xxx_pci.c -index e8b2eef..5a9dad9 100644 ---- a/hw/mips/gt64xxx_pci.c -+++ b/hw/mips/gt64xxx_pci.c -@@ -1232,6 +1232,10 @@ static const TypeInfo gt64120_pci_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIDevice), - .class_init = gt64120_pci_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void gt64120_class_init(ObjectClass *klass, void *data) -diff --git a/hw/misc/edu.c b/hw/misc/edu.c -index 01acacf..34eb05d 100644 ---- a/hw/misc/edu.c -+++ b/hw/misc/edu.c -@@ -408,12 +408,17 @@ static void edu_class_init(ObjectClass *class, void *data) - - static void pci_edu_register_types(void) - { -+ static InterfaceInfo interfaces[] = { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }; - static const TypeInfo edu_info = { - .name = "edu", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(EduState), - .instance_init = edu_instance_init, - .class_init = edu_class_init, -+ .interfaces = interfaces, - }; - - type_register_static(&edu_info); -diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c -index 33ef10b..a0a1480 100644 ---- a/hw/misc/ivshmem.c -+++ b/hw/misc/ivshmem.c -@@ -1017,6 +1017,10 @@ static const TypeInfo ivshmem_common_info = { - .instance_size = sizeof(IVShmemState), - .abstract = true, - .class_init = ivshmem_common_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static const VMStateDescription ivshmem_plain_vmsd = { -diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c -index 5d57f45..298e650 100644 ---- a/hw/misc/macio/macio.c -+++ b/hw/misc/macio/macio.c -@@ -415,6 +415,10 @@ static const TypeInfo macio_type_info = { - .instance_init = macio_instance_init, - .abstract = true, - .class_init = macio_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void macio_register_types(void) -diff --git a/hw/misc/pci-testdev.c b/hw/misc/pci-testdev.c -index 7d59902..32041f5 100644 ---- a/hw/misc/pci-testdev.c -+++ b/hw/misc/pci-testdev.c -@@ -326,6 +326,10 @@ static const TypeInfo pci_testdev_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCITestDevState), - .class_init = pci_testdev_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void pci_testdev_register_types(void) -diff --git a/hw/net/e1000.c b/hw/net/e1000.c -index d29e9ee..793d54a 100644 ---- a/hw/net/e1000.c -+++ b/hw/net/e1000.c -@@ -1695,6 +1695,10 @@ static const TypeInfo e1000_base_info = { - .instance_init = e1000_instance_init, - .class_size = sizeof(E1000BaseClass), - .abstract = true, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static const E1000Info e1000_devices[] = { -diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c -index 5a4774a..522deb7 100644 ---- a/hw/net/eepro100.c -+++ b/hw/net/eepro100.c -@@ -2117,6 +2117,10 @@ static void eepro100_register_types(void) - type_info.class_init = eepro100_class_init; - type_info.instance_size = sizeof(EEPRO100State); - type_info.instance_init = eepro100_instance_init; -+ type_info.interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }; - - type_register(&type_info); - } -diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c -index 8660955..2284308 100644 ---- a/hw/net/ne2000.c -+++ b/hw/net/ne2000.c -@@ -786,6 +786,10 @@ static const TypeInfo ne2000_info = { - .instance_size = sizeof(PCINE2000State), - .class_init = ne2000_class_init, - .instance_init = ne2000_instance_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void ne2000_register_types(void) -diff --git a/hw/net/pcnet-pci.c b/hw/net/pcnet-pci.c -index eeab4ca..0e4d4f7 100644 ---- a/hw/net/pcnet-pci.c -+++ b/hw/net/pcnet-pci.c -@@ -365,6 +365,10 @@ static const TypeInfo pcnet_info = { - .instance_size = sizeof(PCIPCNetState), - .class_init = pcnet_class_init, - .instance_init = pcnet_instance_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void pci_pcnet_register_types(void) -diff --git a/hw/net/rocker/rocker.c b/hw/net/rocker/rocker.c -index 4f0f6d7..26d78eb 100644 ---- a/hw/net/rocker/rocker.c -+++ b/hw/net/rocker/rocker.c -@@ -1573,6 +1573,10 @@ static const TypeInfo rocker_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(Rocker), - .class_init = rocker_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void rocker_register_types(void) -diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c -index 80c62dc..52eafc3 100644 ---- a/hw/net/rtl8139.c -+++ b/hw/net/rtl8139.c -@@ -3491,6 +3491,10 @@ static const TypeInfo rtl8139_info = { - .instance_size = sizeof(RTL8139State), - .class_init = rtl8139_class_init, - .instance_init = rtl8139_instance_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void rtl8139_register_types(void) -diff --git a/hw/pci-bridge/dec.c b/hw/pci-bridge/dec.c -index eb275e1..84492d5 100644 ---- a/hw/pci-bridge/dec.c -+++ b/hw/pci-bridge/dec.c -@@ -79,6 +79,10 @@ static const TypeInfo dec_21154_pci_bridge_info = { - .parent = TYPE_PCI_BRIDGE, - .instance_size = sizeof(PCIBridge), - .class_init = dec_21154_pci_bridge_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn) -@@ -138,6 +142,10 @@ static const TypeInfo dec_21154_pci_host_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIDevice), - .class_init = dec_21154_pci_host_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void pci_dec_21154_device_class_init(ObjectClass *klass, void *data) -diff --git a/hw/pci-bridge/i82801b11.c b/hw/pci-bridge/i82801b11.c -index 2c1b747..cb522bf 100644 ---- a/hw/pci-bridge/i82801b11.c -+++ b/hw/pci-bridge/i82801b11.c -@@ -106,6 +106,10 @@ static const TypeInfo i82801b11_bridge_info = { - .parent = TYPE_PCI_BRIDGE, - .instance_size = sizeof(I82801b11Bridge), - .class_init = i82801b11_bridge_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void d2pbr_register(void) -diff --git a/hw/pci-bridge/pci_bridge_dev.c b/hw/pci-bridge/pci_bridge_dev.c -index 4373f1d..d56f663 100644 ---- a/hw/pci-bridge/pci_bridge_dev.c -+++ b/hw/pci-bridge/pci_bridge_dev.c -@@ -238,6 +238,7 @@ static const TypeInfo pci_bridge_dev_info = { - .instance_finalize = pci_bridge_dev_instance_finalize, - .interfaces = (InterfaceInfo[]) { - { TYPE_HOTPLUG_HANDLER }, -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, - { } - } - }; -diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c -index ff59abf..8c8ac73 100644 ---- a/hw/pci-bridge/pci_expander_bridge.c -+++ b/hw/pci-bridge/pci_expander_bridge.c -@@ -316,6 +316,10 @@ static const TypeInfo pxb_dev_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PXBDev), - .class_init = pxb_dev_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void pxb_pcie_dev_realize(PCIDevice *dev, Error **errp) -@@ -350,6 +354,10 @@ static const TypeInfo pxb_pcie_dev_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PXBDev), - .class_init = pxb_pcie_dev_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void pxb_register_types(void) -diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c -index 96e5d0b..6cf7279 100644 ---- a/hw/pci-host/apb.c -+++ b/hw/pci-host/apb.c -@@ -817,6 +817,10 @@ static const TypeInfo pbm_pci_host_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIDevice), - .class_init = pbm_pci_host_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void pbm_host_class_init(ObjectClass *klass, void *data) -@@ -857,6 +861,10 @@ static const TypeInfo pbm_pci_bridge_info = { - .name = "pbm-bridge", - .parent = TYPE_PCI_BRIDGE, - .class_init = pbm_pci_bridge_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void pbm_iommu_memory_region_class_init(ObjectClass *klass, void *data) -diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c -index 89133a9..9f61e27 100644 ---- a/hw/pci-host/bonito.c -+++ b/hw/pci-host/bonito.c -@@ -833,6 +833,10 @@ static const TypeInfo bonito_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIBonitoState), - .class_init = bonito_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void bonito_pcihost_class_init(ObjectClass *klass, void *data) -diff --git a/hw/pci-host/gpex.c b/hw/pci-host/gpex.c -index 83084b9..59f3132 100644 ---- a/hw/pci-host/gpex.c -+++ b/hw/pci-host/gpex.c -@@ -144,6 +144,10 @@ static const TypeInfo gpex_root_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(GPEXRootState), - .class_init = gpex_root_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void gpex_register(void) -diff --git a/hw/pci-host/grackle.c b/hw/pci-host/grackle.c -index 2e281f6..38cd279 100644 ---- a/hw/pci-host/grackle.c -+++ b/hw/pci-host/grackle.c -@@ -142,6 +142,10 @@ static const TypeInfo grackle_pci_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIDevice), - .class_init = grackle_pci_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void pci_grackle_class_init(ObjectClass *klass, void *data) -diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c -index 90c50b0..68c3922 100644 ---- a/hw/pci-host/piix.c -+++ b/hw/pci-host/piix.c -@@ -694,6 +694,10 @@ static const TypeInfo piix3_pci_type_info = { - .instance_size = sizeof(PIIX3State), - .abstract = true, - .class_init = pci_piix3_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void piix3_class_init(ObjectClass *klass, void *data) -@@ -748,6 +752,10 @@ static const TypeInfo i440fx_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCII440FXState), - .class_init = i440fx_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - #if 0 /* Disabled in Red Hat Enterprise Linux */ -diff --git a/hw/pci-host/ppce500.c b/hw/pci-host/ppce500.c -index becc0ee..39cd244 100644 ---- a/hw/pci-host/ppce500.c -+++ b/hw/pci-host/ppce500.c -@@ -516,6 +516,10 @@ static const TypeInfo e500_host_bridge_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PPCE500PCIBridgeState), - .class_init = e500_host_bridge_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static Property pcihost_properties[] = { -diff --git a/hw/pci-host/prep.c b/hw/pci-host/prep.c -index 8b293ba..92eed0f 100644 ---- a/hw/pci-host/prep.c -+++ b/hw/pci-host/prep.c -@@ -372,6 +372,10 @@ static const TypeInfo raven_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(RavenPCIState), - .class_init = raven_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static Property raven_pcihost_properties[] = { -diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c -index 0e472f2..9cd07ce 100644 ---- a/hw/pci-host/q35.c -+++ b/hw/pci-host/q35.c -@@ -591,6 +591,10 @@ static const TypeInfo mch_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(MCHPCIState), - .class_init = mch_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void q35_register(void) -diff --git a/hw/pci-host/uninorth.c b/hw/pci-host/uninorth.c -index 6cf5e59..ea5c265 100644 ---- a/hw/pci-host/uninorth.c -+++ b/hw/pci-host/uninorth.c -@@ -374,6 +374,10 @@ static const TypeInfo unin_main_pci_host_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIDevice), - .class_init = unin_main_pci_host_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void u3_agp_pci_host_class_init(ObjectClass *klass, void *data) -@@ -398,6 +402,10 @@ static const TypeInfo u3_agp_pci_host_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIDevice), - .class_init = u3_agp_pci_host_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void unin_agp_pci_host_class_init(ObjectClass *klass, void *data) -@@ -422,6 +430,10 @@ static const TypeInfo unin_agp_pci_host_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIDevice), - .class_init = unin_agp_pci_host_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void unin_internal_pci_host_class_init(ObjectClass *klass, void *data) -@@ -446,6 +458,10 @@ static const TypeInfo unin_internal_pci_host_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIDevice), - .class_init = unin_internal_pci_host_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void pci_unin_main_class_init(ObjectClass *klass, void *data) -diff --git a/hw/pci-host/versatile.c b/hw/pci-host/versatile.c -index aa1fdf7..6394a52 100644 ---- a/hw/pci-host/versatile.c -+++ b/hw/pci-host/versatile.c -@@ -487,6 +487,10 @@ static const TypeInfo versatile_pci_host_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIDevice), - .class_init = versatile_pci_host_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static Property pci_vpb_properties[] = { -diff --git a/hw/ppc/ppc4xx_pci.c b/hw/ppc/ppc4xx_pci.c -index 6953f8b..4765dce 100644 ---- a/hw/ppc/ppc4xx_pci.c -+++ b/hw/ppc/ppc4xx_pci.c -@@ -359,6 +359,10 @@ static const TypeInfo ppc4xx_host_bridge_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIDevice), - .class_init = ppc4xx_host_bridge_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void ppc4xx_pcihost_class_init(ObjectClass *klass, void *data) -diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c -index e295d88..419fc66 100644 ---- a/hw/scsi/esp-pci.c -+++ b/hw/scsi/esp-pci.c -@@ -398,6 +398,10 @@ static const TypeInfo esp_pci_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIESPState), - .class_init = esp_pci_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - typedef struct { -diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c -index 3e56ab2..423a284 100644 ---- a/hw/scsi/lsi53c895a.c -+++ b/hw/scsi/lsi53c895a.c -@@ -2244,6 +2244,10 @@ static const TypeInfo lsi_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(LSIState), - .class_init = lsi_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void lsi53c810_class_init(ObjectClass *klass, void *data) -diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c -index 3641c30..4ae10e3 100644 ---- a/hw/scsi/megasas.c -+++ b/hw/scsi/megasas.c -@@ -2468,6 +2468,10 @@ static struct MegasasInfo megasas_devices[] = { - .is_express = false, - .vmsd = &vmstate_megasas_gen1, - .props = megasas_properties_gen1, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - },{ - .name = TYPE_MEGASAS_GEN2, - .desc = "LSI MegaRAID SAS 2108", -diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c -index 765ab53..f807dc6 100644 ---- a/hw/scsi/mptsas.c -+++ b/hw/scsi/mptsas.c -@@ -1441,6 +1441,10 @@ static const TypeInfo mptsas_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(MPTSASState), - .class_init = mptsas1068_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void mptsas_register_types(void) -diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c -index 6d6a791..b064a08 100644 ---- a/hw/sd/sdhci.c -+++ b/hw/sd/sdhci.c -@@ -1315,6 +1315,10 @@ static const TypeInfo sdhci_pci_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(SDHCIState), - .class_init = sdhci_pci_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static Property sdhci_sysbus_properties[] = { -diff --git a/hw/sh4/sh_pci.c b/hw/sh4/sh_pci.c -index 38395c0..cbb01af 100644 ---- a/hw/sh4/sh_pci.c -+++ b/hw/sh4/sh_pci.c -@@ -179,6 +179,10 @@ static const TypeInfo sh_pci_host_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIDevice), - .class_init = sh_pci_host_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void sh_pci_device_class_init(ObjectClass *klass, void *data) -diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c -index bbdb40c..13bc121 100644 ---- a/hw/sparc64/sun4u.c -+++ b/hw/sparc64/sun4u.c -@@ -277,6 +277,10 @@ static const TypeInfo ebus_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(EbusState), - .class_init = ebus_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - #define TYPE_OPENPROM "openprom" -diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c -index 6dedcb8..8c0fc53 100644 ---- a/hw/usb/hcd-ehci-pci.c -+++ b/hw/usb/hcd-ehci-pci.c -@@ -170,6 +170,10 @@ static const TypeInfo ehci_pci_type_info = { - .instance_finalize = usb_ehci_pci_finalize, - .abstract = true, - .class_init = ehci_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void ehci_data_class_init(ObjectClass *klass, void *data) -diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c -index 267982e..a31df67 100644 ---- a/hw/usb/hcd-ohci.c -+++ b/hw/usb/hcd-ohci.c -@@ -2139,6 +2139,10 @@ static const TypeInfo ohci_pci_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(OHCIPCIState), - .class_init = ohci_pci_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static Property ohci_sysbus_properties[] = { -diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c -index 465ed42..86d6ab8 100644 ---- a/hw/usb/hcd-uhci.c -+++ b/hw/usb/hcd-uhci.c -@@ -1336,6 +1336,10 @@ static const TypeInfo uhci_pci_type_info = { - .class_size = sizeof(UHCIPCIDeviceClass), - .abstract = true, - .class_init = uhci_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void uhci_data_class_init(ObjectClass *klass, void *data) -diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c -index 58046e6..4199771 100644 ---- a/hw/vfio/pci-quirks.c -+++ b/hw/vfio/pci-quirks.c -@@ -1199,6 +1199,10 @@ static TypeInfo vfio_pci_igd_lpc_bridge_info = { - .name = "vfio-pci-igd-lpc-bridge", - .parent = TYPE_PCI_DEVICE, - .class_init = vfio_pci_igd_lpc_bridge_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void vfio_pci_igd_register_types(void) -diff --git a/hw/watchdog/wdt_i6300esb.c b/hw/watchdog/wdt_i6300esb.c -index 49b3cd1..e596b08 100644 ---- a/hw/watchdog/wdt_i6300esb.c -+++ b/hw/watchdog/wdt_i6300esb.c -@@ -463,6 +463,10 @@ static const TypeInfo i6300esb_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(I6300State), - .class_init = i6300esb_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void i6300esb_register_types(void) -diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c -index 375efa6..01df341 100644 ---- a/hw/xen/xen_pt.c -+++ b/hw/xen/xen_pt.c -@@ -964,6 +964,10 @@ static const TypeInfo xen_pci_passthrough_info = { - .instance_size = sizeof(XenPCIPassthroughState), - .instance_finalize = xen_pci_passthrough_finalize, - .class_init = xen_pci_passthrough_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { }, -+ }, - }; - - static void xen_pci_passthrough_register_types(void) --- -1.8.3.1 - diff --git a/SOURCES/kvm-pci-Add-INTERFACE_PCIE_DEVICE-to-all-PCIe-devices.patch b/SOURCES/kvm-pci-Add-INTERFACE_PCIE_DEVICE-to-all-PCIe-devices.patch deleted file mode 100644 index 7af8f59..0000000 --- a/SOURCES/kvm-pci-Add-INTERFACE_PCIE_DEVICE-to-all-PCIe-devices.patch +++ /dev/null @@ -1,174 +0,0 @@ -From 4dc6726309313a4c2e508d2ac9ec3bd7ea29cde2 Mon Sep 17 00:00:00 2001 -From: Eduardo Habkost -Date: Fri, 20 Oct 2017 18:29:14 +0200 -Subject: [PATCH 09/19] pci: Add INTERFACE_PCIE_DEVICE to all PCIe devices - -RH-Author: Eduardo Habkost -Message-id: <20171020182917.10771-5-ehabkost@redhat.com> -Patchwork-id: 77423 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH v2 4/7] pci: Add INTERFACE_PCIE_DEVICE to all PCIe devices -Bugzilla: 1390348 -RH-Acked-by: Marcel Apfelbaum -RH-Acked-by: Michael S. Tsirkin -RH-Acked-by: Laurent Vivier - -Change all devices that set is_express=1 to implement -INTERFACE_PCIE_DEVICE. - -Backport notes: -* Not included: hw/pci-bridge/pcie_pci_bridge.c - -Cc: Keith Busch -Cc: Kevin Wolf -Cc: Max Reitz -Cc: Dmitry Fleytman -Cc: Jason Wang -Cc: "Michael S. Tsirkin" -Cc: Marcel Apfelbaum -Cc: Paul Burton -Cc: Paolo Bonzini -Cc: Hannes Reinecke -Cc: qemu-block@nongnu.org -Reviewed-by: Alistair Francis -Signed-off-by: Eduardo Habkost -Reviewed-by: David Gibson -Reviewed-by: Marcel Apfelbaum -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 71d787677d0cacea846dc851c3e56ad076d59c04) -Signed-off-by: Eduardo Habkost -Signed-off-by: Miroslav Rezanina ---- - hw/block/nvme.c | 4 ++++ - hw/net/e1000e.c | 4 ++++ - hw/pci-bridge/pcie_root_port.c | 4 ++++ - hw/pci-bridge/xio3130_downstream.c | 4 ++++ - hw/pci-bridge/xio3130_upstream.c | 4 ++++ - hw/pci-host/xilinx-pcie.c | 4 ++++ - hw/scsi/megasas.c | 6 ++++++ - 7 files changed, 30 insertions(+) - -diff --git a/hw/block/nvme.c b/hw/block/nvme.c -index 6071dc1..26d58b6 100644 ---- a/hw/block/nvme.c -+++ b/hw/block/nvme.c -@@ -1110,6 +1110,10 @@ static const TypeInfo nvme_info = { - .instance_size = sizeof(NvmeCtrl), - .class_init = nvme_class_init, - .instance_init = nvme_instance_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_PCIE_DEVICE }, -+ { } -+ }, - }; - - static void nvme_register_types(void) -diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c -index d6ca464..ac9b1e3 100644 ---- a/hw/net/e1000e.c -+++ b/hw/net/e1000e.c -@@ -729,6 +729,10 @@ static const TypeInfo e1000e_info = { - .instance_size = sizeof(E1000EState), - .class_init = e1000e_class_init, - .instance_init = e1000e_instance_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_PCIE_DEVICE }, -+ { } -+ }, - }; - - static void e1000e_register_types(void) -diff --git a/hw/pci-bridge/pcie_root_port.c b/hw/pci-bridge/pcie_root_port.c -index 4d588cb..9b6e4ce 100644 ---- a/hw/pci-bridge/pcie_root_port.c -+++ b/hw/pci-bridge/pcie_root_port.c -@@ -161,6 +161,10 @@ static const TypeInfo rp_info = { - .class_init = rp_class_init, - .abstract = true, - .class_size = sizeof(PCIERootPortClass), -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_PCIE_DEVICE }, -+ { } -+ }, - }; - - static void rp_register_types(void) -diff --git a/hw/pci-bridge/xio3130_downstream.c b/hw/pci-bridge/xio3130_downstream.c -index 5a882b0..1e09d2a 100644 ---- a/hw/pci-bridge/xio3130_downstream.c -+++ b/hw/pci-bridge/xio3130_downstream.c -@@ -196,6 +196,10 @@ static const TypeInfo xio3130_downstream_info = { - .name = "xio3130-downstream", - .parent = TYPE_PCIE_SLOT, - .class_init = xio3130_downstream_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_PCIE_DEVICE }, -+ { } -+ }, - }; - - static void xio3130_downstream_register_types(void) -diff --git a/hw/pci-bridge/xio3130_upstream.c b/hw/pci-bridge/xio3130_upstream.c -index a052224..227997c 100644 ---- a/hw/pci-bridge/xio3130_upstream.c -+++ b/hw/pci-bridge/xio3130_upstream.c -@@ -166,6 +166,10 @@ static const TypeInfo xio3130_upstream_info = { - .name = "x3130-upstream", - .parent = TYPE_PCIE_PORT, - .class_init = xio3130_upstream_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_PCIE_DEVICE }, -+ { } -+ }, - }; - - static void xio3130_upstream_register_types(void) -diff --git a/hw/pci-host/xilinx-pcie.c b/hw/pci-host/xilinx-pcie.c -index 4613dda..7659253 100644 ---- a/hw/pci-host/xilinx-pcie.c -+++ b/hw/pci-host/xilinx-pcie.c -@@ -317,6 +317,10 @@ static const TypeInfo xilinx_pcie_root_info = { - .parent = TYPE_PCI_BRIDGE, - .instance_size = sizeof(XilinxPCIERoot), - .class_init = xilinx_pcie_root_class_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_PCIE_DEVICE }, -+ { } -+ }, - }; - - static void xilinx_pcie_register(void) -diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c -index 734fdae..3641c30 100644 ---- a/hw/scsi/megasas.c -+++ b/hw/scsi/megasas.c -@@ -2451,6 +2451,7 @@ typedef struct MegasasInfo { - int osts; - const VMStateDescription *vmsd; - Property *props; -+ InterfaceInfo *interfaces; - } MegasasInfo; - - static struct MegasasInfo megasas_devices[] = { -@@ -2480,6 +2481,10 @@ static struct MegasasInfo megasas_devices[] = { - .is_express = true, - .vmsd = &vmstate_megasas_gen2, - .props = megasas_properties_gen2, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_PCIE_DEVICE }, -+ { } -+ }, - } - }; - -@@ -2531,6 +2536,7 @@ static void megasas_register_types(void) - type_info.parent = TYPE_MEGASAS_BASE; - type_info.class_data = (void *)info; - type_info.class_init = megasas_class_init; -+ type_info.interfaces = info->interfaces; - - type_register(&type_info); - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-pci-Add-interface-names-to-hybrid-PCI-devices.patch b/SOURCES/kvm-pci-Add-interface-names-to-hybrid-PCI-devices.patch deleted file mode 100644 index 326fb96..0000000 --- a/SOURCES/kvm-pci-Add-interface-names-to-hybrid-PCI-devices.patch +++ /dev/null @@ -1,132 +0,0 @@ -From 0e3c4dff97fed5335c1af115e06d329e2f705022 Mon Sep 17 00:00:00 2001 -From: Eduardo Habkost -Date: Fri, 20 Oct 2017 18:29:13 +0200 -Subject: [PATCH 08/19] pci: Add interface names to hybrid PCI devices - -RH-Author: Eduardo Habkost -Message-id: <20171020182917.10771-4-ehabkost@redhat.com> -Patchwork-id: 77425 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH v2 3/7] pci: Add interface names to hybrid PCI devices -Bugzilla: 1390348 -RH-Acked-by: Marcel Apfelbaum -RH-Acked-by: Michael S. Tsirkin -RH-Acked-by: Laurent Vivier - -The following devices support both PCI Express and Conventional -PCI, by including special code to handle the QEMU_PCI_CAP_EXPRESS -flag and/or conditional pcie_endpoint_cap_init() calls: - -* vfio-pci (is_express=1, but legacy PCI handled by - vfio_populate_device()) -* vmxnet3 (is_express=0, but PCIe handled by vmxnet3_realize()) -* pvscsi (is_express=0, but PCIe handled by pvscsi_realize()) -* virtio-pci (is_express=0, but PCIe handled by - virtio_pci_dc_realize(), and additional legacy PCI code at - virtio_pci_realize()) -* base-xhci (is_express=1, but pcie_endpoint_cap_init() call - is conditional on pci_bus_is_express(dev->bus) - * Note that xhci does not clear QEMU_PCI_CAP_EXPRESS like the - other hybrid devices - -Cc: Dmitry Fleytman -Cc: Jason Wang -Cc: Paolo Bonzini -Cc: Gerd Hoffmann -Cc: Alex Williamson -Cc: "Michael S. Tsirkin" -Signed-off-by: Eduardo Habkost -Reviewed-by: David Gibson -Reviewed-by: Marcel Apfelbaum -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit a5fa336f11a1eddad9f2be6506e59ba50ed81818) -Signed-off-by: Eduardo Habkost -Signed-off-by: Miroslav Rezanina ---- - hw/net/vmxnet3.c | 5 +++++ - hw/scsi/vmw_pvscsi.c | 2 ++ - hw/usb/hcd-xhci.c | 5 +++++ - hw/vfio/pci.c | 5 +++++ - hw/virtio/virtio-pci.c | 5 +++++ - 5 files changed, 22 insertions(+) - -diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c -index a19a7a3..f99d9a6 100644 ---- a/hw/net/vmxnet3.c -+++ b/hw/net/vmxnet3.c -@@ -2651,6 +2651,11 @@ static const TypeInfo vmxnet3_info = { - .instance_size = sizeof(VMXNET3State), - .class_init = vmxnet3_class_init, - .instance_init = vmxnet3_instance_init, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_PCIE_DEVICE }, -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { } -+ }, - }; - - static void vmxnet3_register_types(void) -diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c -index 77d8b6f..d185393 100644 ---- a/hw/scsi/vmw_pvscsi.c -+++ b/hw/scsi/vmw_pvscsi.c -@@ -1300,6 +1300,8 @@ static const TypeInfo pvscsi_info = { - .class_init = pvscsi_class_init, - .interfaces = (InterfaceInfo[]) { - { TYPE_HOTPLUG_HANDLER }, -+ { INTERFACE_PCIE_DEVICE }, -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, - { } - } - }; -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index 53de805..d92e633 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -3688,6 +3688,11 @@ static const TypeInfo xhci_info = { - .instance_size = sizeof(XHCIState), - .class_init = xhci_class_init, - .abstract = true, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_PCIE_DEVICE }, -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { } -+ }, - }; - - static void qemu_xhci_class_init(ObjectClass *klass, void *data) -diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c -index f3f1ce6..b3a2889 100644 ---- a/hw/vfio/pci.c -+++ b/hw/vfio/pci.c -@@ -3036,6 +3036,11 @@ static const TypeInfo vfio_pci_dev_info = { - .class_init = vfio_pci_dev_class_init, - .instance_init = vfio_instance_init, - .instance_finalize = vfio_instance_finalize, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_PCIE_DEVICE }, -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { } -+ }, - }; - - static void register_vfio_pci_dev_type(void) -diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c -index 8208aa2..6e497c8 100644 ---- a/hw/virtio/virtio-pci.c -+++ b/hw/virtio/virtio-pci.c -@@ -1958,6 +1958,11 @@ static const TypeInfo virtio_pci_info = { - .class_init = virtio_pci_class_init, - .class_size = sizeof(VirtioPCIClass), - .abstract = true, -+ .interfaces = (InterfaceInfo[]) { -+ { INTERFACE_PCIE_DEVICE }, -+ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { } -+ }, - }; - - /* virtio-blk-pci */ --- -1.8.3.1 - diff --git a/SOURCES/kvm-pci-Validate-interfaces-on-base_class_init.patch b/SOURCES/kvm-pci-Validate-interfaces-on-base_class_init.patch deleted file mode 100644 index 972a64d..0000000 --- a/SOURCES/kvm-pci-Validate-interfaces-on-base_class_init.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 091efe6a8488e0eac52d78fd5db2db76efb891d3 Mon Sep 17 00:00:00 2001 -From: Eduardo Habkost -Date: Fri, 20 Oct 2017 18:29:17 +0200 -Subject: [PATCH 12/19] pci: Validate interfaces on base_class_init - -RH-Author: Eduardo Habkost -Message-id: <20171020182917.10771-8-ehabkost@redhat.com> -Patchwork-id: 77427 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH v2 7/7] pci: Validate interfaces on base_class_init -Bugzilla: 1390348 -RH-Acked-by: Marcel Apfelbaum -RH-Acked-by: Michael S. Tsirkin -RH-Acked-by: Laurent Vivier - -Make sure we don't forget to add the Conventional PCI or PCI -Express interface names on PCI device classes in the future. - -Signed-off-by: Eduardo Habkost -Revieed-by: David Gibson -Reviewed-by: Marcel Apfelbaum -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 2fefa16cec5a719f5cbc26c0672dd2099cd2ed9b) -Signed-off-by: Eduardo Habkost -Signed-off-by: Miroslav Rezanina ---- - hw/pci/pci.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/hw/pci/pci.c b/hw/pci/pci.c -index 1226696..f0c98cd 100644 ---- a/hw/pci/pci.c -+++ b/hw/pci/pci.c -@@ -2525,6 +2525,17 @@ static void pci_device_class_init(ObjectClass *klass, void *data) - pc->realize = pci_default_realize; - } - -+static void pci_device_class_base_init(ObjectClass *klass, void *data) -+{ -+ if (!object_class_is_abstract(klass)) { -+ ObjectClass *conventional = -+ object_class_dynamic_cast(klass, INTERFACE_CONVENTIONAL_PCI_DEVICE); -+ ObjectClass *pcie = -+ object_class_dynamic_cast(klass, INTERFACE_PCIE_DEVICE); -+ assert(conventional || pcie); -+ } -+} -+ - AddressSpace *pci_device_iommu_address_space(PCIDevice *dev) - { - PCIBus *bus = PCI_BUS(dev->bus); -@@ -2649,6 +2660,7 @@ static const TypeInfo pci_device_type_info = { - .abstract = true, - .class_size = sizeof(PCIDeviceClass), - .class_init = pci_device_class_init, -+ .class_base_init = pci_device_class_base_init, - }; - - static void pci_register_types(void) --- -1.8.3.1 - diff --git a/SOURCES/kvm-pci-bus-let-it-has-higher-migration-priority.patch b/SOURCES/kvm-pci-bus-let-it-has-higher-migration-priority.patch deleted file mode 100644 index 7b35ea8..0000000 --- a/SOURCES/kvm-pci-bus-let-it-has-higher-migration-priority.patch +++ /dev/null @@ -1,159 +0,0 @@ -From a80ee7295748aeadc1e2c37a71ee46699c9324cb Mon Sep 17 00:00:00 2001 -From: Peter Xu -Date: Fri, 9 Feb 2018 06:02:44 +0100 -Subject: [PATCH 03/15] pci/bus: let it has higher migration priority - -RH-Author: Peter Xu -Message-id: <20180209060244.17420-1-peterx@redhat.com> -Patchwork-id: 78963 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH] pci/bus: let it has higher migration priority -Bugzilla: 1538953 -RH-Acked-by: Marcel Apfelbaum -RH-Acked-by: Auger Eric -RH-Acked-by: Dr. David Alan Gilbert - -NOTE: downstream does not have hw/pci-bridge/pcie_pci_bridge.c, so the - original change to that file is not needed. - -In the past, we prioritized IOMMU migration so that we have such a -priority order: - - IOMMU > PCI Devices - -When migrating a guest with both vIOMMU and a pcie-root-port, we'll -always migrate vIOMMU first, since pci buses will be seen to have the -same priority of general PCI devices. - -That's problematic. - -The thing is that PCI bus number information is stored in the root port, -and that is needed by vIOMMU during post_load(), e.g., to figure out -context entry for a device. If we don't have correct bus numbers for -devices, we won't be able to recover device state of the DMAR memory -regions, and things will be messed up. - -So let's boost the PCIe root ports to be even with higher priority: - - PCIe Root Port > IOMMU > PCI Devices - -A smoke test shows that this patch fixes bug 1538953. - -Also, apply this rule to all the PCI bus/bridge devices: ioh3420, -xio3130_downstream, xio3130_upstream, pcie_pci_bridge, pci-pci bridge, -i82801b11. - -I noted that we set pcie_pci_bridge_dev_vmstate twice. Clean that up -together. - -CC: Alex Williamson -CC: Marcel Apfelbaum -CC: Michael S. Tsirkin -CC: Dr. David Alan Gilbert -CC: Juan Quintela -CC: Laurent Vivier -Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1538953 -Reported-by: Maxime Coquelin -Signed-off-by: Peter Xu -Reviewed-by: Marcel Apfelbaum -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 9d6b9db19c4b99ce5a1ad75b490c01edd2c2b0cf) -Signed-off-by: Peter Xu -Signed-off-by: Miroslav Rezanina ---- - hw/pci-bridge/gen_pcie_root_port.c | 1 + - hw/pci-bridge/i82801b11.c | 1 + - hw/pci-bridge/ioh3420.c | 1 + - hw/pci-bridge/pci_bridge_dev.c | 1 + - hw/pci-bridge/xio3130_downstream.c | 1 + - hw/pci-bridge/xio3130_upstream.c | 1 + - include/migration/vmstate.h | 1 + - 7 files changed, 7 insertions(+) - -diff --git a/hw/pci-bridge/gen_pcie_root_port.c b/hw/pci-bridge/gen_pcie_root_port.c -index 0e2f2e8..435fbaa 100644 ---- a/hw/pci-bridge/gen_pcie_root_port.c -+++ b/hw/pci-bridge/gen_pcie_root_port.c -@@ -101,6 +101,7 @@ static void gen_rp_realize(DeviceState *dev, Error **errp) - - static const VMStateDescription vmstate_rp_dev = { - .name = "pcie-root-port", -+ .priority = MIG_PRI_PCI_BUS, - .version_id = 1, - .minimum_version_id = 1, - .post_load = pcie_cap_slot_post_load, -diff --git a/hw/pci-bridge/i82801b11.c b/hw/pci-bridge/i82801b11.c -index cb522bf..60df9b2 100644 ---- a/hw/pci-bridge/i82801b11.c -+++ b/hw/pci-bridge/i82801b11.c -@@ -80,6 +80,7 @@ err_bridge: - - static const VMStateDescription i82801b11_bridge_dev_vmstate = { - .name = "i82801b11_bridge", -+ .priority = MIG_PRI_PCI_BUS, - .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE(parent_obj, PCIBridge), - VMSTATE_END_OF_LIST() -diff --git a/hw/pci-bridge/ioh3420.c b/hw/pci-bridge/ioh3420.c -index da4e5bd..a26d104 100644 ---- a/hw/pci-bridge/ioh3420.c -+++ b/hw/pci-bridge/ioh3420.c -@@ -85,6 +85,7 @@ static void ioh3420_interrupts_uninit(PCIDevice *d) - - static const VMStateDescription vmstate_ioh3420 = { - .name = "ioh-3240-express-root-port", -+ .priority = MIG_PRI_PCI_BUS, - .version_id = 1, - .minimum_version_id = 1, - .post_load = pcie_cap_slot_post_load, -diff --git a/hw/pci-bridge/pci_bridge_dev.c b/hw/pci-bridge/pci_bridge_dev.c -index d56f663..b2d861d 100644 ---- a/hw/pci-bridge/pci_bridge_dev.c -+++ b/hw/pci-bridge/pci_bridge_dev.c -@@ -174,6 +174,7 @@ static bool pci_device_shpc_present(void *opaque, int version_id) - - static const VMStateDescription pci_bridge_dev_vmstate = { - .name = "pci_bridge", -+ .priority = MIG_PRI_PCI_BUS, - .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE(parent_obj, PCIBridge), - SHPC_VMSTATE(shpc, PCIDevice, pci_device_shpc_present), -diff --git a/hw/pci-bridge/xio3130_downstream.c b/hw/pci-bridge/xio3130_downstream.c -index 1e09d2a..4dd2e65 100644 ---- a/hw/pci-bridge/xio3130_downstream.c -+++ b/hw/pci-bridge/xio3130_downstream.c -@@ -161,6 +161,7 @@ static Property xio3130_downstream_props[] = { - - static const VMStateDescription vmstate_xio3130_downstream = { - .name = "xio3130-express-downstream-port", -+ .priority = MIG_PRI_PCI_BUS, - .version_id = 1, - .minimum_version_id = 1, - .post_load = pcie_cap_slot_post_load, -diff --git a/hw/pci-bridge/xio3130_upstream.c b/hw/pci-bridge/xio3130_upstream.c -index 227997c..c5f02a6 100644 ---- a/hw/pci-bridge/xio3130_upstream.c -+++ b/hw/pci-bridge/xio3130_upstream.c -@@ -133,6 +133,7 @@ PCIEPort *xio3130_upstream_init(PCIBus *bus, int devfn, bool multifunction, - - static const VMStateDescription vmstate_xio3130_upstream = { - .name = "xio3130-express-upstream-port", -+ .priority = MIG_PRI_PCI_BUS, - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { -diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h -index 85e43da..d23555b 100644 ---- a/include/migration/vmstate.h -+++ b/include/migration/vmstate.h -@@ -148,6 +148,7 @@ enum VMStateFlags { - typedef enum { - MIG_PRI_DEFAULT = 0, - MIG_PRI_IOMMU, /* Must happen before PCI devices */ -+ MIG_PRI_PCI_BUS, /* Must happen before IOMMU */ - MIG_PRI_GICV3_ITS, /* Must happen before PCI devices */ - MIG_PRI_GICV3, /* Must happen before the ITS */ - MIG_PRI_MAX, --- -1.8.3.1 - diff --git a/SOURCES/kvm-pci-conventional-pci-device-and-pci-express-device-i.patch b/SOURCES/kvm-pci-conventional-pci-device-and-pci-express-device-i.patch deleted file mode 100644 index f869465..0000000 --- a/SOURCES/kvm-pci-conventional-pci-device-and-pci-express-device-i.patch +++ /dev/null @@ -1,83 +0,0 @@ -From e4794a20f02368af6260ed3b4d9e040b41734459 Mon Sep 17 00:00:00 2001 -From: Eduardo Habkost -Date: Fri, 20 Oct 2017 18:29:12 +0200 -Subject: [PATCH 07/19] pci: conventional-pci-device and pci-express-device - interfaces - -RH-Author: Eduardo Habkost -Message-id: <20171020182917.10771-3-ehabkost@redhat.com> -Patchwork-id: 77422 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH v2 2/7] pci: conventional-pci-device and pci-express-device interfaces -Bugzilla: 1390348 -RH-Acked-by: Marcel Apfelbaum -RH-Acked-by: Michael S. Tsirkin -RH-Acked-by: Laurent Vivier - -Those two interfaces will be used to indicate which device types -support Conventional PCI or PCI Express buses. Management -software will be able to use the qom-list-types QMP command to -query that information. - -Signed-off-by: Eduardo Habkost -Reviewed-by: David Gibson -Reviewed-by: Marcel Apfelbaum -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 619f02aefc587e5e2821cd84b584eba199c97c9e) -Signed-off-by: Eduardo Habkost -Signed-off-by: Miroslav Rezanina ---- - hw/pci/pci.c | 12 ++++++++++++ - include/hw/pci/pci.h | 6 ++++++ - 2 files changed, 18 insertions(+) - -diff --git a/hw/pci/pci.c b/hw/pci/pci.c -index 258fbe5..1226696 100644 ---- a/hw/pci/pci.c -+++ b/hw/pci/pci.c -@@ -168,6 +168,16 @@ static const TypeInfo pci_bus_info = { - .class_init = pci_bus_class_init, - }; - -+static const TypeInfo pcie_interface_info = { -+ .name = INTERFACE_PCIE_DEVICE, -+ .parent = TYPE_INTERFACE, -+}; -+ -+static const TypeInfo conventional_pci_interface_info = { -+ .name = INTERFACE_CONVENTIONAL_PCI_DEVICE, -+ .parent = TYPE_INTERFACE, -+}; -+ - static const TypeInfo pcie_bus_info = { - .name = TYPE_PCIE_BUS, - .parent = TYPE_PCI_BUS, -@@ -2645,6 +2655,8 @@ static void pci_register_types(void) - { - type_register_static(&pci_bus_info); - type_register_static(&pcie_bus_info); -+ type_register_static(&conventional_pci_interface_info); -+ type_register_static(&pcie_interface_info); - type_register_static(&pci_device_type_info); - } - -diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h -index e598b09..cc6f5d2 100644 ---- a/include/hw/pci/pci.h -+++ b/include/hw/pci/pci.h -@@ -195,6 +195,12 @@ enum { - #define PCI_DEVICE_GET_CLASS(obj) \ - OBJECT_GET_CLASS(PCIDeviceClass, (obj), TYPE_PCI_DEVICE) - -+/* Implemented by devices that can be plugged on PCI Express buses */ -+#define INTERFACE_PCIE_DEVICE "pci-express-device" -+ -+/* Implemented by devices that can be plugged on Conventional PCI buses */ -+#define INTERFACE_CONVENTIONAL_PCI_DEVICE "conventional-pci-device" -+ - typedef struct PCIINTxRoute { - enum { - PCI_INTX_ENABLED, --- -1.8.3.1 - diff --git a/SOURCES/kvm-pcie_root_port-Fix-x-migrate-msix-compat.patch b/SOURCES/kvm-pcie_root_port-Fix-x-migrate-msix-compat.patch deleted file mode 100644 index c2f317c..0000000 --- a/SOURCES/kvm-pcie_root_port-Fix-x-migrate-msix-compat.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 917c9e7df753cd941ddb6f8a8212bd1a45bf3d09 Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Wed, 15 Nov 2017 12:29:19 +0100 -Subject: [PATCH 05/30] pcie_root_port: Fix x-migrate-msix compat - -RH-Author: Dr. David Alan Gilbert -Message-id: <20171115122920.7207-2-dgilbert@redhat.com> -Patchwork-id: 77679 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 1/2] pcie_root_port: Fix x-migrate-msix compat -Bugzilla: 1511312 -RH-Acked-by: Marcel Apfelbaum -RH-Acked-by: Laurent Vivier -RH-Acked-by: Laszlo Ersek - -From: "Dr. David Alan Gilbert" - -2.9 gained a property, x-migrate-msix, on pcie-root-ports -to enable migration of the msix data, it defaulted to on but -was marked as off for backwards compatibility on old machine -types. We picked up this compatibility entry for -HW_COMPAT_RHEL7_4. - -However, this had already been backported to 7.4 -(b131cb258ae, bz 1455150) and since this device was new downstream -in 7.4 there was no need for a compatibility entry. - -Remove the compatibility entry so that x-migrate-msix is true -for all our machine types just like it is in 7.4. - -Signed-off-by: Dr. David Alan Gilbert -Signed-off-by: Miroslav Rezanina ---- - include/hw/compat.h | 8 ++------ - 1 file changed, 2 insertions(+), 6 deletions(-) - -diff --git a/include/hw/compat.h b/include/hw/compat.h -index 7a2a4a6..3f9d356 100644 ---- a/include/hw/compat.h -+++ b/include/hw/compat.h -@@ -414,18 +414,14 @@ - }, - - /* Mostly like HW_COMPAT_2_9 except -- * x-mtu-bypass-backend has already been -- * backported to RHEL7.4 -+ * x-mtu-bypass-backend, x-migrate-msix has already been -+ * backported to RHEL7.4. shpc was already on in 7.4. - */ - #define HW_COMPAT_RHEL7_4 \ - { /* HW_COMPAT_RHEL7_4 */ \ - .driver = "intel-iommu",\ - .property = "pt",\ - .value = "off",\ -- },{ /* HW_COMPAT_RHEL7_4 */ \ -- .driver = "pcie-root-port",\ -- .property = "x-migrate-msix",\ -- .value = "false",\ - }, - - #endif /* HW_COMPAT_H */ --- -1.8.3.1 - diff --git a/SOURCES/kvm-ppc-Change-Power9-compat-table-to-support-at-most-8-.patch b/SOURCES/kvm-ppc-Change-Power9-compat-table-to-support-at-most-8-.patch deleted file mode 100644 index 903a9d9..0000000 --- a/SOURCES/kvm-ppc-Change-Power9-compat-table-to-support-at-most-8-.patch +++ /dev/null @@ -1,59 +0,0 @@ -From ff6a3c436c561a73b00e8dbe4b5c8dc52ecfda40 Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Fri, 19 Jan 2018 04:04:55 +0100 -Subject: [PATCH 15/21] ppc: Change Power9 compat table to support at most 8 - threads/core - -RH-Author: David Gibson -Message-id: <20180119040458.5629-2-dgibson@redhat.com> -Patchwork-id: 78675 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 1/4] ppc: Change Power9 compat table to support at most 8 threads/core -Bugzilla: 1529243 -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier -RH-Acked-by: Miroslav Rezanina - -From: Jose Ricardo Ziviani - -Increases the max smt mode to 8 for Power9. That's because KVM supports -smt emulation in this platform so QEMU should allow users to use it as -well. - -Today if we try to pass -smp ...,threads=8, QEMU will silently truncate -it to smt4 mode and may cause a crash if we try to perform a cpu -hotplug. - -Signed-off-by: Jose Ricardo Ziviani -[dwg: Added an explanatory comment] -Signed-off-by: David Gibson -(cherry picked from commit 03ee51d3548f5f553a3089f466483c1c6d5c666b) - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - target/ppc/compat.c | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/target/ppc/compat.c b/target/ppc/compat.c -index 2d95434..94ff14a 100644 ---- a/target/ppc/compat.c -+++ b/target/ppc/compat.c -@@ -73,7 +73,14 @@ static const CompatInfo compat_table[] = { - .pvr = CPU_POWERPC_LOGICAL_3_00, - .pcr = PCR_COMPAT_3_00, - .pcr_level = PCR_COMPAT_3_00, -- .max_threads = 4, -+ /* -+ * POWER9 hardware only supports 4 threads / core, but this -+ * limit is for guests. We need to support 8 vthreads/vcore -+ * on POWER9 for POWER8 compatibility guests, and it's very -+ * confusing if half of the threads disappear from the guest -+ * if it announces it's POWER9 aware at CAS time. -+ */ -+ .max_threads = 8, - }, - }; - --- -1.8.3.1 - diff --git a/SOURCES/kvm-ppc-fix-VTB-migration.patch b/SOURCES/kvm-ppc-fix-VTB-migration.patch deleted file mode 100644 index abd373e..0000000 --- a/SOURCES/kvm-ppc-fix-VTB-migration.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 43f0b133d1312d042fb31bf7f63bb31a642eef26 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 23 Nov 2017 16:14:21 +0100 -Subject: [PATCH 3/7] ppc: fix VTB migration - -RH-Author: Laurent Vivier -Message-id: <20171123161421.30320-1-lvivier@redhat.com> -Patchwork-id: 77796 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH] ppc: fix VTB migration -Bugzilla: 1506882 -RH-Acked-by: Serhii Popovych -RH-Acked-by: David Gibson -RH-Acked-by: Thomas Huth - -Migration of a system under stress (for example, with -"stress-ng --numa 2") triggers on the destination -some kernel watchdog messages like: - -NMI watchdog: BUG: soft lockup - CPU#0 stuck for 3489660870s! -NMI watchdog: BUG: soft lockup - CPU#1 stuck for 3489660884s! - -This problem appears with the changes introduced by - 42043e4 spapr: clock should count only if vm is running - -I think this commit only triggers the problem. - -Kernel computes the soft lockup duration using the -Virtual Timebase register (VTB), not using the Timebase -Register (TBR, the one 42043e4 stops). - -It appears VTB is not migrated, so this patch adds it in -the list of the SPRs to migrate, and fixes the problem. - -For the migration, I've tested a migration from qemu-2.8.0 and -pseries-2.8.0 to a patched master (qemu-2.11.0-rc1). The received -VTB is 0 (as is it not initialized by qemu-2.8.0), but the value -seems to be ignored by KVM and a non zero VTB is used by the kernel. -I have no explanation for that, but as the original problem appears -only with SMP system under stress I suspect some problems in KVM -(I think because VTB is shared by all threads of a core). - -Signed-off-by: Laurent Vivier -Signed-off-by: David Gibson -(cherry picked from commit 6dd836f5d32b989e18c6dda655a26f4d73a52f6a) -Signed-off-by: Laurent Vivier -Signed-off-by: Miroslav Rezanina ---- - target/ppc/translate_init.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/target/ppc/translate_init.c b/target/ppc/translate_init.c -index 371bbae..9d38882 100644 ---- a/target/ppc/translate_init.c -+++ b/target/ppc/translate_init.c -@@ -8168,10 +8168,10 @@ static void gen_spr_power8_ebb(CPUPPCState *env) - /* Virtual Time Base */ - static void gen_spr_vtb(CPUPPCState *env) - { -- spr_register(env, SPR_VTB, "VTB", -+ spr_register_kvm(env, SPR_VTB, "VTB", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_tbl, SPR_NOACCESS, -- 0x00000000); -+ KVM_REG_PPC_VTB, 0x00000000); - } - - static void gen_spr_power8_fscr(CPUPPCState *env) --- -1.8.3.1 - diff --git a/SOURCES/kvm-ppc-fix-setting-of-compat-mode.patch b/SOURCES/kvm-ppc-fix-setting-of-compat-mode.patch deleted file mode 100644 index 32cad00..0000000 --- a/SOURCES/kvm-ppc-fix-setting-of-compat-mode.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 7f958a52f5e8e4dd02182b308c96d5bde25a1327 Mon Sep 17 00:00:00 2001 -From: Suraj Jitindar Singh -Date: Wed, 6 Dec 2017 02:57:59 +0100 -Subject: [PATCH 19/21] ppc: fix setting of compat mode - -RH-Author: Suraj Jitindar Singh -Message-id: <1512529079-12590-1-git-send-email-sursingh@redhat.com> -Patchwork-id: 78173 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH] ppc: fix setting of compat mode -Bugzilla: 1396119 -RH-Acked-by: David Gibson -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier - -From: Greg Kurz - -While trying to make KVM PR usable again, commit 5dfaa532ae introduced a -regression: the current compat_pvr value is passed to KVM instead of the -new one. This means that we always pass 0 instead of the max-cpu-compat -PVR during the initial machine reset. And at CAS time, we either pass -the PVR from the command line or even don't call kvmppc_set_compat() at -all, ie, the PCR will not be set as expected. - -For example if we start a big endian fedora26 guest in power7 compat -mode on a POWER8 host, we get this in the guest: - -$ cat /proc/cpuinfo -processor : 0 -cpu : POWER7 (architected), altivec supported -clock : 4024.000000MHz -revision : 2.0 (pvr 004d 0200) - -timebase : 512000000 -platform : pSeries -model : IBM pSeries (emulated by qemu) -machine : CHRP IBM pSeries (emulated by qemu) -MMU : Hash - -but the guest can still execute POWER8 instructions, and the following -program succeeds: - -int main() -{ - asm("vncipher 0,0,0"); // ISA 2.07 instruction -} - -Let's pass the new compat_pvr to kvmppc_set_compat() and the program fails -with SIGILL as expected. - -Reported-by: Nageswara R Sastry -Signed-off-by: Greg Kurz -Signed-off-by: David Gibson -(cherry picked from commit e4f0c6bb1a9f72ad9e32c3171d36bae17ea1cd67) - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: Miroslav Rezanina ---- - target/ppc/compat.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/target/ppc/compat.c b/target/ppc/compat.c -index 540b4eb..2d95434 100644 ---- a/target/ppc/compat.c -+++ b/target/ppc/compat.c -@@ -152,7 +152,7 @@ void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp) - cpu_synchronize_state(CPU(cpu)); - - if (kvm_enabled() && cpu->compat_pvr != compat_pvr) { -- int ret = kvmppc_set_compat(cpu, cpu->compat_pvr); -+ int ret = kvmppc_set_compat(cpu, compat_pvr); - if (ret < 0) { - error_setg_errno(errp, -ret, - "Unable to set CPU compatibility mode in KVM"); --- -1.8.3.1 - diff --git a/SOURCES/kvm-ppc-spapr-caps-Add-support-for-custom-spapr_capabili.patch b/SOURCES/kvm-ppc-spapr-caps-Add-support-for-custom-spapr_capabili.patch deleted file mode 100644 index 24e8690..0000000 --- a/SOURCES/kvm-ppc-spapr-caps-Add-support-for-custom-spapr_capabili.patch +++ /dev/null @@ -1,136 +0,0 @@ -From d5704100a478118313ce89e8725c714f20deb094 Mon Sep 17 00:00:00 2001 -From: Suraj Jitindar Singh -Date: Tue, 13 Mar 2018 05:21:32 +0100 -Subject: [PATCH 10/17] ppc/spapr-caps: Add support for custom - spapr_capabilities - -RH-Author: Suraj Jitindar Singh -Message-id: <1520918499-27663-5-git-send-email-sursingh@redhat.com> -Patchwork-id: 79246 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 04/11] ppc/spapr-caps: Add support for custom spapr_capabilities -Bugzilla: 1554957 -RH-Acked-by: David Gibson -RH-Acked-by: Laurent Vivier -RH-Acked-by: Miroslav Rezanina - -From: Suraj Jitindar Singh - -There are currently 2 implemented types of spapr-caps, boolean and -tristate. However there may be a need for caps which don't fit either of -these options. Add a custom capability type for which a list of custom -valid strings can be specified and implement the get/set functions for -these. Also add a field for help text to describe the available options. - -Signed-off-by: Suraj Jitindar Singh -[dwg: Change "help" option to "?" matching qemu conventions] -[dwg: Add ATTRIBUTE_UNUSED to avoid breaking bisect] -Signed-off-by: David Gibson - -(cherry picked from commit 87175d1bc5272fff5cffb05c410b39f839dfc948) - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1548919 - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr_caps.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 70 insertions(+) - -diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c -index 99a4b71..3d8b796 100644 ---- a/hw/ppc/spapr_caps.c -+++ b/hw/ppc/spapr_caps.c -@@ -32,6 +32,20 @@ - - #include "hw/ppc/spapr.h" - -+typedef struct sPAPRCapPossible { -+ int num; /* size of vals array below */ -+ const char *help; /* help text for vals */ -+ /* -+ * Note: -+ * - because of the way compatibility is determined vals MUST be ordered -+ * such that later options are a superset of all preceding options. -+ * - the order of vals must be preserved, that is their index is important, -+ * however vals may be added to the end of the list so long as the above -+ * point is observed -+ */ -+ const char *vals[]; -+} sPAPRCapPossible; -+ - typedef struct sPAPRCapabilityInfo { - const char *name; - const char *description; -@@ -41,6 +55,8 @@ typedef struct sPAPRCapabilityInfo { - ObjectPropertyAccessor *get; - ObjectPropertyAccessor *set; - const char *type; -+ /* Possible values if this is a custom string type */ -+ sPAPRCapPossible *possible; - /* Make sure the virtual hardware can support this capability */ - void (*apply)(sPAPRMachineState *spapr, uint8_t val, Error **errp); - } sPAPRCapabilityInfo; -@@ -133,6 +149,60 @@ out: - g_free(val); - } - -+static void ATTRIBUTE_UNUSED spapr_cap_get_string(Object *obj, Visitor *v, -+ const char *name, -+ void *opaque, Error **errp) -+{ -+ sPAPRCapabilityInfo *cap = opaque; -+ sPAPRMachineState *spapr = SPAPR_MACHINE(obj); -+ char *val = NULL; -+ uint8_t value = spapr_get_cap(spapr, cap->index); -+ -+ if (value >= cap->possible->num) { -+ error_setg(errp, "Invalid value (%d) for cap-%s", value, cap->name); -+ return; -+ } -+ -+ val = g_strdup(cap->possible->vals[value]); -+ -+ visit_type_str(v, name, &val, errp); -+ g_free(val); -+} -+ -+static void ATTRIBUTE_UNUSED spapr_cap_set_string(Object *obj, Visitor *v, -+ const char *name, -+ void *opaque, Error **errp) -+{ -+ sPAPRCapabilityInfo *cap = opaque; -+ sPAPRMachineState *spapr = SPAPR_MACHINE(obj); -+ Error *local_err = NULL; -+ uint8_t i; -+ char *val; -+ -+ visit_type_str(v, name, &val, &local_err); -+ if (local_err) { -+ error_propagate(errp, local_err); -+ return; -+ } -+ -+ if (!strcmp(val, "?")) { -+ error_setg(errp, "%s", cap->possible->help); -+ goto out; -+ } -+ for (i = 0; i < cap->possible->num; i++) { -+ if (!strcasecmp(val, cap->possible->vals[i])) { -+ spapr->cmd_line_caps[cap->index] = true; -+ spapr->eff.caps[cap->index] = i; -+ goto out; -+ } -+ } -+ -+ error_setg(errp, "Invalid capability mode \"%s\" for cap-%s", val, -+ cap->name); -+out: -+ g_free(val); -+} -+ - static void cap_htm_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp) - { - if (!val) { --- -1.8.3.1 - diff --git a/SOURCES/kvm-ppc-spapr-caps-Change-migration-macro-to-take-full-s.patch b/SOURCES/kvm-ppc-spapr-caps-Change-migration-macro-to-take-full-s.patch deleted file mode 100644 index 8259a1f..0000000 --- a/SOURCES/kvm-ppc-spapr-caps-Change-migration-macro-to-take-full-s.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 798cff99adef284cd804b031a4e4004016fd1f0b Mon Sep 17 00:00:00 2001 -From: Suraj Jitindar Singh -Date: Tue, 13 Mar 2018 05:21:29 +0100 -Subject: [PATCH 07/17] ppc/spapr-caps: Change migration macro to take full - spapr-cap name - -RH-Author: Suraj Jitindar Singh -Message-id: <1520918499-27663-2-git-send-email-sursingh@redhat.com> -Patchwork-id: 79245 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 01/11] ppc/spapr-caps: Change migration macro to take full spapr-cap name -Bugzilla: 1554957 -RH-Acked-by: David Gibson -RH-Acked-by: Laurent Vivier -RH-Acked-by: Miroslav Rezanina - -From: Suraj Jitindar Singh - -Change the macro that generates the vmstate migration field and the needed -function for the spapr-caps to take the full spapr-cap name. This has -the benefit of meaning this instance will be picked up when greping -for the spapr-caps and making it more obvious what this macro is doing. - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: David Gibson -(cherry picked from commit 8c5909c41916f25b47bfdc465059a926603c1319) - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1548919 - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr_caps.c | 30 +++++++++++++++--------------- - 1 file changed, 15 insertions(+), 15 deletions(-) - -diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c -index 62efdae..e69d308 100644 ---- a/hw/ppc/spapr_caps.c -+++ b/hw/ppc/spapr_caps.c -@@ -350,34 +350,34 @@ int spapr_caps_post_migration(sPAPRMachineState *spapr) - } - - /* Used to generate the migration field and needed function for a spapr cap */ --#define SPAPR_CAP_MIG_STATE(cap, ccap) \ --static bool spapr_cap_##cap##_needed(void *opaque) \ -+#define SPAPR_CAP_MIG_STATE(sname, cap) \ -+static bool spapr_cap_##sname##_needed(void *opaque) \ - { \ - sPAPRMachineState *spapr = opaque; \ - \ -- return spapr->cmd_line_caps[SPAPR_CAP_##ccap] && \ -- (spapr->eff.caps[SPAPR_CAP_##ccap] != \ -- spapr->def.caps[SPAPR_CAP_##ccap]); \ -+ return spapr->cmd_line_caps[cap] && \ -+ (spapr->eff.caps[cap] != \ -+ spapr->def.caps[cap]); \ - } \ - \ --const VMStateDescription vmstate_spapr_cap_##cap = { \ -- .name = "spapr/cap/" #cap, \ -+const VMStateDescription vmstate_spapr_cap_##sname = { \ -+ .name = "spapr/cap/" #sname, \ - .version_id = 1, \ - .minimum_version_id = 1, \ -- .needed = spapr_cap_##cap##_needed, \ -+ .needed = spapr_cap_##sname##_needed, \ - .fields = (VMStateField[]) { \ -- VMSTATE_UINT8(mig.caps[SPAPR_CAP_##ccap], \ -+ VMSTATE_UINT8(mig.caps[cap], \ - sPAPRMachineState), \ - VMSTATE_END_OF_LIST() \ - }, \ - } - --SPAPR_CAP_MIG_STATE(htm, HTM); --SPAPR_CAP_MIG_STATE(vsx, VSX); --SPAPR_CAP_MIG_STATE(dfp, DFP); --SPAPR_CAP_MIG_STATE(cfpc, CFPC); --SPAPR_CAP_MIG_STATE(sbbc, SBBC); --SPAPR_CAP_MIG_STATE(ibs, IBS); -+SPAPR_CAP_MIG_STATE(htm, SPAPR_CAP_HTM); -+SPAPR_CAP_MIG_STATE(vsx, SPAPR_CAP_VSX); -+SPAPR_CAP_MIG_STATE(dfp, SPAPR_CAP_DFP); -+SPAPR_CAP_MIG_STATE(cfpc, SPAPR_CAP_CFPC); -+SPAPR_CAP_MIG_STATE(sbbc, SPAPR_CAP_SBBC); -+SPAPR_CAP_MIG_STATE(ibs, SPAPR_CAP_IBS); - - void spapr_caps_reset(sPAPRMachineState *spapr) - { --- -1.8.3.1 - diff --git a/SOURCES/kvm-ppc-spapr-caps-Convert-cap-cfpc-to-custom-spapr-cap.patch b/SOURCES/kvm-ppc-spapr-caps-Convert-cap-cfpc-to-custom-spapr-cap.patch deleted file mode 100644 index 5574e59..0000000 --- a/SOURCES/kvm-ppc-spapr-caps-Convert-cap-cfpc-to-custom-spapr-cap.patch +++ /dev/null @@ -1,109 +0,0 @@ -From e9c565a32315df050f7181931e545270de1641d0 Mon Sep 17 00:00:00 2001 -From: Suraj Jitindar Singh -Date: Tue, 13 Mar 2018 05:21:33 +0100 -Subject: [PATCH 11/17] ppc/spapr-caps: Convert cap-cfpc to custom spapr-cap - -RH-Author: Suraj Jitindar Singh -Message-id: <1520918499-27663-6-git-send-email-sursingh@redhat.com> -Patchwork-id: 79251 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 05/11] ppc/spapr-caps: Convert cap-cfpc to custom spapr-cap -Bugzilla: 1554957 -RH-Acked-by: David Gibson -RH-Acked-by: Laurent Vivier -RH-Acked-by: Miroslav Rezanina - -From: Suraj Jitindar Singh - -Convert cap-cfpc (cache flush on privilege change) to a custom spapr-cap -type. - -Signed-off-by: Suraj Jitindar Singh -[dwg: Don't explicitly list "?"/help option, trusting convention] -[dwg: Strip no-longer-necessary ATTRIBUTE_UNUSED back off] -[dwg: Fix some minor style problems] -Signed-off-by: David Gibson - -(cherry picked from commit f27aa81e72b5a5e184a0f3aa3e77061f4fcfb265) - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1548919 - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr_caps.c | 33 ++++++++++++++++++++++----------- - 1 file changed, 22 insertions(+), 11 deletions(-) - -diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c -index 3d8b796..b5a991f 100644 ---- a/hw/ppc/spapr_caps.c -+++ b/hw/ppc/spapr_caps.c -@@ -149,9 +149,8 @@ out: - g_free(val); - } - --static void ATTRIBUTE_UNUSED spapr_cap_get_string(Object *obj, Visitor *v, -- const char *name, -- void *opaque, Error **errp) -+static void spapr_cap_get_string(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) - { - sPAPRCapabilityInfo *cap = opaque; - sPAPRMachineState *spapr = SPAPR_MACHINE(obj); -@@ -169,9 +168,8 @@ static void ATTRIBUTE_UNUSED spapr_cap_get_string(Object *obj, Visitor *v, - g_free(val); - } - --static void ATTRIBUTE_UNUSED spapr_cap_set_string(Object *obj, Visitor *v, -- const char *name, -- void *opaque, Error **errp) -+static void spapr_cap_set_string(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) - { - sPAPRCapabilityInfo *cap = opaque; - sPAPRMachineState *spapr = SPAPR_MACHINE(obj); -@@ -250,14 +248,26 @@ static void cap_dfp_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp) - } - } - -+sPAPRCapPossible cap_cfpc_possible = { -+ .num = 3, -+ .vals = {"broken", "workaround", "fixed"}, -+ .help = "broken - no protection, workaround - workaround available," -+ " fixed - fixed in hardware", -+}; -+ - static void cap_safe_cache_apply(sPAPRMachineState *spapr, uint8_t val, - Error **errp) - { -+ uint8_t kvm_val = kvmppc_get_cap_safe_cache(); -+ - if (tcg_enabled() && val) { - /* TODO - for now only allow broken for TCG */ -- error_setg(errp, "Requested safe cache capability level not supported by tcg, try a different value for cap-cfpc"); -- } else if (kvm_enabled() && (val > kvmppc_get_cap_safe_cache())) { -- error_setg(errp, "Requested safe cache capability level not supported by kvm, try a different value for cap-cfpc"); -+ error_setg(errp, -+"Requested safe cache capability level not supported by tcg, try a different value for cap-cfpc"); -+ } else if (kvm_enabled() && (val > kvm_val)) { -+ error_setg(errp, -+"Requested safe cache capability level not supported by kvm, try cap-cfpc=%s", -+ cap_cfpc_possible.vals[kvm_val]); - } - } - -@@ -319,9 +329,10 @@ sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = { - .name = "cfpc", - .description = "Cache Flush on Privilege Change" VALUE_DESC_TRISTATE, - .index = SPAPR_CAP_CFPC, -- .get = spapr_cap_get_tristate, -- .set = spapr_cap_set_tristate, -+ .get = spapr_cap_get_string, -+ .set = spapr_cap_set_string, - .type = "string", -+ .possible = &cap_cfpc_possible, - .apply = cap_safe_cache_apply, - }, - [SPAPR_CAP_SBBC] = { --- -1.8.3.1 - diff --git a/SOURCES/kvm-ppc-spapr-caps-Convert-cap-ibs-to-custom-spapr-cap.patch b/SOURCES/kvm-ppc-spapr-caps-Convert-cap-ibs-to-custom-spapr-cap.patch deleted file mode 100644 index 7008246..0000000 --- a/SOURCES/kvm-ppc-spapr-caps-Convert-cap-ibs-to-custom-spapr-cap.patch +++ /dev/null @@ -1,226 +0,0 @@ -From 150289beb689037a96b526a4a266da844ee572b8 Mon Sep 17 00:00:00 2001 -From: Suraj Jitindar Singh -Date: Tue, 13 Mar 2018 05:21:35 +0100 -Subject: [PATCH 13/17] ppc/spapr-caps: Convert cap-ibs to custom spapr-cap - -RH-Author: Suraj Jitindar Singh -Message-id: <1520918499-27663-8-git-send-email-sursingh@redhat.com> -Patchwork-id: 79254 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 07/11] ppc/spapr-caps: Convert cap-ibs to custom spapr-cap -Bugzilla: 1554957 -RH-Acked-by: David Gibson -RH-Acked-by: Laurent Vivier -RH-Acked-by: Miroslav Rezanina - -From: Suraj Jitindar Singh - -Convert cap-ibs (indirect branch speculation) to a custom spapr-cap -type. - -All tristate caps have now been converted to custom spapr-caps, so -remove the remaining support for them. - -Signed-off-by: Suraj Jitindar Singh -[dwg: Don't explicitly list "?"/help option, trust convention] -[dwg: Fold tristate removal into here, to not break bisect] -[dwg: Fix minor style problems] -Signed-off-by: David Gibson - -(cherry picked from commit c76c0d3090136773219baad486c836c67ba9ea6d) - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1548919 - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr_caps.c | 90 ++++++++++++++------------------------------------ - hw/ppc/spapr_hcall.c | 5 ++- - include/hw/ppc/spapr.h | 5 ++- - target/ppc/kvm.c | 6 ++-- - 4 files changed, 36 insertions(+), 70 deletions(-) - -diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c -index 8748692..da1f519 100644 ---- a/hw/ppc/spapr_caps.c -+++ b/hw/ppc/spapr_caps.c -@@ -89,65 +89,6 @@ static void spapr_cap_set_bool(Object *obj, Visitor *v, const char *name, - spapr->eff.caps[cap->index] = value ? SPAPR_CAP_ON : SPAPR_CAP_OFF; - } - --static void spapr_cap_get_tristate(Object *obj, Visitor *v, const char *name, -- void *opaque, Error **errp) --{ -- sPAPRCapabilityInfo *cap = opaque; -- sPAPRMachineState *spapr = SPAPR_MACHINE(obj); -- char *val = NULL; -- uint8_t value = spapr_get_cap(spapr, cap->index); -- -- switch (value) { -- case SPAPR_CAP_BROKEN: -- val = g_strdup("broken"); -- break; -- case SPAPR_CAP_WORKAROUND: -- val = g_strdup("workaround"); -- break; -- case SPAPR_CAP_FIXED: -- val = g_strdup("fixed"); -- break; -- default: -- error_setg(errp, "Invalid value (%d) for cap-%s", value, cap->name); -- return; -- } -- -- visit_type_str(v, name, &val, errp); -- g_free(val); --} -- --static void spapr_cap_set_tristate(Object *obj, Visitor *v, const char *name, -- void *opaque, Error **errp) --{ -- sPAPRCapabilityInfo *cap = opaque; -- sPAPRMachineState *spapr = SPAPR_MACHINE(obj); -- char *val; -- Error *local_err = NULL; -- uint8_t value; -- -- visit_type_str(v, name, &val, &local_err); -- if (local_err) { -- error_propagate(errp, local_err); -- return; -- } -- -- if (!strcasecmp(val, "broken")) { -- value = SPAPR_CAP_BROKEN; -- } else if (!strcasecmp(val, "workaround")) { -- value = SPAPR_CAP_WORKAROUND; -- } else if (!strcasecmp(val, "fixed")) { -- value = SPAPR_CAP_FIXED; -- } else { -- error_setg(errp, "Invalid capability mode \"%s\" for cap-%s", val, -- cap->name); -- goto out; -- } -- -- spapr->cmd_line_caps[cap->index] = true; -- spapr->eff.caps[cap->index] = value; --out: -- g_free(val); --} - - static void spapr_cap_get_string(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -@@ -294,16 +235,31 @@ static void cap_safe_bounds_check_apply(sPAPRMachineState *spapr, uint8_t val, - } - } - -+sPAPRCapPossible cap_ibs_possible = { -+ .num = 4, -+ /* Note workaround only maintained for compatibility */ -+ .vals = {"broken", "workaround", "fixed-ibs", "fixed-ccd"}, -+ .help = "broken - no protection, fixed-ibs - indirect branch serialisation," -+ " fixed-ccd - cache count disabled", -+}; -+ - static void cap_safe_indirect_branch_apply(sPAPRMachineState *spapr, - uint8_t val, Error **errp) - { -+ uint8_t kvm_val = kvmppc_get_cap_safe_indirect_branch(); -+ - if (val == SPAPR_CAP_WORKAROUND) { /* Can only be Broken or Fixed */ -- error_setg(errp, "Requested safe indirect branch capability level \"workaround\" not valid, try cap-ibs=fixed"); -+ error_setg(errp, -+"Requested safe indirect branch capability level \"workaround\" not valid, try cap-ibs=%s", -+ cap_ibs_possible.vals[kvm_val]); - } else if (tcg_enabled() && val) { - /* TODO - for now only allow broken for TCG */ -- error_setg(errp, "Requested safe indirect branch capability level not supported by tcg, try a different value for cap-ibs"); -- } else if (kvm_enabled() && (val > kvmppc_get_cap_safe_indirect_branch())) { -- error_setg(errp, "Requested safe indirect branch capability level not supported by kvm, try a different value for cap-ibs"); -+ error_setg(errp, -+"Requested safe indirect branch capability level not supported by tcg, try a different value for cap-ibs"); -+ } else if (kvm_enabled() && val && (val != kvm_val)) { -+ error_setg(errp, -+"Requested safe indirect branch capability level not supported by kvm, try cap-ibs=%s", -+ cap_ibs_possible.vals[kvm_val]); - } - } - -@@ -359,11 +315,13 @@ sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = { - }, - [SPAPR_CAP_IBS] = { - .name = "ibs", -- .description = "Indirect Branch Serialisation (broken, fixed)", -+ .description = -+ "Indirect Branch Speculation (broken, fixed-ibs, fixed-ccd)", - .index = SPAPR_CAP_IBS, -- .get = spapr_cap_get_tristate, -- .set = spapr_cap_set_tristate, -+ .get = spapr_cap_get_string, -+ .set = spapr_cap_set_string, - .type = "string", -+ .possible = &cap_ibs_possible, - .apply = cap_safe_indirect_branch_apply, - }, - }; -diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c -index d3f811a..1a5dd7c 100644 ---- a/hw/ppc/spapr_hcall.c -+++ b/hw/ppc/spapr_hcall.c -@@ -1670,7 +1670,10 @@ static target_ulong h_get_cpu_characteristics(PowerPCCPU *cpu, - } - - switch (safe_indirect_branch) { -- case SPAPR_CAP_FIXED: -+ case SPAPR_CAP_FIXED_CCD: -+ characteristics |= H_CPU_CHAR_CACHE_COUNT_DIS; -+ break; -+ case SPAPR_CAP_FIXED_IBS: - characteristics |= H_CPU_CHAR_BCCTRL_SERIALISED; - break; - default: /* broken */ -diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h -index 375b2ba..fb35008 100644 ---- a/include/hw/ppc/spapr.h -+++ b/include/hw/ppc/spapr.h -@@ -75,10 +75,12 @@ typedef enum { - /* Bool Caps */ - #define SPAPR_CAP_OFF 0x00 - #define SPAPR_CAP_ON 0x01 --/* Broken | Workaround | Fixed Caps */ -+/* Custom Caps */ - #define SPAPR_CAP_BROKEN 0x00 - #define SPAPR_CAP_WORKAROUND 0x01 - #define SPAPR_CAP_FIXED 0x02 -+#define SPAPR_CAP_FIXED_IBS 0x02 -+#define SPAPR_CAP_FIXED_CCD 0x03 - - typedef struct sPAPRCapabilities sPAPRCapabilities; - struct sPAPRCapabilities { -@@ -315,6 +317,7 @@ struct sPAPRMachineState { - #define H_CPU_CHAR_L1D_THREAD_PRIV PPC_BIT(4) - #define H_CPU_CHAR_HON_BRANCH_HINTS PPC_BIT(5) - #define H_CPU_CHAR_THR_RECONF_TRIG PPC_BIT(6) -+#define H_CPU_CHAR_CACHE_COUNT_DIS PPC_BIT(7) - #define H_CPU_BEHAV_FAVOUR_SECURITY PPC_BIT(0) - #define H_CPU_BEHAV_L1D_FLUSH_PR PPC_BIT(1) - #define H_CPU_BEHAV_BNDS_CHK_SPEC_BAR PPC_BIT(2) -diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c -index 4383953..4cd6c92 100644 ---- a/target/ppc/kvm.c -+++ b/target/ppc/kvm.c -@@ -2511,8 +2511,10 @@ static void kvmppc_get_cpu_characteristics(KVMState *s) - cap_ppc_safe_bounds_check = 1; - } - /* Parse and set cap_ppc_safe_indirect_branch */ -- if (c.character & c.character_mask & H_CPU_CHAR_BCCTRL_SERIALISED) { -- cap_ppc_safe_indirect_branch = 2; -+ if (c.character & c.character_mask & H_CPU_CHAR_CACHE_COUNT_DIS) { -+ cap_ppc_safe_indirect_branch = SPAPR_CAP_FIXED_CCD; -+ } else if (c.character & c.character_mask & H_CPU_CHAR_BCCTRL_SERIALISED) { -+ cap_ppc_safe_indirect_branch = SPAPR_CAP_FIXED_IBS; - } - } - --- -1.8.3.1 - diff --git a/SOURCES/kvm-ppc-spapr-caps-Convert-cap-sbbc-to-custom-spapr-cap.patch b/SOURCES/kvm-ppc-spapr-caps-Convert-cap-sbbc-to-custom-spapr-cap.patch deleted file mode 100644 index cb48433..0000000 --- a/SOURCES/kvm-ppc-spapr-caps-Convert-cap-sbbc-to-custom-spapr-cap.patch +++ /dev/null @@ -1,85 +0,0 @@ -From bf60dd793e4a04ab7952aa8e5046436113805c0d Mon Sep 17 00:00:00 2001 -From: Suraj Jitindar Singh -Date: Tue, 13 Mar 2018 05:21:34 +0100 -Subject: [PATCH 12/17] ppc/spapr-caps: Convert cap-sbbc to custom spapr-cap - -RH-Author: Suraj Jitindar Singh -Message-id: <1520918499-27663-7-git-send-email-sursingh@redhat.com> -Patchwork-id: 79253 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 06/11] ppc/spapr-caps: Convert cap-sbbc to custom spapr-cap -Bugzilla: 1554957 -RH-Acked-by: David Gibson -RH-Acked-by: Laurent Vivier -RH-Acked-by: Miroslav Rezanina - -From: Suraj Jitindar Singh - -Convert cap-sbbc (speculation barrier bounds checking) to a custom -spapr-cap type. - -Signed-off-by: Suraj Jitindar Singh -[dwg: Removed trailing whitespace] -[dwg: Don't explicitly list "?"/help option, trust convention] -[dwg: Fix some minor style problems] -Signed-off-by: David Gibson - -(cherry picked from commit aaf265ffde352c4100a8e2adc554ec11aa6abe08) - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1548919 - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr_caps.c | 23 ++++++++++++++++++----- - 1 file changed, 18 insertions(+), 5 deletions(-) - -diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c -index b5a991f..8748692 100644 ---- a/hw/ppc/spapr_caps.c -+++ b/hw/ppc/spapr_caps.c -@@ -271,14 +271,26 @@ static void cap_safe_cache_apply(sPAPRMachineState *spapr, uint8_t val, - } - } - -+sPAPRCapPossible cap_sbbc_possible = { -+ .num = 3, -+ .vals = {"broken", "workaround", "fixed"}, -+ .help = "broken - no protection, workaround - workaround available," -+ " fixed - fixed in hardware", -+}; -+ - static void cap_safe_bounds_check_apply(sPAPRMachineState *spapr, uint8_t val, - Error **errp) - { -+ uint8_t kvm_val = kvmppc_get_cap_safe_bounds_check(); -+ - if (tcg_enabled() && val) { - /* TODO - for now only allow broken for TCG */ -- error_setg(errp, "Requested safe bounds check capability level not supported by tcg, try a different value for cap-sbbc"); -- } else if (kvm_enabled() && (val > kvmppc_get_cap_safe_bounds_check())) { -- error_setg(errp, "Requested safe bounds check capability level not supported by kvm, try a different value for cap-sbbc"); -+ error_setg(errp, -+"Requested safe bounds check capability level not supported by tcg, try a different value for cap-sbbc"); -+ } else if (kvm_enabled() && (val > kvm_val)) { -+ error_setg(errp, -+"Requested safe bounds check capability level not supported by kvm, try cap-sbbc=%s", -+ cap_sbbc_possible.vals[kvm_val]); - } - } - -@@ -339,9 +351,10 @@ sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = { - .name = "sbbc", - .description = "Speculation Barrier Bounds Checking" VALUE_DESC_TRISTATE, - .index = SPAPR_CAP_SBBC, -- .get = spapr_cap_get_tristate, -- .set = spapr_cap_set_tristate, -+ .get = spapr_cap_get_string, -+ .set = spapr_cap_set_string, - .type = "string", -+ .possible = &cap_sbbc_possible, - .apply = cap_safe_bounds_check_apply, - }, - [SPAPR_CAP_IBS] = { --- -1.8.3.1 - diff --git a/SOURCES/kvm-ppc-spapr-caps-Define-the-pseries-2.12-sxxm-machine-.patch b/SOURCES/kvm-ppc-spapr-caps-Define-the-pseries-2.12-sxxm-machine-.patch deleted file mode 100644 index e691630..0000000 --- a/SOURCES/kvm-ppc-spapr-caps-Define-the-pseries-2.12-sxxm-machine-.patch +++ /dev/null @@ -1,132 +0,0 @@ -From c51968caca390f8feade4d61c32778cf8c51c68a Mon Sep 17 00:00:00 2001 -From: Suraj Jitindar Singh -Date: Tue, 13 Mar 2018 05:21:36 +0100 -Subject: [PATCH 14/17] ppc/spapr-caps: Define the pseries-2.12-sxxm machine - type - -RH-Author: Suraj Jitindar Singh -Message-id: <1520918499-27663-9-git-send-email-sursingh@redhat.com> -Patchwork-id: 79255 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 08/11] ppc/spapr-caps: Define the pseries-2.12-sxxm machine type -Bugzilla: 1554957 -RH-Acked-by: David Gibson -RH-Acked-by: Laurent Vivier -RH-Acked-by: Miroslav Rezanina - -From: Suraj Jitindar Singh - -The sxxm (speculative execution exploit mitigation) machine type is a -variant of the 2.12 machine type with workarounds for speculative -execution vulnerabilities enabled by default. - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: David Gibson -(cherry picked from commit 813f3cf655c6f3afe6e2ef04281ba7cd5ea24357) - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1548919 - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ - hw/ppc/spapr_caps.c | 11 +++++++++++ - 2 files changed, 64 insertions(+) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index c71ffac..a43e64c 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -3756,6 +3756,59 @@ static const TypeInfo spapr_machine_info = { - - #if 0 /* Disabled for Red Hat Enterprise Linux */ - /* -+ * pseries-2.12 -+ */ -+static void spapr_machine_2_12_instance_options(MachineState *machine) -+{ -+} -+ -+static void spapr_machine_2_12_class_options(MachineClass *mc) -+{ -+ /* Defaults for the latest behaviour inherited from the base class */ -+} -+ -+DEFINE_SPAPR_MACHINE(2_12, "2.12", true); -+ -+static void spapr_machine_2_12_sxxm_instance_options(MachineState *machine) -+{ -+ spapr_machine_2_12_instance_options(machine); -+} -+ -+static void spapr_machine_2_12_sxxm_class_options(MachineClass *mc) -+{ -+ sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); -+ -+ spapr_machine_2_12_class_options(mc); -+ smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND; -+ smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND; -+ smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_FIXED_CCD; -+} -+ -+DEFINE_SPAPR_MACHINE(2_12_sxxm, "2.12-sxxm", false); -+ -+/* -+ * pseries-2.11 -+ */ -+#define SPAPR_COMPAT_2_11 \ -+ HW_COMPAT_2_11 -+ -+static void spapr_machine_2_11_instance_options(MachineState *machine) -+{ -+ spapr_machine_2_12_instance_options(machine); -+} -+ -+static void spapr_machine_2_11_class_options(MachineClass *mc) -+{ -+ sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); -+ -+ spapr_machine_2_12_class_options(mc); -+ smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_ON; -+ SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_11); -+} -+ -+DEFINE_SPAPR_MACHINE(2_11, "2.11", false); -+ -+/* - * pseries-2.10 - */ - static void spapr_machine_2_10_instance_options(MachineState *machine) -diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c -index da1f519..531e145 100644 ---- a/hw/ppc/spapr_caps.c -+++ b/hw/ppc/spapr_caps.c -@@ -335,15 +335,26 @@ static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr, - - caps = smc->default_caps; - -+ if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00, -+ 0, spapr->max_compat_pvr)) { -+ caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN; -+ } -+ - if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07, - 0, spapr->max_compat_pvr)) { - caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF; - } - -+ if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06_PLUS, -+ 0, spapr->max_compat_pvr)) { -+ caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN; -+ } -+ - if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06, - 0, spapr->max_compat_pvr)) { - caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_OFF; - caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_OFF; -+ caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN; - } - - return caps; --- -1.8.3.1 - diff --git a/SOURCES/kvm-ppc-spapr-caps-Disallow-setting-workaround-for-spapr.patch b/SOURCES/kvm-ppc-spapr-caps-Disallow-setting-workaround-for-spapr.patch deleted file mode 100644 index 0dfe734..0000000 --- a/SOURCES/kvm-ppc-spapr-caps-Disallow-setting-workaround-for-spapr.patch +++ /dev/null @@ -1,65 +0,0 @@ -From cb43b40e88fde117852a7a52506e4421d82c4fc8 Mon Sep 17 00:00:00 2001 -From: Suraj Jitindar Singh -Date: Tue, 13 Mar 2018 05:21:30 +0100 -Subject: [PATCH 08/17] ppc/spapr-caps: Disallow setting workaround for - spapr-cap-ibs - -RH-Author: Suraj Jitindar Singh -Message-id: <1520918499-27663-3-git-send-email-sursingh@redhat.com> -Patchwork-id: 79252 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 02/11] ppc/spapr-caps: Disallow setting workaround for spapr-cap-ibs -Bugzilla: 1554957 -RH-Acked-by: David Gibson -RH-Acked-by: Laurent Vivier -RH-Acked-by: Miroslav Rezanina - -From: Suraj Jitindar Singh - -The spapr-cap cap-ibs can only have values broken or fixed as there is -no explicit workaround required. Currently setting the value workaround -for this cap will hit an assert if the guest makes the hcall -h_get_cpu_characteristics. - -Report an error when attempting to apply the setting with a more helpful -error message. - -Reported-by: Satheesh Rajendran -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: David Gibson -(cherry picked from commit 4f5b039d2bf9bb26b6e26a3dc65da36fe970cba9) - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1548919 - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr_caps.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c -index e69d308..99a4b71 100644 ---- a/hw/ppc/spapr_caps.c -+++ b/hw/ppc/spapr_caps.c -@@ -205,7 +205,9 @@ static void cap_safe_bounds_check_apply(sPAPRMachineState *spapr, uint8_t val, - static void cap_safe_indirect_branch_apply(sPAPRMachineState *spapr, - uint8_t val, Error **errp) - { -- if (tcg_enabled() && val) { -+ if (val == SPAPR_CAP_WORKAROUND) { /* Can only be Broken or Fixed */ -+ error_setg(errp, "Requested safe indirect branch capability level \"workaround\" not valid, try cap-ibs=fixed"); -+ } else if (tcg_enabled() && val) { - /* TODO - for now only allow broken for TCG */ - error_setg(errp, "Requested safe indirect branch capability level not supported by tcg, try a different value for cap-ibs"); - } else if (kvm_enabled() && (val > kvmppc_get_cap_safe_indirect_branch())) { -@@ -263,7 +265,7 @@ sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = { - }, - [SPAPR_CAP_IBS] = { - .name = "ibs", -- .description = "Indirect Branch Serialisation" VALUE_DESC_TRISTATE, -+ .description = "Indirect Branch Serialisation (broken, fixed)", - .index = SPAPR_CAP_IBS, - .get = spapr_cap_get_tristate, - .set = spapr_cap_set_tristate, --- -1.8.3.1 - diff --git a/SOURCES/kvm-ppc-spapr_caps-Don-t-disable-cap_cfpc-on-POWER8-by-d.patch b/SOURCES/kvm-ppc-spapr_caps-Don-t-disable-cap_cfpc-on-POWER8-by-d.patch new file mode 100644 index 0000000..9ae3b8a --- /dev/null +++ b/SOURCES/kvm-ppc-spapr_caps-Don-t-disable-cap_cfpc-on-POWER8-by-d.patch @@ -0,0 +1,60 @@ +From 003ad494e12c03291a61039302eb766372929130 Mon Sep 17 00:00:00 2001 +From: Suraj Jitindar Singh +Date: Thu, 21 Jun 2018 06:56:49 +0200 +Subject: [PATCH 54/54] ppc/spapr_caps: Don't disable cap_cfpc on POWER8 by + default + +RH-Author: Suraj Jitindar Singh +Message-id: <1529564209-30369-4-git-send-email-sursingh@redhat.com> +Patchwork-id: 80929 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 3/3] ppc/spapr_caps: Don't disable cap_cfpc on POWER8 by default +Bugzilla: 1560847 +RH-Acked-by: Laurent Vivier +RH-Acked-by: David Gibson +RH-Acked-by: Miroslav Rezanina + +From: Suraj Jitindar Singh + +In default_caps_with_cpu() we set spapr_cap_cfpc to broken for POWER8 +processors and before. + +Since we no longer require private l1d cache on POWER8 for this cap to +be set to workaround change this to default to broken for POWER7 +processors and before. + +Signed-off-by: Suraj Jitindar Singh +Reviewed-by: David Gibson +Signed-off-by: David Gibson +(cherry picked from commit b2540203bdf4a390c3489146eae82ce237303653) + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1560847 + +Signed-off-by: Suraj Jitindar Singh +Signed-off-by: Miroslav Rezanina +--- + hw/ppc/spapr_caps.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c +index 531e145..00e43a9 100644 +--- a/hw/ppc/spapr_caps.c ++++ b/hw/ppc/spapr_caps.c +@@ -335,14 +335,10 @@ static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr, + + caps = smc->default_caps; + +- if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00, +- 0, spapr->max_compat_pvr)) { +- caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN; +- } +- + if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07, + 0, spapr->max_compat_pvr)) { + caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF; ++ caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN; + } + + if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06_PLUS, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pr-helper-Rework-socket-path-handling.patch b/SOURCES/kvm-pr-helper-Rework-socket-path-handling.patch new file mode 100644 index 0000000..0245a99 --- /dev/null +++ b/SOURCES/kvm-pr-helper-Rework-socket-path-handling.patch @@ -0,0 +1,141 @@ +From 5b8df1e97b5b90c9d41fd10796217bfe06951856 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Fri, 6 Jul 2018 17:56:58 +0200 +Subject: [PATCH 24/89] pr-helper: Rework socket path handling + +RH-Author: Paolo Bonzini +Message-id: <20180706175659.30615-9-pbonzini@redhat.com> +Patchwork-id: 81252 +O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH 8/9] pr-helper: Rework socket path handling +Bugzilla: 1533158 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Michal Privoznik + +From: Michal Privoznik + +When reviewing Paolo's pr-helper patches I've noticed couple of +problems: + +1) socket_path needs to be calculated at two different places +(one for printing out help, the other if socket activation is NOT +used), + +2) even though the default socket_path is allocated in +compute_default_paths() it is the only default path the function +handles. For instance, pidfile is allocated outside of this +function. And yet again, at different places than 1) + +Signed-off-by: Michal Privoznik +Message-Id: +Signed-off-by: Paolo Bonzini +(cherry picked from commit 2729d79d4993099782002c9a218de1fc12c32c69) +Signed-off-by: Miroslav Rezanina +--- + scsi/qemu-pr-helper.c | 36 ++++++++++-------------------------- + 1 file changed, 10 insertions(+), 26 deletions(-) + +diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c +index 4d843bd..bae3e55 100644 +--- a/scsi/qemu-pr-helper.c ++++ b/scsi/qemu-pr-helper.c +@@ -76,14 +76,12 @@ static int gid = -1; + + static void compute_default_paths(void) + { +- if (!socket_path) { +- socket_path = qemu_get_local_state_pathname("run/qemu-pr-helper.sock"); +- } ++ socket_path = qemu_get_local_state_pathname("run/qemu-pr-helper.sock"); ++ pidfile = qemu_get_local_state_pathname("run/qemu-pr-helper.pid"); + } + + static void usage(const char *name) + { +- compute_default_paths(); + (printf) ( + "Usage: %s [OPTIONS] FILE\n" + "Persistent Reservation helper program for QEMU\n" +@@ -830,19 +828,6 @@ static gboolean accept_client(QIOChannel *ioc, GIOCondition cond, gpointer opaqu + return TRUE; + } + +- +-/* +- * Check socket parameters compatibility when socket activation is used. +- */ +-static const char *socket_activation_validate_opts(void) +-{ +- if (socket_path != NULL) { +- return "Unix socket can't be set when using socket activation"; +- } +- +- return NULL; +-} +- + static void termsig_handler(int signum) + { + atomic_cmpxchg(&state, RUNNING, TERMINATE); +@@ -916,6 +901,7 @@ int main(int argc, char **argv) + char *trace_file = NULL; + bool daemonize = false; + bool pidfile_specified = false; ++ bool socket_path_specified = false; + unsigned socket_activation; + + struct sigaction sa_sigterm; +@@ -932,12 +918,14 @@ int main(int argc, char **argv) + qemu_add_opts(&qemu_trace_opts); + qemu_init_exec_dir(argv[0]); + +- pidfile = qemu_get_local_state_pathname("run/qemu-pr-helper.pid"); ++ compute_default_paths(); + + while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) { + switch (ch) { + case 'k': +- socket_path = optarg; ++ g_free(socket_path); ++ socket_path = g_strdup(optarg); ++ socket_path_specified = true; + if (socket_path[0] != '/') { + error_report("socket path must be absolute"); + exit(EXIT_FAILURE); +@@ -1028,10 +1016,9 @@ int main(int argc, char **argv) + socket_activation = check_socket_activation(); + if (socket_activation == 0) { + SocketAddress saddr; +- compute_default_paths(); + saddr = (SocketAddress){ + .type = SOCKET_ADDRESS_TYPE_UNIX, +- .u.q_unix.path = g_strdup(socket_path) ++ .u.q_unix.path = socket_path, + }; + server_ioc = qio_channel_socket_new(); + if (qio_channel_socket_listen_sync(server_ioc, &saddr, &local_err) < 0) { +@@ -1039,12 +1026,10 @@ int main(int argc, char **argv) + error_report_err(local_err); + return 1; + } +- g_free(saddr.u.q_unix.path); + } else { + /* Using socket activation - check user didn't use -p etc. */ +- const char *err_msg = socket_activation_validate_opts(); +- if (err_msg != NULL) { +- error_report("%s", err_msg); ++ if (socket_path_specified) { ++ error_report("Unix socket can't be set when using socket activation"); + exit(EXIT_FAILURE); + } + +@@ -1061,7 +1046,6 @@ int main(int argc, char **argv) + error_get_pretty(local_err)); + exit(EXIT_FAILURE); + } +- socket_path = NULL; + } + + if (qemu_init_main_loop(&local_err)) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pr-helper-avoid-error-on-PR-IN-command-with-zero-req.patch b/SOURCES/kvm-pr-helper-avoid-error-on-PR-IN-command-with-zero-req.patch new file mode 100644 index 0000000..261f115 --- /dev/null +++ b/SOURCES/kvm-pr-helper-avoid-error-on-PR-IN-command-with-zero-req.patch @@ -0,0 +1,139 @@ +From 502aa0cb17507c7af0cca61aeb5ff17b65c7afc7 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Fri, 6 Jul 2018 17:56:57 +0200 +Subject: [PATCH 23/89] pr-helper: avoid error on PR IN command with zero + request size + +RH-Author: Paolo Bonzini +Message-id: <20180706175659.30615-8-pbonzini@redhat.com> +Patchwork-id: 81250 +O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH 7/9] pr-helper: avoid error on PR IN command with zero request size +Bugzilla: 1533158 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Michal Privoznik + +After reading a PR IN command with zero request size in prh_read_request, +the resp->result field will be uninitialized and the resp.sz field will +be also uninitialized when returning to prh_co_entry. + +If resp->result == GOOD (from a previous successful reply or just luck), +then the assert in prh_write_response might not be triggered and +uninitialized response will be sent. + +The fix is to remove the whole handling of sz == 0 in prh_co_entry. +Those errors apply only to PR OUT commands and it's perfectly okay to +catch them later in do_pr_out and multipath_pr_out; the check for +too-short parameters in fact doesn't apply in the easy SG_IO case, as +it can be left to the target firmware even. + +The result is that prh_read_request does not fail requests anymore and +prh_co_entry becomes simpler. + +Reported-by: Dima Stepanov +Signed-off-by: Paolo Bonzini +(cherry picked from commit ee8c13b81474e002db083e9692b11c0e106a9c7f) +Signed-off-by: Miroslav Rezanina +--- + scsi/qemu-pr-helper.c | 63 ++++++++++++++++++++++++--------------------------- + 1 file changed, 30 insertions(+), 33 deletions(-) + +diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c +index 3961023..4d843bd 100644 +--- a/scsi/qemu-pr-helper.c ++++ b/scsi/qemu-pr-helper.c +@@ -444,6 +444,14 @@ static int multipath_pr_out(int fd, const uint8_t *cdb, uint8_t *sense, + char transportids[PR_HELPER_DATA_SIZE]; + int r; + ++ if (sz < PR_OUT_FIXED_PARAM_SIZE) { ++ /* Illegal request, Parameter list length error. This isn't fatal; ++ * we have read the data, send an error without closing the socket. ++ */ ++ scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM_LEN)); ++ return CHECK_CONDITION; ++ } ++ + switch (rq_servact) { + case MPATH_PROUT_REG_SA: + case MPATH_PROUT_RES_SA: +@@ -563,6 +571,12 @@ static int do_pr_out(int fd, const uint8_t *cdb, uint8_t *sense, + const uint8_t *param, int sz) + { + int resp_sz; ++ ++ if ((fcntl(fd, F_GETFL) & O_ACCMODE) == O_RDONLY) { ++ scsi_build_sense(sense, SENSE_CODE(INVALID_OPCODE)); ++ return CHECK_CONDITION; ++ } ++ + #ifdef CONFIG_MPATH + if (is_mpath(fd)) { + return multipath_pr_out(fd, cdb, sense, param, sz); +@@ -679,21 +693,6 @@ static int coroutine_fn prh_read_request(PRHelperClient *client, + errp) < 0) { + goto out_close; + } +- if ((fcntl(client->fd, F_GETFL) & O_ACCMODE) == O_RDONLY) { +- scsi_build_sense(resp->sense, SENSE_CODE(INVALID_OPCODE)); +- sz = 0; +- } else if (sz < PR_OUT_FIXED_PARAM_SIZE) { +- /* Illegal request, Parameter list length error. This isn't fatal; +- * we have read the data, send an error without closing the socket. +- */ +- scsi_build_sense(resp->sense, SENSE_CODE(INVALID_PARAM_LEN)); +- sz = 0; +- } +- if (sz == 0) { +- resp->result = CHECK_CONDITION; +- close(client->fd); +- client->fd = -1; +- } + } + + req->fd = client->fd; +@@ -774,25 +773,23 @@ static void coroutine_fn prh_co_entry(void *opaque) + break; + } + +- if (sz > 0) { +- num_active_sockets++; +- if (req.cdb[0] == PERSISTENT_RESERVE_OUT) { +- r = do_pr_out(req.fd, req.cdb, resp.sense, +- client->data, sz); +- resp.sz = 0; +- } else { +- resp.sz = sizeof(client->data); +- r = do_pr_in(req.fd, req.cdb, resp.sense, +- client->data, &resp.sz); +- resp.sz = MIN(resp.sz, sz); +- } +- num_active_sockets--; +- close(req.fd); +- if (r == -1) { +- break; +- } +- resp.result = r; ++ num_active_sockets++; ++ if (req.cdb[0] == PERSISTENT_RESERVE_OUT) { ++ r = do_pr_out(req.fd, req.cdb, resp.sense, ++ client->data, sz); ++ resp.sz = 0; ++ } else { ++ resp.sz = sizeof(client->data); ++ r = do_pr_in(req.fd, req.cdb, resp.sense, ++ client->data, &resp.sz); ++ resp.sz = MIN(resp.sz, sz); ++ } ++ num_active_sockets--; ++ close(req.fd); ++ if (r == -1) { ++ break; + } ++ resp.result = r; + + if (prh_write_response(client, &req, &resp, &local_err) < 0) { + break; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pr-helper-fix-assertion-failure-on-failed-multipath-.patch b/SOURCES/kvm-pr-helper-fix-assertion-failure-on-failed-multipath-.patch new file mode 100644 index 0000000..c0888ab --- /dev/null +++ b/SOURCES/kvm-pr-helper-fix-assertion-failure-on-failed-multipath-.patch @@ -0,0 +1,69 @@ +From ffe4cdcc9b82668410476d565961821515dde5b1 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Fri, 6 Jul 2018 17:56:52 +0200 +Subject: [PATCH 18/89] pr-helper: fix assertion failure on failed multipath + PERSISTENT RESERVE IN +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Paolo Bonzini +Message-id: <20180706175659.30615-3-pbonzini@redhat.com> +Patchwork-id: 81246 +O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH 2/9] pr-helper: fix assertion failure on failed multipath PERSISTENT RESERVE IN +Bugzilla: 1533158 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Michal Privoznik + +The response size is expected to be zero if the SCSI status is not +"GOOD", but nothing was resetting it. + +This can be reproduced simply by "sg_persist -s /dev/sdb" where /dev/sdb +in the guest is a scsi-block device corresponding to a multipath device +on the host. + +Before: + + PR in (Read full status): Aborted command + +and on the host: + + prh_write_response: Assertion `resp->sz == 0' failed. + +After: + + PR in (Read full status): bad field in cdb or parameter list + (perhaps unsupported service action) + +Reported-by: Jiri Belka +Reviewed-by: Michal Privoznik +Signed-off-by: Paolo Bonzini +Reviewed-by: Paolo Bonzini +Reviewed-by: Philippe Mathieu-Daudé +(cherry picked from commit 86933b4e7879e427e03365bf352c0964640cb37b) +Signed-off-by: Miroslav Rezanina +--- + scsi/qemu-pr-helper.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c +index 19887f5..3961023 100644 +--- a/scsi/qemu-pr-helper.c ++++ b/scsi/qemu-pr-helper.c +@@ -547,7 +547,11 @@ static int do_pr_in(int fd, const uint8_t *cdb, uint8_t *sense, + #ifdef CONFIG_MPATH + if (is_mpath(fd)) { + /* multipath_pr_in fills the whole input buffer. */ +- return multipath_pr_in(fd, cdb, sense, data, *resp_sz); ++ int r = multipath_pr_in(fd, cdb, sense, data, *resp_sz); ++ if (r != GOOD) { ++ *resp_sz = 0; ++ } ++ return r; + } + #endif + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pr-helper-fix-socket-path-default-in-help.patch b/SOURCES/kvm-pr-helper-fix-socket-path-default-in-help.patch new file mode 100644 index 0000000..dca2948 --- /dev/null +++ b/SOURCES/kvm-pr-helper-fix-socket-path-default-in-help.patch @@ -0,0 +1,66 @@ +From ba4e622bc5d07daba8a63589124c944d6105e054 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Fri, 6 Jul 2018 17:56:51 +0200 +Subject: [PATCH 17/89] pr-helper: fix --socket-path default in help +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Paolo Bonzini +Message-id: <20180706175659.30615-2-pbonzini@redhat.com> +Patchwork-id: 81244 +O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH 1/9] pr-helper: fix --socket-path default in help +Bugzilla: 1533158 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Michal Privoznik + +Currently --help shows "(default '(null)')" for the -k/--socket-path +option. Fix it by getting the default path in /var/run. + +Signed-off-by: Paolo Bonzini +Reviewed-by: Philippe Mathieu-Daudé +(cherry picked from commit 50fa332516d5e42695811f43396b749185e21b9c) +Signed-off-by: Miroslav Rezanina +--- + scsi/qemu-pr-helper.c | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c +index 7a29e64..19887f5 100644 +--- a/scsi/qemu-pr-helper.c ++++ b/scsi/qemu-pr-helper.c +@@ -74,8 +74,16 @@ static int uid = -1; + static int gid = -1; + #endif + ++static void compute_default_paths(void) ++{ ++ if (!socket_path) { ++ socket_path = qemu_get_local_state_pathname("run/qemu-pr-helper.sock"); ++ } ++} ++ + static void usage(const char *name) + { ++ compute_default_paths(); + (printf) ( + "Usage: %s [OPTIONS] FILE\n" + "Persistent Reservation helper program for QEMU\n" +@@ -834,13 +842,6 @@ static const char *socket_activation_validate_opts(void) + return NULL; + } + +-static void compute_default_paths(void) +-{ +- if (!socket_path) { +- socket_path = qemu_get_local_state_pathname("run/qemu-pr-helper.sock"); +- } +-} +- + static void termsig_handler(int signum) + { + atomic_cmpxchg(&state, RUNNING, TERMINATE); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pr-manager-add-query-pr-managers-QMP-command.patch b/SOURCES/kvm-pr-manager-add-query-pr-managers-QMP-command.patch new file mode 100644 index 0000000..3f06e19 --- /dev/null +++ b/SOURCES/kvm-pr-manager-add-query-pr-managers-QMP-command.patch @@ -0,0 +1,201 @@ +From 91fa5e18d2ac6e376901a71f3f44343761fde012 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Fri, 6 Jul 2018 17:56:55 +0200 +Subject: [PATCH 21/89] pr-manager: add query-pr-managers QMP command + +RH-Author: Paolo Bonzini +Message-id: <20180706175659.30615-6-pbonzini@redhat.com> +Patchwork-id: 81251 +O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH 5/9] pr-manager: add query-pr-managers QMP command +Bugzilla: 1533158 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Michal Privoznik + +This command lets you query the connection status of each pr-manager-helper +object. + +Signed-off-by: Paolo Bonzini +(cherry picked from commit 5f64089416f0d77c87683401838f064c51a292ed) + +[RHEL: no allow-preconfig yet, so don't specify it] + +Signed-off-by: Miroslav Rezanina +--- + include/scsi/pr-manager.h | 2 ++ + qapi/block.json | 27 +++++++++++++++++++++++++++ + scsi/pr-manager-helper.c | 13 +++++++++++++ + scsi/pr-manager-stub.c | 6 ++++++ + scsi/pr-manager.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ + 5 files changed, 93 insertions(+) + +diff --git a/include/scsi/pr-manager.h b/include/scsi/pr-manager.h +index 71971ae..50a77b0 100644 +--- a/include/scsi/pr-manager.h ++++ b/include/scsi/pr-manager.h +@@ -33,8 +33,10 @@ typedef struct PRManagerClass { + + /* */ + int (*run)(PRManager *pr_mgr, int fd, struct sg_io_hdr *hdr); ++ bool (*is_connected)(PRManager *pr_mgr); + } PRManagerClass; + ++bool pr_manager_is_connected(PRManager *pr_mgr); + BlockAIOCB *pr_manager_execute(PRManager *pr_mgr, + AioContext *ctx, int fd, + struct sg_io_hdr *hdr, +diff --git a/qapi/block.json b/qapi/block.json +index 48c732f..c636354 100644 +--- a/qapi/block.json ++++ b/qapi/block.json +@@ -78,6 +78,33 @@ + 'data': { 'device': 'str', 'name': 'str' } } + + ## ++# @PRManagerInfo: ++# ++# Information about a persistent reservation manager ++# ++# @id: the identifier of the persistent reservation manager ++# ++# @connected: true if the persistent reservation manager is connected to ++# the underlying storage or helper ++# ++# Since: 3.0 ++## ++{ 'struct': 'PRManagerInfo', ++ 'data': {'id': 'str', 'connected': 'bool'} } ++ ++## ++# @query-pr-managers: ++# ++# Returns a list of information about each persistent reservation manager. ++# ++# Returns: a list of @PRManagerInfo for each persistent reservation manager ++# ++# Since: 3.0 ++## ++{ 'command': 'query-pr-managers', 'returns': ['PRManagerInfo'] } ++ ++ ++## + # @blockdev-snapshot-internal-sync: + # + # Synchronously take an internal snapshot of a block device, when the +diff --git a/scsi/pr-manager-helper.c b/scsi/pr-manager-helper.c +index 0c0fe38..b11481b 100644 +--- a/scsi/pr-manager-helper.c ++++ b/scsi/pr-manager-helper.c +@@ -235,6 +235,18 @@ out: + return ret; + } + ++static bool pr_manager_helper_is_connected(PRManager *p) ++{ ++ PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(p); ++ bool result; ++ ++ qemu_mutex_lock(&pr_mgr->lock); ++ result = (pr_mgr->ioc != NULL); ++ qemu_mutex_unlock(&pr_mgr->lock); ++ ++ return result; ++} ++ + static void pr_manager_helper_complete(UserCreatable *uc, Error **errp) + { + PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(uc); +@@ -284,6 +296,7 @@ static void pr_manager_helper_class_init(ObjectClass *klass, + &error_abort); + uc_klass->complete = pr_manager_helper_complete; + prmgr_klass->run = pr_manager_helper_run; ++ prmgr_klass->is_connected = pr_manager_helper_is_connected; + } + + static const TypeInfo pr_manager_helper_info = { +diff --git a/scsi/pr-manager-stub.c b/scsi/pr-manager-stub.c +index 632f17c..738b6d7 100644 +--- a/scsi/pr-manager-stub.c ++++ b/scsi/pr-manager-stub.c +@@ -22,3 +22,9 @@ PRManager *pr_manager_lookup(const char *id, Error **errp) + error_setg(errp, "No persistent reservation manager with id '%s'", id); + return NULL; + } ++ ++ ++PRManagerInfoList *qmp_query_pr_managers(Error **errp) ++{ ++ return NULL; ++} +diff --git a/scsi/pr-manager.c b/scsi/pr-manager.c +index 87c45db..2a8f300 100644 +--- a/scsi/pr-manager.c ++++ b/scsi/pr-manager.c +@@ -17,6 +17,10 @@ + #include "block/thread-pool.h" + #include "scsi/pr-manager.h" + #include "trace.h" ++#include "qapi/qapi-types-block.h" ++#include "qapi/qapi-commands-block.h" ++ ++#define PR_MANAGER_PATH "/objects" + + typedef struct PRManagerData { + PRManager *pr_mgr; +@@ -64,6 +68,14 @@ BlockAIOCB *pr_manager_execute(PRManager *pr_mgr, + data, complete, opaque); + } + ++bool pr_manager_is_connected(PRManager *pr_mgr) ++{ ++ PRManagerClass *pr_mgr_class = ++ PR_MANAGER_GET_CLASS(pr_mgr); ++ ++ return !pr_mgr_class->is_connected || pr_mgr_class->is_connected(pr_mgr); ++} ++ + static const TypeInfo pr_manager_info = { + .parent = TYPE_OBJECT, + .name = TYPE_PR_MANAGER, +@@ -105,5 +117,38 @@ pr_manager_register_types(void) + type_register_static(&pr_manager_info); + } + ++static int query_one_pr_manager(Object *object, void *opaque) ++{ ++ PRManagerInfoList ***prev = opaque; ++ PRManagerInfoList *elem; ++ PRManagerInfo *info; ++ PRManager *pr_mgr; ++ ++ pr_mgr = (PRManager *)object_dynamic_cast(object, TYPE_PR_MANAGER); ++ if (!pr_mgr) { ++ return 0; ++ } ++ ++ elem = g_new0(PRManagerInfoList, 1); ++ info = g_new0(PRManagerInfo, 1); ++ info->id = object_get_canonical_path_component(object); ++ info->connected = pr_manager_is_connected(pr_mgr); ++ elem->value = info; ++ elem->next = NULL; ++ ++ **prev = elem; ++ *prev = &elem->next; ++ return 0; ++} ++ ++PRManagerInfoList *qmp_query_pr_managers(Error **errp) ++{ ++ PRManagerInfoList *head = NULL; ++ PRManagerInfoList **prev = &head; ++ Object *container = container_get(object_get_root(), PR_MANAGER_PATH); ++ ++ object_child_foreach(container, query_one_pr_manager, &prev); ++ return head; ++} + + type_init(pr_manager_register_types); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pr-manager-helper-avoid-SIGSEGV-when-writing-to-the-.patch b/SOURCES/kvm-pr-manager-helper-avoid-SIGSEGV-when-writing-to-the-.patch new file mode 100644 index 0000000..d16482f --- /dev/null +++ b/SOURCES/kvm-pr-manager-helper-avoid-SIGSEGV-when-writing-to-the-.patch @@ -0,0 +1,47 @@ +From 6bd996ee8e67d32215526016b84631147d065b7b Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Fri, 6 Jul 2018 17:56:53 +0200 +Subject: [PATCH 19/89] pr-manager-helper: avoid SIGSEGV when writing to the + socket fail + +RH-Author: Paolo Bonzini +Message-id: <20180706175659.30615-4-pbonzini@redhat.com> +Patchwork-id: 81245 +O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH 3/9] pr-manager-helper: avoid SIGSEGV when writing to the socket fail +Bugzilla: 1533158 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Michal Privoznik + +When writing to the qemu-pr-helper socket failed, the persistent +reservation manager was correctly disconnecting the socket, but it +did not clear pr_mgr->ioc. So the rest of the code did not know +that the socket had been disconnected, accessed pr_mgr->ioc and +happily caused a crash. + +To reproduce, it is enough to stop qemu-pr-helper between QEMU +startup and executing e.g. sg_persist -k /dev/sdb. + +Reviewed-by: Michal Privoznik +Signed-off-by: Paolo Bonzini +(cherry picked from commit aad10040d411d21542dc9ae58a2854c89ccedd78) +Signed-off-by: Miroslav Rezanina +--- + scsi/pr-manager-helper.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/scsi/pr-manager-helper.c b/scsi/pr-manager-helper.c +index 82ff6b6..0c0fe38 100644 +--- a/scsi/pr-manager-helper.c ++++ b/scsi/pr-manager-helper.c +@@ -71,6 +71,7 @@ static int pr_manager_helper_write(PRManagerHelper *pr_mgr, + if (n_written <= 0) { + assert(n_written != QIO_CHANNEL_ERR_BLOCK); + object_unref(OBJECT(pr_mgr->ioc)); ++ pr_mgr->ioc = NULL; + return n_written < 0 ? -EINVAL : 0; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pr-manager-helper-fix-memory-leak-on-event.patch b/SOURCES/kvm-pr-manager-helper-fix-memory-leak-on-event.patch new file mode 100644 index 0000000..856ed72 --- /dev/null +++ b/SOURCES/kvm-pr-manager-helper-fix-memory-leak-on-event.patch @@ -0,0 +1,38 @@ +From 7d3c970b0033d3bdb99e901676228bdb205e96c0 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Fri, 6 Jul 2018 17:56:59 +0200 +Subject: [PATCH 25/89] pr-manager-helper: fix memory leak on event + +RH-Author: Paolo Bonzini +Message-id: <20180706175659.30615-10-pbonzini@redhat.com> +Patchwork-id: 81249 +O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH 9/9] pr-manager-helper: fix memory leak on event +Bugzilla: 1533158 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Michal Privoznik + +Reported by Coverity. + +Signed-off-by: Paolo Bonzini +(cherry picked from commit ea3d77c889cfa8c450da8a716c2bfd6aaea0adb2) +Signed-off-by: Miroslav Rezanina +--- + scsi/pr-manager-helper.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/scsi/pr-manager-helper.c b/scsi/pr-manager-helper.c +index 519a296..3027dde 100644 +--- a/scsi/pr-manager-helper.c ++++ b/scsi/pr-manager-helper.c +@@ -46,6 +46,7 @@ static void pr_manager_send_status_changed_event(PRManagerHelper *pr_mgr) + if (id) { + qapi_event_send_pr_manager_status_changed(id, !!pr_mgr->ioc, + &error_abort); ++ g_free(id); + } + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pr-manager-helper-report-event-on-connection-disconn.patch b/SOURCES/kvm-pr-manager-helper-report-event-on-connection-disconn.patch new file mode 100644 index 0000000..5cd17ad --- /dev/null +++ b/SOURCES/kvm-pr-manager-helper-report-event-on-connection-disconn.patch @@ -0,0 +1,118 @@ +From d6d700d511612f621c0b6dcbd3d7996126f3da80 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Fri, 6 Jul 2018 17:56:56 +0200 +Subject: [PATCH 22/89] pr-manager-helper: report event on + connection/disconnection + +RH-Author: Paolo Bonzini +Message-id: <20180706175659.30615-7-pbonzini@redhat.com> +Patchwork-id: 81247 +O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH 6/9] pr-manager-helper: report event on connection/disconnection +Bugzilla: 1533158 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Michal Privoznik + +Let management know if there were any problems communicating with +qemu-pr-helper. The event is edge-triggered, and is sent every time +the connection status of the pr-manager-helper object changes. + +Signed-off-by: Paolo Bonzini +(cherry picked from commit e2c81a45101fdddfd47477a1805806f2c76639bf) +Signed-off-by: Miroslav Rezanina +--- + qapi/block.json | 24 ++++++++++++++++++++++++ + scsi/pr-manager-helper.c | 14 ++++++++++++++ + 2 files changed, 38 insertions(+) + +diff --git a/qapi/block.json b/qapi/block.json +index c636354..f05b91a 100644 +--- a/qapi/block.json ++++ b/qapi/block.json +@@ -403,6 +403,30 @@ + 'data': { 'device': 'str', 'id': 'str', 'tray-open': 'bool' } } + + ## ++# @PR_MANAGER_STATUS_CHANGED: ++# ++# Emitted whenever the connected status of a persistent reservation ++# manager changes. ++# ++# @id: The id of the PR manager object ++# ++# @connected: true if the PR manager is connected to a backend ++# ++# Since: 3.0 ++# ++# Example: ++# ++# <- { "event": "PR_MANAGER_STATUS_CHANGED", ++# "data": { "id": "pr-helper0", ++# "connected": true ++# }, ++# "timestamp": { "seconds": 1519840375, "microseconds": 450486 } } ++# ++## ++{ 'event': 'PR_MANAGER_STATUS_CHANGED', ++ 'data': { 'id': 'str', 'connected': 'bool' } } ++ ++## + # @QuorumOpType: + # + # An enumeration of the quorum operation types +diff --git a/scsi/pr-manager-helper.c b/scsi/pr-manager-helper.c +index b11481b..519a296 100644 +--- a/scsi/pr-manager-helper.c ++++ b/scsi/pr-manager-helper.c +@@ -17,6 +17,7 @@ + #include "io/channel.h" + #include "io/channel-socket.h" + #include "pr-helper.h" ++#include "qapi/qapi-events-block.h" + + #include + +@@ -38,6 +39,16 @@ typedef struct PRManagerHelper { + QIOChannel *ioc; + } PRManagerHelper; + ++static void pr_manager_send_status_changed_event(PRManagerHelper *pr_mgr) ++{ ++ char *id = object_get_canonical_path_component(OBJECT(pr_mgr)); ++ ++ if (id) { ++ qapi_event_send_pr_manager_status_changed(id, !!pr_mgr->ioc, ++ &error_abort); ++ } ++} ++ + /* Called with lock held. */ + static int pr_manager_helper_read(PRManagerHelper *pr_mgr, + void *buf, int sz, Error **errp) +@@ -47,6 +58,7 @@ static int pr_manager_helper_read(PRManagerHelper *pr_mgr, + if (r < 0) { + object_unref(OBJECT(pr_mgr->ioc)); + pr_mgr->ioc = NULL; ++ pr_manager_send_status_changed_event(pr_mgr); + return -EINVAL; + } + +@@ -72,6 +84,7 @@ static int pr_manager_helper_write(PRManagerHelper *pr_mgr, + assert(n_written != QIO_CHANNEL_ERR_BLOCK); + object_unref(OBJECT(pr_mgr->ioc)); + pr_mgr->ioc = NULL; ++ pr_manager_send_status_changed_event(pr_mgr); + return n_written < 0 ? -EINVAL : 0; + } + +@@ -127,6 +140,7 @@ static int pr_manager_helper_initialize(PRManagerHelper *pr_mgr, + goto out_close; + } + ++ pr_manager_send_status_changed_event(pr_mgr); + return 0; + + out_close: +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pr-manager-put-stubs-in-.c-file.patch b/SOURCES/kvm-pr-manager-put-stubs-in-.c-file.patch new file mode 100644 index 0000000..39e5b36 --- /dev/null +++ b/SOURCES/kvm-pr-manager-put-stubs-in-.c-file.patch @@ -0,0 +1,86 @@ +From 16baef3f994e29063e8f7c48c9f03a8d07744932 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Fri, 6 Jul 2018 17:56:54 +0200 +Subject: [PATCH 20/89] pr-manager: put stubs in .c file + +RH-Author: Paolo Bonzini +Message-id: <20180706175659.30615-5-pbonzini@redhat.com> +Patchwork-id: 81253 +O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH 4/9] pr-manager: put stubs in .c file +Bugzilla: 1533158 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Michal Privoznik + +Signed-off-by: Paolo Bonzini +(cherry picked from commit 58b3017f7fba15e8c440115dfd5d380f490d0b61) +Signed-off-by: Miroslav Rezanina +--- + include/scsi/pr-manager.h | 9 --------- + scsi/Makefile.objs | 1 + + scsi/pr-manager-stub.c | 24 ++++++++++++++++++++++++ + 3 files changed, 25 insertions(+), 9 deletions(-) + create mode 100644 scsi/pr-manager-stub.c + +diff --git a/include/scsi/pr-manager.h b/include/scsi/pr-manager.h +index 5d2f13a..71971ae 100644 +--- a/include/scsi/pr-manager.h ++++ b/include/scsi/pr-manager.h +@@ -41,15 +41,6 @@ BlockAIOCB *pr_manager_execute(PRManager *pr_mgr, + BlockCompletionFunc *complete, + void *opaque); + +-#ifdef CONFIG_LINUX + PRManager *pr_manager_lookup(const char *id, Error **errp); +-#else +-static inline PRManager *pr_manager_lookup(const char *id, Error **errp) +-{ +- /* The classes do not exist at all! */ +- error_setg(errp, "No persistent reservation manager with id '%s'", id); +- return NULL; +-} +-#endif + + #endif +diff --git a/scsi/Makefile.objs b/scsi/Makefile.objs +index 4d25e47..bb8789c 100644 +--- a/scsi/Makefile.objs ++++ b/scsi/Makefile.objs +@@ -1,3 +1,4 @@ + block-obj-y += utils.o + + block-obj-$(CONFIG_LINUX) += pr-manager.o pr-manager-helper.o ++block-obj-$(call lnot,$(CONFIG_LINUX)) += pr-manager-stub.o +diff --git a/scsi/pr-manager-stub.c b/scsi/pr-manager-stub.c +new file mode 100644 +index 0000000..632f17c +--- /dev/null ++++ b/scsi/pr-manager-stub.c +@@ -0,0 +1,24 @@ ++/* ++ * Persistent reservation manager - stub for non-Linux platforms ++ * ++ * Copyright (c) 2018 Red Hat, Inc. ++ * ++ * Author: Paolo Bonzini ++ * ++ * This code is licensed under the LGPL. ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "qapi/error.h" ++#include "scsi/pr-manager.h" ++#include "trace.h" ++#include "qapi/qapi-types-block.h" ++#include "qapi/qapi-commands-block.h" ++ ++PRManager *pr_manager_lookup(const char *id, Error **errp) ++{ ++ /* The classes do not exist at all! */ ++ error_setg(errp, "No persistent reservation manager with id '%s'", id); ++ return NULL; ++} +-- +1.8.3.1 + diff --git a/SOURCES/kvm-q35-Fix-mismerge.patch b/SOURCES/kvm-q35-Fix-mismerge.patch deleted file mode 100644 index 0ab0a8f..0000000 --- a/SOURCES/kvm-q35-Fix-mismerge.patch +++ /dev/null @@ -1,43 +0,0 @@ -From b0c06140414df1c0637c3d06f67e0292c31f967d Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Wed, 15 Nov 2017 12:29:20 +0100 -Subject: [PATCH 06/30] q35: Fix mismerge - -RH-Author: Dr. David Alan Gilbert -Message-id: <20171115122920.7207-3-dgilbert@redhat.com> -Patchwork-id: 77677 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 2/2] q35: Fix mismerge -Bugzilla: 1511312 -RH-Acked-by: Marcel Apfelbaum -RH-Acked-by: Laurent Vivier -RH-Acked-by: Laszlo Ersek - -From: "Dr. David Alan Gilbert" - -There's a mismerged line calling SET_MACHINE_COMPAT for the -RHEL macro in the base pc_q35_machine_option that's ifdef'd -out, it's correctly called later in pc_q35_machine_rhel7_options. - -Clean it up (should be no effect). - -Signed-off-by: Dr. David Alan Gilbert -Signed-off-by: Miroslav Rezanina ---- - hw/i386/pc_q35.c | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c -index 27c85c5..0818a96 100644 ---- a/hw/i386/pc_q35.c -+++ b/hw/i386/pc_q35.c -@@ -301,7 +301,6 @@ static void pc_q35_machine_options(MachineClass *m) - m->no_floppy = 1; - m->has_dynamic_sysbus = true; - m->max_cpus = 288; -- SET_MACHINE_COMPAT(m, PC_RHEL_COMPAT); - } - - static void pc_q35_2_10_machine_options(MachineClass *m) --- -1.8.3.1 - diff --git a/SOURCES/kvm-qapi-add-disabled-parameter-to-block-dirty-bitmap-ad.patch b/SOURCES/kvm-qapi-add-disabled-parameter-to-block-dirty-bitmap-ad.patch new file mode 100644 index 0000000..766d30d --- /dev/null +++ b/SOURCES/kvm-qapi-add-disabled-parameter-to-block-dirty-bitmap-ad.patch @@ -0,0 +1,100 @@ +From ecbd9793ceb09c1dbbe2e37fd132aa428eb2b4fb Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 18 Jul 2018 22:54:41 +0200 +Subject: [PATCH 56/89] qapi: add disabled parameter to block-dirty-bitmap-add + +RH-Author: John Snow +Message-id: <20180718225511.14878-6-jsnow@redhat.com> +Patchwork-id: 81404 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 05/35] qapi: add disabled parameter to block-dirty-bitmap-add +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Vladimir Sementsov-Ogievskiy + +This is needed, for example, to create a new bitmap and merge several +disabled bitmaps into a new one. Without this flag we will have to +put block-dirty-bitmap-add and block-dirty-bitmap-disable into one +transaction. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: John Snow +Reviewed-by: Jeff Cody +Message-id: 20180606182449.1607-6-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit a6e2ca5f6521553681ae136578ec1cb67e1a7973) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + blockdev.c | 10 ++++++++++ + qapi/block-core.json | 6 +++++- + 2 files changed, 15 insertions(+), 1 deletion(-) + +diff --git a/blockdev.c b/blockdev.c +index 3728082..9beef10 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -2115,6 +2115,7 @@ static void block_dirty_bitmap_add_prepare(BlkActionState *common, + action->has_granularity, action->granularity, + action->has_persistent, action->persistent, + action->has_autoload, action->autoload, ++ action->has_x_disabled, action->x_disabled, + &local_err); + + if (!local_err) { +@@ -2922,6 +2923,7 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name, + bool has_granularity, uint32_t granularity, + bool has_persistent, bool persistent, + bool has_autoload, bool autoload, ++ bool has_disabled, bool disabled, + Error **errp) + { + BlockDriverState *bs; +@@ -2956,6 +2958,10 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name, + warn_report("Autoload option is deprecated and its value is ignored"); + } + ++ if (!has_disabled) { ++ disabled = false; ++ } ++ + if (persistent && + !bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp)) + { +@@ -2967,6 +2973,10 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name, + return; + } + ++ if (disabled) { ++ bdrv_disable_dirty_bitmap(bitmap); ++ } ++ + bdrv_dirty_bitmap_set_persistance(bitmap, persistent); + } + +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 4e1fda3..27ed91b 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -1734,11 +1734,15 @@ + # Currently, all dirty tracking bitmaps are loaded from Qcow2 on + # open. + # ++# @x-disabled: the bitmap is created in the disabled state, which means that ++# it will not track drive changes. The bitmap may be enabled with ++# x-block-dirty-bitmap-enable. Default is false. (Since: 3.0) ++# + # Since: 2.4 + ## + { 'struct': 'BlockDirtyBitmapAdd', + 'data': { 'node': 'str', 'name': 'str', '*granularity': 'uint32', +- '*persistent': 'bool', '*autoload': 'bool' } } ++ '*persistent': 'bool', '*autoload': 'bool', '*x-disabled': 'bool' } } + + ## + # @BlockDirtyBitmapMerge: +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qapi-add-x-block-dirty-bitmap-enable-disable.patch b/SOURCES/kvm-qapi-add-x-block-dirty-bitmap-enable-disable.patch new file mode 100644 index 0000000..c4674e8 --- /dev/null +++ b/SOURCES/kvm-qapi-add-x-block-dirty-bitmap-enable-disable.patch @@ -0,0 +1,142 @@ +From 65fa69814f994a95b1574dd16ea81aef4774fec5 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 18 Jul 2018 22:54:38 +0200 +Subject: [PATCH 53/89] qapi: add x-block-dirty-bitmap-enable/disable + +RH-Author: John Snow +Message-id: <20180718225511.14878-3-jsnow@redhat.com> +Patchwork-id: 81406 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 02/35] qapi: add x-block-dirty-bitmap-enable/disable +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Vladimir Sementsov-Ogievskiy + +Expose the ability to turn bitmaps "on" or "off". This is experimental +and principally for the sake of the Libvirt Checkpoints API, and it may +or may not be committed for 3.0. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: John Snow +Reviewed-by: Jeff Cody +Message-id: 20180606182449.1607-3-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit 5c5d2e50e5ac85234d793f0127a20ea3424a1229) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + blockdev.c | 42 ++++++++++++++++++++++++++++++++++++++++++ + qapi/block-core.json | 42 ++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 84 insertions(+) + +diff --git a/blockdev.c b/blockdev.c +index d8b6520..ca2ffff 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -2965,6 +2965,48 @@ void qmp_block_dirty_bitmap_clear(const char *node, const char *name, + bdrv_clear_dirty_bitmap(bitmap, NULL); + } + ++void qmp_x_block_dirty_bitmap_enable(const char *node, const char *name, ++ Error **errp) ++{ ++ BlockDriverState *bs; ++ BdrvDirtyBitmap *bitmap; ++ ++ bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp); ++ if (!bitmap) { ++ return; ++ } ++ ++ if (bdrv_dirty_bitmap_frozen(bitmap)) { ++ error_setg(errp, ++ "Bitmap '%s' is currently frozen and cannot be enabled", ++ name); ++ return; ++ } ++ ++ bdrv_enable_dirty_bitmap(bitmap); ++} ++ ++void qmp_x_block_dirty_bitmap_disable(const char *node, const char *name, ++ Error **errp) ++{ ++ BlockDriverState *bs; ++ BdrvDirtyBitmap *bitmap; ++ ++ bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp); ++ if (!bitmap) { ++ return; ++ } ++ ++ if (bdrv_dirty_bitmap_frozen(bitmap)) { ++ error_setg(errp, ++ "Bitmap '%s' is currently frozen and cannot be disabled", ++ name); ++ return; ++ } ++ ++ bdrv_disable_dirty_bitmap(bitmap); ++} ++ + BlockDirtyBitmapSha256 *qmp_x_debug_block_dirty_bitmap_sha256(const char *node, + const char *name, + Error **errp) +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 0b07e41..5c8cfa3 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -1809,6 +1809,48 @@ + 'data': 'BlockDirtyBitmap' } + + ## ++# @x-block-dirty-bitmap-enable: ++# ++# Enables a dirty bitmap so that it will begin tracking disk changes. ++# ++# Returns: nothing on success ++# If @node is not a valid block device, DeviceNotFound ++# If @name is not found, GenericError with an explanation ++# ++# Since: 3.0 ++# ++# Example: ++# ++# -> { "execute": "x-block-dirty-bitmap-enable", ++# "arguments": { "node": "drive0", "name": "bitmap0" } } ++# <- { "return": {} } ++# ++## ++ { 'command': 'x-block-dirty-bitmap-enable', ++ 'data': 'BlockDirtyBitmap' } ++ ++## ++# @x-block-dirty-bitmap-disable: ++# ++# Disables a dirty bitmap so that it will stop tracking disk changes. ++# ++# Returns: nothing on success ++# If @node is not a valid block device, DeviceNotFound ++# If @name is not found, GenericError with an explanation ++# ++# Since: 3.0 ++# ++# Example: ++# ++# -> { "execute": "x-block-dirty-bitmap-disable", ++# "arguments": { "node": "drive0", "name": "bitmap0" } } ++# <- { "return": {} } ++# ++## ++ { 'command': 'x-block-dirty-bitmap-disable', ++ 'data': 'BlockDirtyBitmap' } ++ ++## + # @BlockDirtyBitmapSha256: + # + # SHA256 hash of dirty bitmap data +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qapi-add-x-block-dirty-bitmap-merge.patch b/SOURCES/kvm-qapi-add-x-block-dirty-bitmap-merge.patch new file mode 100644 index 0000000..36c3b20 --- /dev/null +++ b/SOURCES/kvm-qapi-add-x-block-dirty-bitmap-merge.patch @@ -0,0 +1,171 @@ +From 56f208617b142524b79ddd060db62c045561c418 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 18 Jul 2018 22:54:40 +0200 +Subject: [PATCH 55/89] qapi: add x-block-dirty-bitmap-merge + +RH-Author: John Snow +Message-id: <20180718225511.14878-5-jsnow@redhat.com> +Patchwork-id: 81397 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 04/35] qapi: add x-block-dirty-bitmap-merge +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Vladimir Sementsov-Ogievskiy + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: John Snow +Reviewed-by: Jeff Cody +Message-id: 20180606182449.1607-5-jsnow@redhat.com +Signed-off-by: John Snow +(cherry picked from commit b598e531f1123d2fb72615f1161c66093be751ea) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/dirty-bitmap.c | 18 ++++++++++++++++++ + blockdev.c | 30 ++++++++++++++++++++++++++++++ + include/block/dirty-bitmap.h | 3 ++- + qapi/block-core.json | 38 ++++++++++++++++++++++++++++++++++++++ + 4 files changed, 88 insertions(+), 1 deletion(-) + +diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c +index 5623425..4159d39 100644 +--- a/block/dirty-bitmap.c ++++ b/block/dirty-bitmap.c +@@ -757,3 +757,21 @@ int64_t bdrv_dirty_bitmap_next_zero(BdrvDirtyBitmap *bitmap, uint64_t offset) + { + return hbitmap_next_zero(bitmap->bitmap, offset); + } ++ ++void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src, ++ Error **errp) ++{ ++ /* only bitmaps from one bds are supported */ ++ assert(dest->mutex == src->mutex); ++ ++ qemu_mutex_lock(dest->mutex); ++ ++ assert(bdrv_dirty_bitmap_enabled(dest)); ++ assert(!bdrv_dirty_bitmap_readonly(dest)); ++ ++ if (!hbitmap_merge(dest->bitmap, src->bitmap)) { ++ error_setg(errp, "Bitmaps are incompatible and can't be merged"); ++ } ++ ++ qemu_mutex_unlock(dest->mutex); ++} +diff --git a/blockdev.c b/blockdev.c +index a88d792..3728082 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -3086,6 +3086,36 @@ void qmp_x_block_dirty_bitmap_disable(const char *node, const char *name, + bdrv_disable_dirty_bitmap(bitmap); + } + ++void qmp_x_block_dirty_bitmap_merge(const char *node, const char *dst_name, ++ const char *src_name, Error **errp) ++{ ++ BlockDriverState *bs; ++ BdrvDirtyBitmap *dst, *src; ++ ++ dst = block_dirty_bitmap_lookup(node, dst_name, &bs, errp); ++ if (!dst) { ++ return; ++ } ++ ++ if (bdrv_dirty_bitmap_frozen(dst)) { ++ error_setg(errp, "Bitmap '%s' is frozen and cannot be modified", ++ dst_name); ++ return; ++ } else if (bdrv_dirty_bitmap_readonly(dst)) { ++ error_setg(errp, "Bitmap '%s' is readonly and cannot be modified", ++ dst_name); ++ return; ++ } ++ ++ src = bdrv_find_dirty_bitmap(bs, src_name); ++ if (!src) { ++ error_setg(errp, "Dirty bitmap '%s' not found", src_name); ++ return; ++ } ++ ++ bdrv_merge_dirty_bitmap(dst, src, errp); ++} ++ + BlockDirtyBitmapSha256 *qmp_x_debug_block_dirty_bitmap_sha256(const char *node, + const char *name, + Error **errp) +diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h +index 1ff8949..1e14743 100644 +--- a/include/block/dirty-bitmap.h ++++ b/include/block/dirty-bitmap.h +@@ -70,7 +70,8 @@ void bdrv_dirty_bitmap_set_readonly(BdrvDirtyBitmap *bitmap, bool value); + void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap, + bool persistent); + void bdrv_dirty_bitmap_set_qmp_locked(BdrvDirtyBitmap *bitmap, bool qmp_locked); +- ++void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src, ++ Error **errp); + + /* Functions that require manual locking. */ + void bdrv_dirty_bitmap_lock(BdrvDirtyBitmap *bitmap); +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 5c8cfa3..4e1fda3 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -1741,6 +1741,20 @@ + '*persistent': 'bool', '*autoload': 'bool' } } + + ## ++# @BlockDirtyBitmapMerge: ++# ++# @node: name of device/node which the bitmap is tracking ++# ++# @dst_name: name of the destination dirty bitmap ++# ++# @src_name: name of the source dirty bitmap ++# ++# Since: 3.0 ++## ++{ 'struct': 'BlockDirtyBitmapMerge', ++ 'data': { 'node': 'str', 'dst_name': 'str', 'src_name': 'str' } } ++ ++## + # @block-dirty-bitmap-add: + # + # Create a dirty bitmap with a name on the node, and start tracking the writes. +@@ -1851,6 +1865,30 @@ + 'data': 'BlockDirtyBitmap' } + + ## ++# @x-block-dirty-bitmap-merge: ++# ++# Merge @src_name dirty bitmap to @dst_name dirty bitmap. @src_name dirty ++# bitmap is unchanged. On error, @dst_name is unchanged. ++# ++# Returns: nothing on success ++# If @node is not a valid block device, DeviceNotFound ++# If @dst_name or @src_name is not found, GenericError ++# If bitmaps has different sizes or granularities, GenericError ++# ++# Since: 3.0 ++# ++# Example: ++# ++# -> { "execute": "x-block-dirty-bitmap-merge", ++# "arguments": { "node": "drive0", "dst_name": "bitmap0", ++# "src_name": "bitmap1" } } ++# <- { "return": {} } ++# ++## ++ { 'command': 'x-block-dirty-bitmap-merge', ++ 'data': 'BlockDirtyBitmapMerge' } ++ ++## + # @BlockDirtyBitmapSha256: + # + # SHA256 hash of dirty bitmap data +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qapi-block-commit-expose-new-job-properties.patch b/SOURCES/kvm-qapi-block-commit-expose-new-job-properties.patch new file mode 100644 index 0000000..2c7aa78 --- /dev/null +++ b/SOURCES/kvm-qapi-block-commit-expose-new-job-properties.patch @@ -0,0 +1,90 @@ +From 64f2d8be8a97b47baa7c51cceaa29b60d6b969a5 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 10 Sep 2018 18:17:59 +0200 +Subject: [PATCH 21/25] qapi/block-commit: expose new job properties + +RH-Author: John Snow +Message-id: <20180910181803.11781-22-jsnow@redhat.com> +Patchwork-id: 82100 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 21/25] qapi/block-commit: expose new job properties +Bugzilla: 1626061 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Signed-off-by: John Snow +Reviewed-by: Max Reitz +Message-id: 20180906130225.5118-13-jsnow@redhat.com +Reviewed-by: Jeff Cody +Signed-off-by: Max Reitz +(cherry picked from commit 7c91d440488214e953f8cc76e5d5fa477dc0376f) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + blockdev.c | 8 ++++++++ + qapi/block-core.json | 16 +++++++++++++++- + 2 files changed, 23 insertions(+), 1 deletion(-) + +diff --git a/blockdev.c b/blockdev.c +index c4a1801..1d0cbb1 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -3361,6 +3361,8 @@ void qmp_block_commit(bool has_job_id, const char *job_id, const char *device, + bool has_backing_file, const char *backing_file, + bool has_speed, int64_t speed, + bool has_filter_node_name, const char *filter_node_name, ++ bool has_auto_finalize, bool auto_finalize, ++ bool has_auto_dismiss, bool auto_dismiss, + Error **errp) + { + BlockDriverState *bs; +@@ -3380,6 +3382,12 @@ void qmp_block_commit(bool has_job_id, const char *job_id, const char *device, + if (!has_filter_node_name) { + filter_node_name = NULL; + } ++ if (has_auto_finalize && !auto_finalize) { ++ job_flags |= JOB_MANUAL_FINALIZE; ++ } ++ if (has_auto_dismiss && !auto_dismiss) { ++ job_flags |= JOB_MANUAL_DISMISS; ++ } + + /* Important Note: + * libvirt relies on the DeviceNotFound error class in order to probe for +diff --git a/qapi/block-core.json b/qapi/block-core.json +index c6b42eb..af453c5 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -1481,6 +1481,19 @@ + # above @top. If this option is not given, a node name is + # autogenerated. (Since: 2.9) + # ++# @auto-finalize: When false, this job will wait in a PENDING state after it has ++# finished its work, waiting for @block-job-finalize before ++# making any block graph changes. ++# When true, this job will automatically ++# perform its abort or commit actions. ++# Defaults to true. (Since 3.1) ++# ++# @auto-dismiss: When false, this job will wait in a CONCLUDED state after it ++# has completely ceased all work, and awaits @block-job-dismiss. ++# When true, this job will automatically disappear from the query ++# list without user intervention. ++# Defaults to true. (Since 3.1) ++# + # Returns: Nothing on success + # If commit or stream is already active on this device, DeviceInUse + # If @device does not exist, DeviceNotFound +@@ -1501,7 +1514,8 @@ + { 'command': 'block-commit', + 'data': { '*job-id': 'str', 'device': 'str', '*base': 'str', '*top': 'str', + '*backing-file': 'str', '*speed': 'int', +- '*filter-node-name': 'str' } } ++ '*filter-node-name': 'str', ++ '*auto-finalize': 'bool', '*auto-dismiss': 'bool' } } + + ## + # @drive-backup: +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qapi-block-mirror-expose-new-job-properties.patch b/SOURCES/kvm-qapi-block-mirror-expose-new-job-properties.patch new file mode 100644 index 0000000..20068a7 --- /dev/null +++ b/SOURCES/kvm-qapi-block-mirror-expose-new-job-properties.patch @@ -0,0 +1,150 @@ +From 4fd9e923e840ff8a9618e018192bad6ed000cc40 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 10 Sep 2018 18:18:00 +0200 +Subject: [PATCH 22/25] qapi/block-mirror: expose new job properties + +RH-Author: John Snow +Message-id: <20180910181803.11781-23-jsnow@redhat.com> +Patchwork-id: 82096 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 22/25] qapi/block-mirror: expose new job properties +Bugzilla: 1626061 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Signed-off-by: John Snow +Reviewed-by: Max Reitz +Message-id: 20180906130225.5118-14-jsnow@redhat.com +Reviewed-by: Jeff Cody +Signed-off-by: Max Reitz +(cherry picked from commit 61bd6718ebceae42f97a99d2ffd315b05b86f1b3) +Signed-off-by: John Snow + +Conflicts: downstream does not have has_copy_mode. + -blockdev.c + -qapi/block-core.json + +Signed-off-by: Miroslav Rezanina +--- + blockdev.c | 14 ++++++++++++++ + qapi/block-core.json | 30 ++++++++++++++++++++++++++++-- + 2 files changed, 42 insertions(+), 2 deletions(-) + +diff --git a/blockdev.c b/blockdev.c +index 1d0cbb1..a655387 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -3753,6 +3753,8 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs, + bool has_unmap, bool unmap, + bool has_filter_node_name, + const char *filter_node_name, ++ bool has_auto_finalize, bool auto_finalize, ++ bool has_auto_dismiss, bool auto_dismiss, + Error **errp) + { + int job_flags = JOB_DEFAULT; +@@ -3778,6 +3780,12 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs, + if (!has_filter_node_name) { + filter_node_name = NULL; + } ++ if (has_auto_finalize && !auto_finalize) { ++ job_flags |= JOB_MANUAL_FINALIZE; ++ } ++ if (has_auto_dismiss && !auto_dismiss) { ++ job_flags |= JOB_MANUAL_DISMISS; ++ } + + if (granularity != 0 && (granularity < 512 || granularity > 1048576 * 64)) { + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "granularity", +@@ -3954,6 +3962,8 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) + arg->has_on_target_error, arg->on_target_error, + arg->has_unmap, arg->unmap, + false, NULL, ++ arg->has_auto_finalize, arg->auto_finalize, ++ arg->has_auto_dismiss, arg->auto_dismiss, + &local_err); + bdrv_unref(target_bs); + error_propagate(errp, local_err); +@@ -3974,6 +3984,8 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id, + BlockdevOnError on_target_error, + bool has_filter_node_name, + const char *filter_node_name, ++ bool has_auto_finalize, bool auto_finalize, ++ bool has_auto_dismiss, bool auto_dismiss, + Error **errp) + { + BlockDriverState *bs; +@@ -4006,6 +4018,8 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id, + has_on_target_error, on_target_error, + true, true, + has_filter_node_name, filter_node_name, ++ has_auto_finalize, auto_finalize, ++ has_auto_dismiss, auto_dismiss, + &local_err); + error_propagate(errp, local_err); + +diff --git a/qapi/block-core.json b/qapi/block-core.json +index af453c5..6a5e357 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -1712,6 +1712,18 @@ + # written. Both will result in identical contents. + # Default is true. (Since 2.4) + # ++# @auto-finalize: When false, this job will wait in a PENDING state after it has ++# finished its work, waiting for @block-job-finalize before ++# making any block graph changes. ++# When true, this job will automatically ++# perform its abort or commit actions. ++# Defaults to true. (Since 3.1) ++# ++# @auto-dismiss: When false, this job will wait in a CONCLUDED state after it ++# has completely ceased all work, and awaits @block-job-dismiss. ++# When true, this job will automatically disappear from the query ++# list without user intervention. ++# Defaults to true. (Since 3.1) + # Since: 1.3 + ## + { 'struct': 'DriveMirror', +@@ -1721,7 +1733,8 @@ + '*speed': 'int', '*granularity': 'uint32', + '*buf-size': 'int', '*on-source-error': 'BlockdevOnError', + '*on-target-error': 'BlockdevOnError', +- '*unmap': 'bool' } } ++ '*unmap': 'bool', ++ '*auto-finalize': 'bool', '*auto-dismiss': 'bool' } } + + ## + # @BlockDirtyBitmap: +@@ -1984,6 +1997,18 @@ + # above @device. If this option is not given, a node name is + # autogenerated. (Since: 2.9) + # ++# @auto-finalize: When false, this job will wait in a PENDING state after it has ++# finished its work, waiting for @block-job-finalize before ++# making any block graph changes. ++# When true, this job will automatically ++# perform its abort or commit actions. ++# Defaults to true. (Since 3.1) ++# ++# @auto-dismiss: When false, this job will wait in a CONCLUDED state after it ++# has completely ceased all work, and awaits @block-job-dismiss. ++# When true, this job will automatically disappear from the query ++# list without user intervention. ++# Defaults to true. (Since 3.1) + # Returns: nothing on success. + # + # Since: 2.6 +@@ -2004,7 +2029,8 @@ + '*speed': 'int', '*granularity': 'uint32', + '*buf-size': 'int', '*on-source-error': 'BlockdevOnError', + '*on-target-error': 'BlockdevOnError', +- '*filter-node-name': 'str' } } ++ '*filter-node-name': 'str', ++ '*auto-finalize': 'bool', '*auto-dismiss': 'bool' } } + + ## + # @block_set_io_throttle: +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qapi-block-stream-expose-new-job-properties.patch b/SOURCES/kvm-qapi-block-stream-expose-new-job-properties.patch new file mode 100644 index 0000000..0470c4d --- /dev/null +++ b/SOURCES/kvm-qapi-block-stream-expose-new-job-properties.patch @@ -0,0 +1,108 @@ +From 0ac47b4655421a41af7f14aed2949643849635e5 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 10 Sep 2018 18:18:01 +0200 +Subject: [PATCH 23/25] qapi/block-stream: expose new job properties + +RH-Author: John Snow +Message-id: <20180910181803.11781-24-jsnow@redhat.com> +Patchwork-id: 82099 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 23/25] qapi/block-stream: expose new job properties +Bugzilla: 1626061 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Signed-off-by: John Snow +Reviewed-by: Max Reitz +Message-id: 20180906130225.5118-15-jsnow@redhat.com +Reviewed-by: Jeff Cody +Signed-off-by: Max Reitz +(cherry picked from commit fd4bbe3c2caa01a2be5b311ef0685c7f92789592) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + blockdev.c | 9 +++++++++ + hmp.c | 5 +++-- + qapi/block-core.json | 16 +++++++++++++++- + 3 files changed, 27 insertions(+), 3 deletions(-) + +diff --git a/blockdev.c b/blockdev.c +index a655387..6325471 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -3273,6 +3273,8 @@ void qmp_block_stream(bool has_job_id, const char *job_id, const char *device, + bool has_backing_file, const char *backing_file, + bool has_speed, int64_t speed, + bool has_on_error, BlockdevOnError on_error, ++ bool has_auto_finalize, bool auto_finalize, ++ bool has_auto_dismiss, bool auto_dismiss, + Error **errp) + { + BlockDriverState *bs, *iter; +@@ -3342,6 +3344,13 @@ void qmp_block_stream(bool has_job_id, const char *job_id, const char *device, + /* backing_file string overrides base bs filename */ + base_name = has_backing_file ? backing_file : base_name; + ++ if (has_auto_finalize && !auto_finalize) { ++ job_flags |= JOB_MANUAL_FINALIZE; ++ } ++ if (has_auto_dismiss && !auto_dismiss) { ++ job_flags |= JOB_MANUAL_DISMISS; ++ } ++ + stream_start(has_job_id ? job_id : NULL, bs, base_bs, base_name, + job_flags, has_speed ? speed : 0, on_error, &local_err); + if (local_err) { +diff --git a/hmp.c b/hmp.c +index 7a53e63..cc088da 100644 +--- a/hmp.c ++++ b/hmp.c +@@ -1807,8 +1807,9 @@ void hmp_block_stream(Monitor *mon, const QDict *qdict) + int64_t speed = qdict_get_try_int(qdict, "speed", 0); + + qmp_block_stream(true, device, device, base != NULL, base, false, NULL, +- false, NULL, qdict_haskey(qdict, "speed"), speed, +- true, BLOCKDEV_ON_ERROR_REPORT, &error); ++ false, NULL, qdict_haskey(qdict, "speed"), speed, true, ++ BLOCKDEV_ON_ERROR_REPORT, false, false, false, false, ++ &error); + + hmp_handle_error(mon, &error); + } +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 6a5e357..5526cbc 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -2296,6 +2296,19 @@ + # 'stop' and 'enospc' can only be used if the block device + # supports io-status (see BlockInfo). Since 1.3. + # ++# @auto-finalize: When false, this job will wait in a PENDING state after it has ++# finished its work, waiting for @block-job-finalize before ++# making any block graph changes. ++# When true, this job will automatically ++# perform its abort or commit actions. ++# Defaults to true. (Since 3.1) ++# ++# @auto-dismiss: When false, this job will wait in a CONCLUDED state after it ++# has completely ceased all work, and awaits @block-job-dismiss. ++# When true, this job will automatically disappear from the query ++# list without user intervention. ++# Defaults to true. (Since 3.1) ++# + # Returns: Nothing on success. If @device does not exist, DeviceNotFound. + # + # Since: 1.1 +@@ -2311,7 +2324,8 @@ + { 'command': 'block-stream', + 'data': { '*job-id': 'str', 'device': 'str', '*base': 'str', + '*base-node': 'str', '*backing-file': 'str', '*speed': 'int', +- '*on-error': 'BlockdevOnError' } } ++ '*on-error': 'BlockdevOnError', ++ '*auto-finalize': 'bool', '*auto-dismiss': 'bool' } } + + ## + # @block-job-set-speed: +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qapi-new-qmp-command-nbd-server-add-bitmap.patch b/SOURCES/kvm-qapi-new-qmp-command-nbd-server-add-bitmap.patch new file mode 100644 index 0000000..70f30e5 --- /dev/null +++ b/SOURCES/kvm-qapi-new-qmp-command-nbd-server-add-bitmap.patch @@ -0,0 +1,104 @@ +From 9949f65ad44a273fabbf98591ef98b4742e6882f Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 18 Jul 2018 22:55:04 +0200 +Subject: [PATCH 79/89] qapi: new qmp command nbd-server-add-bitmap + +RH-Author: John Snow +Message-id: <20180718225511.14878-29-jsnow@redhat.com> +Patchwork-id: 81408 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 28/35] qapi: new qmp command nbd-server-add-bitmap +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Vladimir Sementsov-Ogievskiy + +For now, the actual command ix x-nbd-server-add-bitmap, reflecting +the fact that we are still working on libvirt code that proves the +command works as needed, and also the fact that we may remove +bitmap-export-name (and just require that the exported name be the +bitmap name). + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20180609151758.17343-6-vsementsov@virtuozzo.com> +Reviewed-by: Eric Blake +[eblake: make the command experimental by adding x- prefix] +Signed-off-by: Eric Blake +(cherry picked from commit 767f0c7d6cddedbc97ad700bd1e0229cc2ce5eb5) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + blockdev-nbd.c | 23 +++++++++++++++++++++++ + qapi/block.json | 23 +++++++++++++++++++++++ + 2 files changed, 46 insertions(+) + +diff --git a/blockdev-nbd.c b/blockdev-nbd.c +index 65a8473..1ef1104 100644 +--- a/blockdev-nbd.c ++++ b/blockdev-nbd.c +@@ -220,3 +220,26 @@ void qmp_nbd_server_stop(Error **errp) + nbd_server_free(nbd_server); + nbd_server = NULL; + } ++ ++void qmp_x_nbd_server_add_bitmap(const char *name, const char *bitmap, ++ bool has_bitmap_export_name, ++ const char *bitmap_export_name, ++ Error **errp) ++{ ++ NBDExport *exp; ++ ++ if (!nbd_server) { ++ error_setg(errp, "NBD server not running"); ++ return; ++ } ++ ++ exp = nbd_export_find(name); ++ if (exp == NULL) { ++ error_setg(errp, "Export '%s' is not found", name); ++ return; ++ } ++ ++ nbd_export_bitmap(exp, bitmap, ++ has_bitmap_export_name ? bitmap_export_name : bitmap, ++ errp); ++} +diff --git a/qapi/block.json b/qapi/block.json +index f05b91a..ba85ceb 100644 +--- a/qapi/block.json ++++ b/qapi/block.json +@@ -364,6 +364,29 @@ + 'data': {'name': 'str', '*mode': 'NbdServerRemoveMode'} } + + ## ++# @x-nbd-server-add-bitmap: ++# ++# Expose a dirty bitmap associated with the selected export. The bitmap search ++# starts at the device attached to the export, and includes all backing files. ++# The exported bitmap is then locked until the NBD export is removed. ++# ++# @name: Export name. ++# ++# @bitmap: Bitmap name to search for. ++# ++# @bitmap-export-name: How the bitmap will be seen by nbd clients ++# (default @bitmap) ++# ++# Note: the client must use NBD_OPT_SET_META_CONTEXT with a query of ++# "qemu:dirty-bitmap:NAME" (where NAME matches @bitmap-export-name) to access ++# the exposed bitmap. ++# ++# Since: 3.0 ++## ++ { 'command': 'x-nbd-server-add-bitmap', ++ 'data': {'name': 'str', 'bitmap': 'str', '*bitmap-export-name': 'str'} } ++ ++## + # @nbd-server-stop: + # + # Stop QEMU's embedded NBD server, and unregister all devices previously +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qcow2-Always-execute-preallocate-in-a-coroutine.patch b/SOURCES/kvm-qcow2-Always-execute-preallocate-in-a-coroutine.patch deleted file mode 100644 index 453efad..0000000 --- a/SOURCES/kvm-qcow2-Always-execute-preallocate-in-a-coroutine.patch +++ /dev/null @@ -1,113 +0,0 @@ -From 98ebc4e55985747726bbcbedecbe06fed8d7ea0a Mon Sep 17 00:00:00 2001 -From: Max Reitz -Date: Mon, 27 Nov 2017 16:19:58 +0100 -Subject: [PATCH 03/21] qcow2: Always execute preallocate() in a coroutine - -RH-Author: Max Reitz -Message-id: <20171127161959.13234-4-mreitz@redhat.com> -Patchwork-id: 77913 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH 3/4] qcow2: Always execute preallocate() in a coroutine -Bugzilla: 1414049 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Fam Zheng -RH-Acked-by: John Snow - -Some qcow2 functions (at least perform_cow()) expect s->lock to be -taken. Therefore, if we want to make use of them, we should execute -preallocate() (as "preallocate_co") in a coroutine so that we can use -the qemu_co_mutex_* functions. - -Signed-off-by: Max Reitz -Message-id: 20171009215533.12530-3-mreitz@redhat.com -Cc: qemu-stable@nongnu.org -Reviewed-by: Eric Blake -Reviewed-by: Jeff Cody -Reviewed-by: Stefan Hajnoczi -Signed-off-by: Max Reitz -(cherry picked from commit 572b07bea1d1a0f7726fd95c2613c76002a379bc) -Signed-off-by: Max Reitz -Signed-off-by: Miroslav Rezanina ---- - block/qcow2.c | 41 ++++++++++++++++++++++++++++++++++------- - 1 file changed, 34 insertions(+), 7 deletions(-) - -diff --git a/block/qcow2.c b/block/qcow2.c -index 2cfe706..b26cbbf 100644 ---- a/block/qcow2.c -+++ b/block/qcow2.c -@@ -2476,6 +2476,14 @@ static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt, - } - - -+typedef struct PreallocCo { -+ BlockDriverState *bs; -+ uint64_t offset; -+ uint64_t new_length; -+ -+ int ret; -+} PreallocCo; -+ - /** - * Preallocates metadata structures for data clusters between @offset (in the - * guest disk) and @new_length (which is thus generally the new guest disk -@@ -2483,9 +2491,12 @@ static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt, - * - * Returns: 0 on success, -errno on failure. - */ --static int preallocate(BlockDriverState *bs, -- uint64_t offset, uint64_t new_length) -+static void coroutine_fn preallocate_co(void *opaque) - { -+ PreallocCo *params = opaque; -+ BlockDriverState *bs = params->bs; -+ uint64_t offset = params->offset; -+ uint64_t new_length = params->new_length; - BDRVQcow2State *s = bs->opaque; - uint64_t bytes; - uint64_t host_offset = 0; -@@ -2493,9 +2504,7 @@ static int preallocate(BlockDriverState *bs, - int ret; - QCowL2Meta *meta; - -- if (qemu_in_coroutine()) { -- qemu_co_mutex_lock(&s->lock); -- } -+ qemu_co_mutex_lock(&s->lock); - - assert(offset <= new_length); - bytes = new_length - offset; -@@ -2549,10 +2558,28 @@ static int preallocate(BlockDriverState *bs, - ret = 0; - - done: -+ qemu_co_mutex_unlock(&s->lock); -+ params->ret = ret; -+} -+ -+static int preallocate(BlockDriverState *bs, -+ uint64_t offset, uint64_t new_length) -+{ -+ PreallocCo params = { -+ .bs = bs, -+ .offset = offset, -+ .new_length = new_length, -+ .ret = -EINPROGRESS, -+ }; -+ - if (qemu_in_coroutine()) { -- qemu_co_mutex_unlock(&s->lock); -+ preallocate_co(¶ms); -+ } else { -+ Coroutine *co = qemu_coroutine_create(preallocate_co, ¶ms); -+ bdrv_coroutine_enter(bs, co); -+ BDRV_POLL_WHILE(bs, params.ret == -EINPROGRESS); - } -- return ret; -+ return params.ret; - } - - /* qcow2_refcount_metadata_size: --- -1.8.3.1 - diff --git a/SOURCES/kvm-qcow2-Do-not-mark-inactive-images-corrupt.patch b/SOURCES/kvm-qcow2-Do-not-mark-inactive-images-corrupt.patch new file mode 100644 index 0000000..8f5eb86 --- /dev/null +++ b/SOURCES/kvm-qcow2-Do-not-mark-inactive-images-corrupt.patch @@ -0,0 +1,57 @@ +From f853102082f547314221cdd5846493252826086f Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 18:00:54 +0200 +Subject: [PATCH 48/54] qcow2: Do not mark inactive images corrupt + +RH-Author: Max Reitz +Message-id: <20180618180055.22739-3-mreitz@redhat.com> +Patchwork-id: 80793 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 2/3] qcow2: Do not mark inactive images corrupt +Bugzilla: 1588039 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf +RH-Acked-by: John Snow + +When signaling a corruption on a read-only image, qcow2 already makes +fatal events non-fatal (i.e., they will not result in the image being +closed, and the image header's corrupt flag will not be set). This is +necessary because we cannot set the corrupt flag on read-only images, +and it is possible because further corruption of read-only images is +impossible. + +Inactive images are effectively read-only, too, so we should do the same +for them. bdrv_is_writable() can tell us whether an image can actually +be written to, so use its result instead of !bs->read_only. + +(Otherwise, the assert(!(bs->open_flags & BDRV_O_INACTIVE)) in +bdrv_co_pwritev() will fail, crashing qemu.) + +Cc: qemu-stable@nongnu.org +Signed-off-by: Max Reitz +Message-id: 20180606193702.7113-3-mreitz@redhat.com +Reviewed-by: John Snow +Reviewed-by: Jeff Cody +Signed-off-by: Max Reitz +(cherry picked from commit ddf3b47ef4b5ed0bf6558d4c2c8ae130b8d8a580) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + block/qcow2.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/block/qcow2.c b/block/qcow2.c +index 35842c5..26a6a7f 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -4383,7 +4383,7 @@ void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset, + char *message; + va_list ap; + +- fatal = fatal && !bs->read_only; ++ fatal = fatal && bdrv_is_writable(bs); + + if (s->signaled_corruption && + (!fatal || (s->incompatible_features & QCOW2_INCOMPAT_CORRUPT))) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qcow2-Fix-qcow2_truncate-error-return-value.patch b/SOURCES/kvm-qcow2-Fix-qcow2_truncate-error-return-value.patch new file mode 100644 index 0000000..70a5a29 --- /dev/null +++ b/SOURCES/kvm-qcow2-Fix-qcow2_truncate-error-return-value.patch @@ -0,0 +1,44 @@ +From 2854a11fc02a664688ddc3ccbd7786f0aec219bd Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Thu, 12 Jul 2018 14:42:53 +0200 +Subject: [PATCH 34/89] qcow2: Fix qcow2_truncate() error return value + +RH-Author: Kevin Wolf +Message-id: <20180712144258.17303-2-kwolf@redhat.com> +Patchwork-id: 81325 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 1/6] qcow2: Fix qcow2_truncate() error return value +Bugzilla: 1595173 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: John Snow + +If qcow2_alloc_clusters_at() returns an error, we do need to negate it +to get back the positive errno code for error_setg_errno(), but we still +need to return the negative error code. + +Fixes: 772d1f973f87269f6a4a4ea4b880680f3779bbdf +Signed-off-by: Kevin Wolf +Reviewed-by: Stefan Hajnoczi +(cherry picked from commit ae5475e82fd1ebb24f4f77cf28f59ca6548c6136) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/qcow2.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/block/qcow2.c b/block/qcow2.c +index da74e2a..dbd448c 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -3594,7 +3594,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, + if (clusters_allocated < 0) { + error_setg_errno(errp, -clusters_allocated, + "Failed to allocate data clusters"); +- return -clusters_allocated; ++ return clusters_allocated; + } + + assert(clusters_allocated == nb_new_data_clusters); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qcow2-Fix-src_offset-in-copy-offloading.patch b/SOURCES/kvm-qcow2-Fix-src_offset-in-copy-offloading.patch new file mode 100644 index 0000000..c2b2623 --- /dev/null +++ b/SOURCES/kvm-qcow2-Fix-src_offset-in-copy-offloading.patch @@ -0,0 +1,82 @@ +From 9cc4ecc4169dc8a8636a1ddc8dbe454a274e1432 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 29 Jun 2018 06:11:51 +0200 +Subject: [PATCH 47/57] qcow2: Fix src_offset in copy offloading + +RH-Author: Fam Zheng +Message-id: <20180629061153.12687-12-famz@redhat.com> +Patchwork-id: 81163 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v2 11/13] qcow2: Fix src_offset in copy offloading +Bugzilla: 1482537 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Kevin Wolf + +Not updating src_offset will result in wrong data being written to dst +image. + +Reported-by: Max Reitz +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/qcow2.c | 1 + + tests/qemu-iotests/063 | 9 +++++++++ + tests/qemu-iotests/063.out | 12 ++++++++++++ + 3 files changed, 22 insertions(+) + +diff --git a/block/qcow2.c b/block/qcow2.c +index c85ebcb..4404dc7 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -3416,6 +3416,7 @@ qcow2_co_copy_range_to(BlockDriverState *bs, + } + + bytes -= cur_bytes; ++ src_offset += cur_bytes; + dst_offset += cur_bytes; + } + ret = 0; +diff --git a/tests/qemu-iotests/063 b/tests/qemu-iotests/063 +index e4f6ea9..adc037c 100755 +--- a/tests/qemu-iotests/063 ++++ b/tests/qemu-iotests/063 +@@ -91,6 +91,15 @@ if $QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n "$TEST_IMG.orig" "$TEST_IMG" >/dev + exit 1 + fi + ++echo "== Regression testing for copy offloading bug ==" ++ ++_make_test_img 1M ++TEST_IMG="$TEST_IMG.target" _make_test_img 1M ++$QEMU_IO -c 'write -P 1 0 512k' -c 'write -P 2 512k 512k' "$TEST_IMG" | _filter_qemu_io ++$QEMU_IO -c 'write -P 4 512k 512k' -c 'write -P 3 0 512k' "$TEST_IMG.target" | _filter_qemu_io ++$QEMU_IMG convert -n -O $IMGFMT "$TEST_IMG" "$TEST_IMG.target" ++$QEMU_IMG compare "$TEST_IMG" "$TEST_IMG.target" ++ + echo "*** done" + rm -f $seq.full + status=0 +diff --git a/tests/qemu-iotests/063.out b/tests/qemu-iotests/063.out +index de1c99a..7b691b2 100644 +--- a/tests/qemu-iotests/063.out ++++ b/tests/qemu-iotests/063.out +@@ -7,4 +7,16 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4194304 + No errors were found on the image. + == Testing conversion to a smaller file fails == + Formatting 'TEST_DIR/t.IMGFMT', 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 ++wrote 524288/524288 bytes at offset 0 ++512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++wrote 524288/524288 bytes at offset 524288 ++512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++wrote 524288/524288 bytes at offset 524288 ++512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++wrote 524288/524288 bytes at offset 0 ++512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++Images are identical. + *** done +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qcow2-Fix-unaligned-preallocated-truncation.patch b/SOURCES/kvm-qcow2-Fix-unaligned-preallocated-truncation.patch deleted file mode 100644 index 924ef3d..0000000 --- a/SOURCES/kvm-qcow2-Fix-unaligned-preallocated-truncation.patch +++ /dev/null @@ -1,51 +0,0 @@ -From f2c23150bc8b51e7b6c78f98cc38880ff1e5e811 Mon Sep 17 00:00:00 2001 -From: Max Reitz -Date: Mon, 27 Nov 2017 16:19:57 +0100 -Subject: [PATCH 02/21] qcow2: Fix unaligned preallocated truncation - -RH-Author: Max Reitz -Message-id: <20171127161959.13234-3-mreitz@redhat.com> -Patchwork-id: 77911 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH 2/4] qcow2: Fix unaligned preallocated truncation -Bugzilla: 1414049 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Fam Zheng -RH-Acked-by: John Snow - -A qcow2 image file's length is not required to have a length that is a -multiple of the cluster size. However, qcow2_refcount_area() expects an -aligned value for its @start_offset parameter, so we need to round -@old_file_size up to the next cluster boundary. - -Reported-by: Ping Li -Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1414049 -Signed-off-by: Max Reitz -Message-id: 20171009215533.12530-2-mreitz@redhat.com -Cc: qemu-stable@nongnu.org -Reviewed-by: Eric Blake -Reviewed-by: Jeff Cody -Reviewed-by: Stefan Hajnoczi -Signed-off-by: Max Reitz -(cherry picked from commit e400ad1e1f0127b4fdabcb1c8de1e99be91788df) -Signed-off-by: Max Reitz -Signed-off-by: Miroslav Rezanina ---- - block/qcow2.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/block/qcow2.c b/block/qcow2.c -index af7b1e7..2cfe706 100644 ---- a/block/qcow2.c -+++ b/block/qcow2.c -@@ -3161,6 +3161,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, - "Failed to inquire current file length"); - return old_file_size; - } -+ old_file_size = ROUND_UP(old_file_size, s->cluster_size); - - nb_new_data_clusters = DIV_ROUND_UP(offset - old_length, - s->cluster_size); --- -1.8.3.1 - diff --git a/SOURCES/kvm-qcow2-Free-allocated-clusters-on-write-error.patch b/SOURCES/kvm-qcow2-Free-allocated-clusters-on-write-error.patch new file mode 100644 index 0000000..faca4b4 --- /dev/null +++ b/SOURCES/kvm-qcow2-Free-allocated-clusters-on-write-error.patch @@ -0,0 +1,83 @@ +From d53f85c0fbaf3b7936e7a4b0f019be986a39fe7a Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Mon, 2 Jul 2018 15:40:07 +0200 +Subject: [PATCH 54/57] qcow2: Free allocated clusters on write error + +RH-Author: Kevin Wolf +Message-id: <20180702154008.15533-3-kwolf@redhat.com> +Patchwork-id: 81185 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 2/3] qcow2: Free allocated clusters on write error +Bugzilla: 1528541 +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng +RH-Acked-by: Stefan Hajnoczi + +If we managed to allocate the clusters, but then failed to write the +data, there's a good chance that we'll still be able to free the +clusters again in order to avoid cluster leaks (the refcounts are +cached, so even if we can't write them out right now, we may be able to +do so when the VM is resumed after a werror=stop/enospc pause). + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +Reviewed-by: Eric Blake +Tested-by: Eric Blake +(cherry picked from commit 8b24cd141549b5b264baeddd4e72902cfb5de23b) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/qcow2-cluster.c | 11 +++++++++++ + block/qcow2.c | 2 ++ + block/qcow2.h | 1 + + 3 files changed, 14 insertions(+) + +diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c +index 1aee726..c90e2ec 100644 +--- a/block/qcow2-cluster.c ++++ b/block/qcow2-cluster.c +@@ -994,6 +994,17 @@ err: + return ret; + } + ++/** ++ * Frees the allocated clusters because the request failed and they won't ++ * actually be linked. ++ */ ++void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m) ++{ ++ BDRVQcow2State *s = bs->opaque; ++ qcow2_free_clusters(bs, m->alloc_offset, m->nb_clusters << s->cluster_bits, ++ QCOW2_DISCARD_NEVER); ++} ++ + /* + * Returns the number of contiguous clusters that can be used for an allocating + * write, but require COW to be performed (this includes yet unallocated space, +diff --git a/block/qcow2.c b/block/qcow2.c +index 4404dc7..da74e2a 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -1771,6 +1771,8 @@ static coroutine_fn int qcow2_handle_l2meta(BlockDriverState *bs, + if (ret) { + goto out; + } ++ } else { ++ qcow2_alloc_cluster_abort(bs, l2meta); + } + + /* Take the request off the list of running requests */ +diff --git a/block/qcow2.h b/block/qcow2.h +index adf5c39..b5e2aa3 100644 +--- a/block/qcow2.h ++++ b/block/qcow2.h +@@ -618,6 +618,7 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, + int compressed_size); + + int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m); ++void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m); + int qcow2_cluster_discard(BlockDriverState *bs, uint64_t offset, + uint64_t bytes, enum qcow2_discard_type type, + bool full_discard); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qcow2-Implement-copy-offloading.patch b/SOURCES/kvm-qcow2-Implement-copy-offloading.patch new file mode 100644 index 0000000..a8bc9a3 --- /dev/null +++ b/SOURCES/kvm-qcow2-Implement-copy-offloading.patch @@ -0,0 +1,301 @@ +From 3650b202ee9499c9c234eb05d296eb4d35f52f34 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 29 Jun 2018 06:11:44 +0200 +Subject: [PATCH 40/57] qcow2: Implement copy offloading + +RH-Author: Fam Zheng +Message-id: <20180629061153.12687-5-famz@redhat.com> +Patchwork-id: 81154 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v2 04/13] qcow2: Implement copy offloading +Bugzilla: 1482537 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Kevin Wolf + +The two callbacks are implemented quite similarly to the read/write +functions: bdrv_co_copy_range_from maps for read and calls into bs->file +or bs->backing depending on the allocation status; bdrv_co_copy_range_to +maps for write and calls into bs->file. + +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Fam Zheng +Message-id: 20180601092648.24614-5-famz@redhat.com +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit fd9fcd37a8645efe322956d94f76e90135522a16) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/qcow2.c | 229 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- + 1 file changed, 199 insertions(+), 30 deletions(-) + +diff --git a/block/qcow2.c b/block/qcow2.c +index 092db81..c85ebcb 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -1756,6 +1756,39 @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs, + return status; + } + ++static coroutine_fn int qcow2_handle_l2meta(BlockDriverState *bs, ++ QCowL2Meta **pl2meta, ++ bool link_l2) ++{ ++ int ret = 0; ++ QCowL2Meta *l2meta = *pl2meta; ++ ++ while (l2meta != NULL) { ++ QCowL2Meta *next; ++ ++ if (!ret && link_l2) { ++ ret = qcow2_alloc_cluster_link_l2(bs, l2meta); ++ if (ret) { ++ goto out; ++ } ++ } ++ ++ /* Take the request off the list of running requests */ ++ if (l2meta->nb_clusters != 0) { ++ QLIST_REMOVE(l2meta, next_in_flight); ++ } ++ ++ qemu_co_queue_restart_all(&l2meta->dependent_requests); ++ ++ next = l2meta->next; ++ g_free(l2meta); ++ l2meta = next; ++ } ++out: ++ *pl2meta = l2meta; ++ return ret; ++} ++ + static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset, + uint64_t bytes, QEMUIOVector *qiov, + int flags) +@@ -2042,24 +2075,9 @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset, + } + } + +- while (l2meta != NULL) { +- QCowL2Meta *next; +- +- ret = qcow2_alloc_cluster_link_l2(bs, l2meta); +- if (ret < 0) { +- goto fail; +- } +- +- /* Take the request off the list of running requests */ +- if (l2meta->nb_clusters != 0) { +- QLIST_REMOVE(l2meta, next_in_flight); +- } +- +- qemu_co_queue_restart_all(&l2meta->dependent_requests); +- +- next = l2meta->next; +- g_free(l2meta); +- l2meta = next; ++ ret = qcow2_handle_l2meta(bs, &l2meta, true); ++ if (ret) { ++ goto fail; + } + + bytes -= cur_bytes; +@@ -2070,18 +2088,7 @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset, + ret = 0; + + fail: +- while (l2meta != NULL) { +- QCowL2Meta *next; +- +- if (l2meta->nb_clusters != 0) { +- QLIST_REMOVE(l2meta, next_in_flight); +- } +- qemu_co_queue_restart_all(&l2meta->dependent_requests); +- +- next = l2meta->next; +- g_free(l2meta); +- l2meta = next; +- } ++ qcow2_handle_l2meta(bs, &l2meta, false); + + qemu_co_mutex_unlock(&s->lock); + +@@ -3264,6 +3271,166 @@ static coroutine_fn int qcow2_co_pdiscard(BlockDriverState *bs, + return ret; + } + ++static int coroutine_fn ++qcow2_co_copy_range_from(BlockDriverState *bs, ++ BdrvChild *src, uint64_t src_offset, ++ BdrvChild *dst, uint64_t dst_offset, ++ uint64_t bytes, BdrvRequestFlags flags) ++{ ++ BDRVQcow2State *s = bs->opaque; ++ int ret; ++ unsigned int cur_bytes; /* number of bytes in current iteration */ ++ BdrvChild *child = NULL; ++ BdrvRequestFlags cur_flags; ++ ++ assert(!bs->encrypted); ++ qemu_co_mutex_lock(&s->lock); ++ ++ while (bytes != 0) { ++ uint64_t copy_offset = 0; ++ /* prepare next request */ ++ cur_bytes = MIN(bytes, INT_MAX); ++ cur_flags = flags; ++ ++ ret = qcow2_get_cluster_offset(bs, src_offset, &cur_bytes, ©_offset); ++ if (ret < 0) { ++ goto out; ++ } ++ ++ switch (ret) { ++ case QCOW2_CLUSTER_UNALLOCATED: ++ if (bs->backing && bs->backing->bs) { ++ int64_t backing_length = bdrv_getlength(bs->backing->bs); ++ if (src_offset >= backing_length) { ++ cur_flags |= BDRV_REQ_ZERO_WRITE; ++ } else { ++ child = bs->backing; ++ cur_bytes = MIN(cur_bytes, backing_length - src_offset); ++ copy_offset = src_offset; ++ } ++ } else { ++ cur_flags |= BDRV_REQ_ZERO_WRITE; ++ } ++ break; ++ ++ case QCOW2_CLUSTER_ZERO_PLAIN: ++ case QCOW2_CLUSTER_ZERO_ALLOC: ++ cur_flags |= BDRV_REQ_ZERO_WRITE; ++ break; ++ ++ case QCOW2_CLUSTER_COMPRESSED: ++ ret = -ENOTSUP; ++ goto out; ++ break; ++ ++ case QCOW2_CLUSTER_NORMAL: ++ child = bs->file; ++ copy_offset += offset_into_cluster(s, src_offset); ++ if ((copy_offset & 511) != 0) { ++ ret = -EIO; ++ goto out; ++ } ++ break; ++ ++ default: ++ abort(); ++ } ++ qemu_co_mutex_unlock(&s->lock); ++ ret = bdrv_co_copy_range_from(child, ++ copy_offset, ++ dst, dst_offset, ++ cur_bytes, cur_flags); ++ qemu_co_mutex_lock(&s->lock); ++ if (ret < 0) { ++ goto out; ++ } ++ ++ bytes -= cur_bytes; ++ src_offset += cur_bytes; ++ dst_offset += cur_bytes; ++ } ++ ret = 0; ++ ++out: ++ qemu_co_mutex_unlock(&s->lock); ++ return ret; ++} ++ ++static int coroutine_fn ++qcow2_co_copy_range_to(BlockDriverState *bs, ++ BdrvChild *src, uint64_t src_offset, ++ BdrvChild *dst, uint64_t dst_offset, ++ uint64_t bytes, BdrvRequestFlags flags) ++{ ++ BDRVQcow2State *s = bs->opaque; ++ int offset_in_cluster; ++ int ret; ++ unsigned int cur_bytes; /* number of sectors in current iteration */ ++ uint64_t cluster_offset; ++ uint8_t *cluster_data = NULL; ++ QCowL2Meta *l2meta = NULL; ++ ++ assert(!bs->encrypted); ++ s->cluster_cache_offset = -1; /* disable compressed cache */ ++ ++ qemu_co_mutex_lock(&s->lock); ++ ++ while (bytes != 0) { ++ ++ l2meta = NULL; ++ ++ offset_in_cluster = offset_into_cluster(s, dst_offset); ++ cur_bytes = MIN(bytes, INT_MAX); ++ ++ /* TODO: ++ * If src->bs == dst->bs, we could simply copy by incrementing ++ * the refcnt, without copying user data. ++ * Or if src->bs == dst->bs->backing->bs, we could copy by discarding. */ ++ ret = qcow2_alloc_cluster_offset(bs, dst_offset, &cur_bytes, ++ &cluster_offset, &l2meta); ++ if (ret < 0) { ++ goto fail; ++ } ++ ++ assert((cluster_offset & 511) == 0); ++ ++ ret = qcow2_pre_write_overlap_check(bs, 0, ++ cluster_offset + offset_in_cluster, cur_bytes); ++ if (ret < 0) { ++ goto fail; ++ } ++ ++ qemu_co_mutex_unlock(&s->lock); ++ ret = bdrv_co_copy_range_to(src, src_offset, ++ bs->file, ++ cluster_offset + offset_in_cluster, ++ cur_bytes, flags); ++ qemu_co_mutex_lock(&s->lock); ++ if (ret < 0) { ++ goto fail; ++ } ++ ++ ret = qcow2_handle_l2meta(bs, &l2meta, true); ++ if (ret) { ++ goto fail; ++ } ++ ++ bytes -= cur_bytes; ++ dst_offset += cur_bytes; ++ } ++ ret = 0; ++ ++fail: ++ qcow2_handle_l2meta(bs, &l2meta, false); ++ ++ qemu_co_mutex_unlock(&s->lock); ++ ++ qemu_vfree(cluster_data); ++ trace_qcow2_writev_done_req(qemu_coroutine_self(), ret); ++ ++ return ret; ++} ++ + static int qcow2_truncate(BlockDriverState *bs, int64_t offset, + PreallocMode prealloc, Error **errp) + { +@@ -4522,6 +4689,8 @@ BlockDriver bdrv_qcow2 = { + + .bdrv_co_pwrite_zeroes = qcow2_co_pwrite_zeroes, + .bdrv_co_pdiscard = qcow2_co_pdiscard, ++ .bdrv_co_copy_range_from = qcow2_co_copy_range_from, ++ .bdrv_co_copy_range_to = qcow2_co_copy_range_to, + .bdrv_truncate = qcow2_truncate, + .bdrv_co_pwritev_compressed = qcow2_co_pwritev_compressed, + .bdrv_make_empty = qcow2_make_empty, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qcow2-Remove-coroutine-trampoline-for-preallocate_co.patch b/SOURCES/kvm-qcow2-Remove-coroutine-trampoline-for-preallocate_co.patch new file mode 100644 index 0000000..8c2d3d0 --- /dev/null +++ b/SOURCES/kvm-qcow2-Remove-coroutine-trampoline-for-preallocate_co.patch @@ -0,0 +1,137 @@ +From 17d9cdafd0e6859af0b44b26870f8d61bc6f7c2d Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Thu, 12 Jul 2018 14:42:55 +0200 +Subject: [PATCH 36/89] qcow2: Remove coroutine trampoline for preallocate_co() + +RH-Author: Kevin Wolf +Message-id: <20180712144258.17303-4-kwolf@redhat.com> +Patchwork-id: 81329 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 3/6] qcow2: Remove coroutine trampoline for preallocate_co() +Bugzilla: 1595173 +RH-Acked-by: Max Reitz +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: John Snow + +All callers are coroutine_fns now, so we can just directly call +preallocate_co(). + +Signed-off-by: Kevin Wolf +Reviewed-by: Stefan Hajnoczi +(cherry picked from commit 47e86b868d57ffe13162ca44e5f6a51c15c4a769) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/qcow2.c | 51 ++++++++------------------------------------------- + 1 file changed, 8 insertions(+), 43 deletions(-) + +diff --git a/block/qcow2.c b/block/qcow2.c +index c5c6ae9..71fbfcd 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -2517,15 +2517,6 @@ static int qcow2_set_up_encryption(BlockDriverState *bs, + return ret; + } + +- +-typedef struct PreallocCo { +- BlockDriverState *bs; +- uint64_t offset; +- uint64_t new_length; +- +- int ret; +-} PreallocCo; +- + /** + * Preallocates metadata structures for data clusters between @offset (in the + * guest disk) and @new_length (which is thus generally the new guest disk +@@ -2533,12 +2524,9 @@ typedef struct PreallocCo { + * + * Returns: 0 on success, -errno on failure. + */ +-static void coroutine_fn preallocate_co(void *opaque) ++static int coroutine_fn preallocate_co(BlockDriverState *bs, uint64_t offset, ++ uint64_t new_length) + { +- PreallocCo *params = opaque; +- BlockDriverState *bs = params->bs; +- uint64_t offset = params->offset; +- uint64_t new_length = params->new_length; + uint64_t bytes; + uint64_t host_offset = 0; + unsigned int cur_bytes; +@@ -2553,7 +2541,7 @@ static void coroutine_fn preallocate_co(void *opaque) + ret = qcow2_alloc_cluster_offset(bs, offset, &cur_bytes, + &host_offset, &meta); + if (ret < 0) { +- goto done; ++ return ret; + } + + while (meta) { +@@ -2563,7 +2551,7 @@ static void coroutine_fn preallocate_co(void *opaque) + if (ret < 0) { + qcow2_free_any_clusters(bs, meta->alloc_offset, + meta->nb_clusters, QCOW2_DISCARD_NEVER); +- goto done; ++ return ret; + } + + /* There are no dependent requests, but we need to remove our +@@ -2590,34 +2578,11 @@ static void coroutine_fn preallocate_co(void *opaque) + ret = bdrv_pwrite(bs->file, (host_offset + cur_bytes) - 1, + &data, 1); + if (ret < 0) { +- goto done; ++ return ret; + } + } + +- ret = 0; +- +-done: +- params->ret = ret; +-} +- +-static int preallocate(BlockDriverState *bs, +- uint64_t offset, uint64_t new_length) +-{ +- PreallocCo params = { +- .bs = bs, +- .offset = offset, +- .new_length = new_length, +- .ret = -EINPROGRESS, +- }; +- +- if (qemu_in_coroutine()) { +- preallocate_co(¶ms); +- } else { +- Coroutine *co = qemu_coroutine_create(preallocate_co, ¶ms); +- bdrv_coroutine_enter(bs, co); +- BDRV_POLL_WHILE(bs, params.ret == -EINPROGRESS); +- } +- return params.ret; ++ return 0; + } + + /* qcow2_refcount_metadata_size: +@@ -3035,7 +3000,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) + if (qcow2_opts->preallocation != PREALLOC_MODE_OFF) { + BDRVQcow2State *s = blk_bs(blk)->opaque; + qemu_co_mutex_lock(&s->lock); +- ret = preallocate(blk_bs(blk), 0, qcow2_opts->size); ++ ret = preallocate_co(blk_bs(blk), 0, qcow2_opts->size); + qemu_co_mutex_unlock(&s->lock); + + if (ret < 0) { +@@ -3544,7 +3509,7 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, + break; + + case PREALLOC_MODE_METADATA: +- ret = preallocate(bs, old_length, offset); ++ ret = preallocate_co(bs, old_length, offset); + if (ret < 0) { + error_setg_errno(errp, -ret, "Preallocation failed"); + goto fail; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qcow2-Remove-dead-check-on-ret.patch b/SOURCES/kvm-qcow2-Remove-dead-check-on-ret.patch new file mode 100644 index 0000000..688c982 --- /dev/null +++ b/SOURCES/kvm-qcow2-Remove-dead-check-on-ret.patch @@ -0,0 +1,51 @@ +From 3e96785b4f89d97ca8297e2ea4ed2458409422ec Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 18 Jul 2018 22:54:48 +0200 +Subject: [PATCH 63/89] qcow2: Remove dead check on !ret +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: John Snow +Message-id: <20180718225511.14878-13-jsnow@redhat.com> +Patchwork-id: 81409 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 12/35] qcow2: Remove dead check on !ret +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Fam Zheng + +In the beginning of the function, we initialize the local variable to 0, +and in the body of the function, we check the assigned values and exit +the loop immediately. So here it can never be non-zero. + +Reported-by: Kevin Wolf +Signed-off-by: Fam Zheng +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Kevin Wolf +(cherry picked from commit 354d930dc6e90e97599459b79c071ff1b93e433b) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/qcow2.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/block/qcow2.c b/block/qcow2.c +index c5341a4..e171a99 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -1772,7 +1772,7 @@ static coroutine_fn int qcow2_handle_l2meta(BlockDriverState *bs, + while (l2meta != NULL) { + QCowL2Meta *next; + +- if (!ret && link_l2) { ++ if (link_l2) { + ret = qcow2_alloc_cluster_link_l2(bs, l2meta); + if (ret) { + goto out; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qcow2-Repair-OFLAG_COPIED-when-fixing-leaks.patch b/SOURCES/kvm-qcow2-Repair-OFLAG_COPIED-when-fixing-leaks.patch new file mode 100644 index 0000000..68cc8a7 --- /dev/null +++ b/SOURCES/kvm-qcow2-Repair-OFLAG_COPIED-when-fixing-leaks.patch @@ -0,0 +1,90 @@ +From dfcb9147d46e9e0da762349fd62a4ac620100cb4 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 17:16:54 +0200 +Subject: [PATCH 45/54] qcow2: Repair OFLAG_COPIED when fixing leaks + +RH-Author: Max Reitz +Message-id: <20180618171655.25987-2-mreitz@redhat.com> +Patchwork-id: 80782 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 1/2] qcow2: Repair OFLAG_COPIED when fixing leaks +Bugzilla: 1527085 +RH-Acked-by: John Snow +RH-Acked-by: Kevin Wolf +RH-Acked-by: Miroslav Rezanina + +Repairing OFLAG_COPIED is usually safe because it is done after the +refcounts have been repaired. Therefore, it we did not find anyone else +referencing a data or L2 cluster, it makes no sense to not set +OFLAG_COPIED -- and the other direction (clearing OFLAG_COPIED) is +always safe, anyway, it may just induce leaks. + +Furthermore, if OFLAG_COPIED is actually consistent with a wrong (leaky) +refcount, we will decrement the refcount with -r leaks, but OFLAG_COPIED +will then be wrong. qemu-img check should not produce images that are +more corrupted afterwards then they were before. + +Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1527085 +Signed-off-by: Max Reitz +Reviewed-by: Eric Blake +Message-id: 20180509200059.31125-2-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit 3cce51c919c7b4028cf6676dfcb80a45741b5117) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + block/qcow2-refcount.c | 25 +++++++++++++++++-------- + 1 file changed, 17 insertions(+), 8 deletions(-) + +diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c +index 6b8b635..4e14c0a 100644 +--- a/block/qcow2-refcount.c ++++ b/block/qcow2-refcount.c +@@ -1799,6 +1799,19 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res, + int ret; + uint64_t refcount; + int i, j; ++ bool repair; ++ ++ if (fix & BDRV_FIX_ERRORS) { ++ /* Always repair */ ++ repair = true; ++ } else if (fix & BDRV_FIX_LEAKS) { ++ /* Repair only if that seems safe: This function is always ++ * called after the refcounts have been fixed, so the refcount ++ * is accurate if that repair was successful */ ++ repair = !res->check_errors && !res->corruptions && !res->leaks; ++ } else { ++ repair = false; ++ } + + for (i = 0; i < s->l1_size; i++) { + uint64_t l1_entry = s->l1_table[i]; +@@ -1818,10 +1831,8 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res, + if ((refcount == 1) != ((l1_entry & QCOW_OFLAG_COPIED) != 0)) { + fprintf(stderr, "%s OFLAG_COPIED L2 cluster: l1_index=%d " + "l1_entry=%" PRIx64 " refcount=%" PRIu64 "\n", +- fix & BDRV_FIX_ERRORS ? "Repairing" : +- "ERROR", +- i, l1_entry, refcount); +- if (fix & BDRV_FIX_ERRORS) { ++ repair ? "Repairing" : "ERROR", i, l1_entry, refcount); ++ if (repair) { + s->l1_table[i] = refcount == 1 + ? l1_entry | QCOW_OFLAG_COPIED + : l1_entry & ~QCOW_OFLAG_COPIED; +@@ -1862,10 +1873,8 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res, + if ((refcount == 1) != ((l2_entry & QCOW_OFLAG_COPIED) != 0)) { + fprintf(stderr, "%s OFLAG_COPIED data cluster: " + "l2_entry=%" PRIx64 " refcount=%" PRIu64 "\n", +- fix & BDRV_FIX_ERRORS ? "Repairing" : +- "ERROR", +- l2_entry, refcount); +- if (fix & BDRV_FIX_ERRORS) { ++ repair ? "Repairing" : "ERROR", l2_entry, refcount); ++ if (repair) { + l2_table[j] = cpu_to_be64(refcount == 1 + ? l2_entry | QCOW_OFLAG_COPIED + : l2_entry & ~QCOW_OFLAG_COPIED); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qcow2-add-overlap-check-for-bitmap-directory.patch b/SOURCES/kvm-qcow2-add-overlap-check-for-bitmap-directory.patch new file mode 100644 index 0000000..e18d53b --- /dev/null +++ b/SOURCES/kvm-qcow2-add-overlap-check-for-bitmap-directory.patch @@ -0,0 +1,217 @@ +From 1b36ea8bc4840907b78867ae040231fe91f12851 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 18 Jul 2018 22:54:45 +0200 +Subject: [PATCH 60/89] qcow2: add overlap check for bitmap directory + +RH-Author: John Snow +Message-id: <20180718225511.14878-10-jsnow@redhat.com> +Patchwork-id: 81394 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 09/35] qcow2: add overlap check for bitmap directory +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Vladimir Sementsov-Ogievskiy + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-id: 20180705151515.779173-1-vsementsov@virtuozzo.com +Signed-off-by: Max Reitz +(cherry picked from commit 0e4e4318eaa56c831001bdf617094807ec6d451c) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + block/qcow2-bitmap.c | 7 ++++++- + block/qcow2-refcount.c | 10 ++++++++++ + block/qcow2.c | 22 ++++++++++++++-------- + block/qcow2.h | 45 ++++++++++++++++++++++++--------------------- + qapi/block-core.json | 21 ++++++++++++--------- + 5 files changed, 66 insertions(+), 39 deletions(-) + +diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c +index 3e4e4e4..14050eb 100644 +--- a/block/qcow2-bitmap.c ++++ b/block/qcow2-bitmap.c +@@ -775,7 +775,12 @@ static int bitmap_list_store(BlockDriverState *bs, Qcow2BitmapList *bm_list, + } + } + +- ret = qcow2_pre_write_overlap_check(bs, 0, dir_offset, dir_size); ++ /* Actually, even in in-place case ignoring QCOW2_OL_BITMAP_DIRECTORY is not ++ * necessary, because we drop QCOW2_AUTOCLEAR_BITMAPS when updating bitmap ++ * directory in-place (actually, turn-off the extension), which is checked ++ * in qcow2_check_metadata_overlap() */ ++ ret = qcow2_pre_write_overlap_check( ++ bs, in_place ? QCOW2_OL_BITMAP_DIRECTORY : 0, dir_offset, dir_size); + if (ret < 0) { + goto fail; + } +diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c +index 4e14c0a..1307069 100644 +--- a/block/qcow2-refcount.c ++++ b/block/qcow2-refcount.c +@@ -2705,6 +2705,16 @@ int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset, + } + } + ++ if ((chk & QCOW2_OL_BITMAP_DIRECTORY) && ++ (s->autoclear_features & QCOW2_AUTOCLEAR_BITMAPS)) ++ { ++ if (overlaps_with(s->bitmap_directory_offset, ++ s->bitmap_directory_size)) ++ { ++ return QCOW2_OL_BITMAP_DIRECTORY; ++ } ++ } ++ + return 0; + } + +diff --git a/block/qcow2.c b/block/qcow2.c +index 71fbfcd..c5341a4 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -676,6 +676,11 @@ static QemuOptsList qcow2_runtime_opts = { + .help = "Check for unintended writes into an inactive L2 table", + }, + { ++ .name = QCOW2_OPT_OVERLAP_BITMAP_DIRECTORY, ++ .type = QEMU_OPT_BOOL, ++ .help = "Check for unintended writes into the bitmap directory", ++ }, ++ { + .name = QCOW2_OPT_CACHE_SIZE, + .type = QEMU_OPT_SIZE, + .help = "Maximum combined metadata (L2 tables and refcount blocks) " +@@ -708,14 +713,15 @@ static QemuOptsList qcow2_runtime_opts = { + }; + + static const char *overlap_bool_option_names[QCOW2_OL_MAX_BITNR] = { +- [QCOW2_OL_MAIN_HEADER_BITNR] = QCOW2_OPT_OVERLAP_MAIN_HEADER, +- [QCOW2_OL_ACTIVE_L1_BITNR] = QCOW2_OPT_OVERLAP_ACTIVE_L1, +- [QCOW2_OL_ACTIVE_L2_BITNR] = QCOW2_OPT_OVERLAP_ACTIVE_L2, +- [QCOW2_OL_REFCOUNT_TABLE_BITNR] = QCOW2_OPT_OVERLAP_REFCOUNT_TABLE, +- [QCOW2_OL_REFCOUNT_BLOCK_BITNR] = QCOW2_OPT_OVERLAP_REFCOUNT_BLOCK, +- [QCOW2_OL_SNAPSHOT_TABLE_BITNR] = QCOW2_OPT_OVERLAP_SNAPSHOT_TABLE, +- [QCOW2_OL_INACTIVE_L1_BITNR] = QCOW2_OPT_OVERLAP_INACTIVE_L1, +- [QCOW2_OL_INACTIVE_L2_BITNR] = QCOW2_OPT_OVERLAP_INACTIVE_L2, ++ [QCOW2_OL_MAIN_HEADER_BITNR] = QCOW2_OPT_OVERLAP_MAIN_HEADER, ++ [QCOW2_OL_ACTIVE_L1_BITNR] = QCOW2_OPT_OVERLAP_ACTIVE_L1, ++ [QCOW2_OL_ACTIVE_L2_BITNR] = QCOW2_OPT_OVERLAP_ACTIVE_L2, ++ [QCOW2_OL_REFCOUNT_TABLE_BITNR] = QCOW2_OPT_OVERLAP_REFCOUNT_TABLE, ++ [QCOW2_OL_REFCOUNT_BLOCK_BITNR] = QCOW2_OPT_OVERLAP_REFCOUNT_BLOCK, ++ [QCOW2_OL_SNAPSHOT_TABLE_BITNR] = QCOW2_OPT_OVERLAP_SNAPSHOT_TABLE, ++ [QCOW2_OL_INACTIVE_L1_BITNR] = QCOW2_OPT_OVERLAP_INACTIVE_L1, ++ [QCOW2_OL_INACTIVE_L2_BITNR] = QCOW2_OPT_OVERLAP_INACTIVE_L2, ++ [QCOW2_OL_BITMAP_DIRECTORY_BITNR] = QCOW2_OPT_OVERLAP_BITMAP_DIRECTORY, + }; + + static void cache_clean_timer_cb(void *opaque) +diff --git a/block/qcow2.h b/block/qcow2.h +index b5e2aa3..d2c63e4 100644 +--- a/block/qcow2.h ++++ b/block/qcow2.h +@@ -98,6 +98,7 @@ + #define QCOW2_OPT_OVERLAP_SNAPSHOT_TABLE "overlap-check.snapshot-table" + #define QCOW2_OPT_OVERLAP_INACTIVE_L1 "overlap-check.inactive-l1" + #define QCOW2_OPT_OVERLAP_INACTIVE_L2 "overlap-check.inactive-l2" ++#define QCOW2_OPT_OVERLAP_BITMAP_DIRECTORY "overlap-check.bitmap-directory" + #define QCOW2_OPT_CACHE_SIZE "cache-size" + #define QCOW2_OPT_L2_CACHE_SIZE "l2-cache-size" + #define QCOW2_OPT_L2_CACHE_ENTRY_SIZE "l2-cache-entry-size" +@@ -401,34 +402,36 @@ typedef enum QCow2ClusterType { + } QCow2ClusterType; + + typedef enum QCow2MetadataOverlap { +- QCOW2_OL_MAIN_HEADER_BITNR = 0, +- QCOW2_OL_ACTIVE_L1_BITNR = 1, +- QCOW2_OL_ACTIVE_L2_BITNR = 2, +- QCOW2_OL_REFCOUNT_TABLE_BITNR = 3, +- QCOW2_OL_REFCOUNT_BLOCK_BITNR = 4, +- QCOW2_OL_SNAPSHOT_TABLE_BITNR = 5, +- QCOW2_OL_INACTIVE_L1_BITNR = 6, +- QCOW2_OL_INACTIVE_L2_BITNR = 7, +- +- QCOW2_OL_MAX_BITNR = 8, +- +- QCOW2_OL_NONE = 0, +- QCOW2_OL_MAIN_HEADER = (1 << QCOW2_OL_MAIN_HEADER_BITNR), +- QCOW2_OL_ACTIVE_L1 = (1 << QCOW2_OL_ACTIVE_L1_BITNR), +- QCOW2_OL_ACTIVE_L2 = (1 << QCOW2_OL_ACTIVE_L2_BITNR), +- QCOW2_OL_REFCOUNT_TABLE = (1 << QCOW2_OL_REFCOUNT_TABLE_BITNR), +- QCOW2_OL_REFCOUNT_BLOCK = (1 << QCOW2_OL_REFCOUNT_BLOCK_BITNR), +- QCOW2_OL_SNAPSHOT_TABLE = (1 << QCOW2_OL_SNAPSHOT_TABLE_BITNR), +- QCOW2_OL_INACTIVE_L1 = (1 << QCOW2_OL_INACTIVE_L1_BITNR), ++ QCOW2_OL_MAIN_HEADER_BITNR = 0, ++ QCOW2_OL_ACTIVE_L1_BITNR = 1, ++ QCOW2_OL_ACTIVE_L2_BITNR = 2, ++ QCOW2_OL_REFCOUNT_TABLE_BITNR = 3, ++ QCOW2_OL_REFCOUNT_BLOCK_BITNR = 4, ++ QCOW2_OL_SNAPSHOT_TABLE_BITNR = 5, ++ QCOW2_OL_INACTIVE_L1_BITNR = 6, ++ QCOW2_OL_INACTIVE_L2_BITNR = 7, ++ QCOW2_OL_BITMAP_DIRECTORY_BITNR = 8, ++ ++ QCOW2_OL_MAX_BITNR = 9, ++ ++ QCOW2_OL_NONE = 0, ++ QCOW2_OL_MAIN_HEADER = (1 << QCOW2_OL_MAIN_HEADER_BITNR), ++ QCOW2_OL_ACTIVE_L1 = (1 << QCOW2_OL_ACTIVE_L1_BITNR), ++ QCOW2_OL_ACTIVE_L2 = (1 << QCOW2_OL_ACTIVE_L2_BITNR), ++ QCOW2_OL_REFCOUNT_TABLE = (1 << QCOW2_OL_REFCOUNT_TABLE_BITNR), ++ QCOW2_OL_REFCOUNT_BLOCK = (1 << QCOW2_OL_REFCOUNT_BLOCK_BITNR), ++ QCOW2_OL_SNAPSHOT_TABLE = (1 << QCOW2_OL_SNAPSHOT_TABLE_BITNR), ++ QCOW2_OL_INACTIVE_L1 = (1 << QCOW2_OL_INACTIVE_L1_BITNR), + /* NOTE: Checking overlaps with inactive L2 tables will result in bdrv + * reads. */ +- QCOW2_OL_INACTIVE_L2 = (1 << QCOW2_OL_INACTIVE_L2_BITNR), ++ QCOW2_OL_INACTIVE_L2 = (1 << QCOW2_OL_INACTIVE_L2_BITNR), ++ QCOW2_OL_BITMAP_DIRECTORY = (1 << QCOW2_OL_BITMAP_DIRECTORY_BITNR), + } QCow2MetadataOverlap; + + /* Perform all overlap checks which can be done in constant time */ + #define QCOW2_OL_CONSTANT \ + (QCOW2_OL_MAIN_HEADER | QCOW2_OL_ACTIVE_L1 | QCOW2_OL_REFCOUNT_TABLE | \ +- QCOW2_OL_SNAPSHOT_TABLE) ++ QCOW2_OL_SNAPSHOT_TABLE | QCOW2_OL_BITMAP_DIRECTORY) + + /* Perform all overlap checks which don't require disk access */ + #define QCOW2_OL_CACHED \ +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 27ed91b..69e0cf8 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -2666,18 +2666,21 @@ + # @template: Specifies a template mode which can be adjusted using the other + # flags, defaults to 'cached' + # ++# @bitmap-directory: since 3.0 ++# + # Since: 2.9 + ## + { 'struct': 'Qcow2OverlapCheckFlags', +- 'data': { '*template': 'Qcow2OverlapCheckMode', +- '*main-header': 'bool', +- '*active-l1': 'bool', +- '*active-l2': 'bool', +- '*refcount-table': 'bool', +- '*refcount-block': 'bool', +- '*snapshot-table': 'bool', +- '*inactive-l1': 'bool', +- '*inactive-l2': 'bool' } } ++ 'data': { '*template': 'Qcow2OverlapCheckMode', ++ '*main-header': 'bool', ++ '*active-l1': 'bool', ++ '*active-l2': 'bool', ++ '*refcount-table': 'bool', ++ '*refcount-block': 'bool', ++ '*snapshot-table': 'bool', ++ '*inactive-l1': 'bool', ++ '*inactive-l2': 'bool', ++ '*bitmap-directory': 'bool' } } + + ## + # @Qcow2OverlapChecks: +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qcow2-don-t-permit-changing-encryption-parameters.patch b/SOURCES/kvm-qcow2-don-t-permit-changing-encryption-parameters.patch deleted file mode 100644 index 3f12d48..0000000 --- a/SOURCES/kvm-qcow2-don-t-permit-changing-encryption-parameters.patch +++ /dev/null @@ -1,46 +0,0 @@ -From e28736d3d0b2e1a8bf4e9d0bb9c6bca8d972b043 Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Wed, 29 Nov 2017 15:09:19 +0100 -Subject: [PATCH 01/36] qcow2: don't permit changing encryption parameters - -RH-Author: Daniel P. Berrange -Message-id: <20171129150920.8539-2-berrange@redhat.com> -Patchwork-id: 77973 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH 1/2] qcow2: don't permit changing encryption parameters -Bugzilla: 1406803 -RH-Acked-by: Max Reitz -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Kevin Wolf - -Currently if trying to change encryption parameters on a qcow2 image, qemu-img -will abort. We already explicitly check for attempt to change encrypt.format -but missed other parameters like encrypt.key-secret. Rather than list each -parameter, just blacklist changing of all parameters with a 'encrypt.' prefix. - -Signed-off-by: Daniel P. Berrange -Reviewed-by: Alberto Garcia -Reviewed-by: Eric Blake -Signed-off-by: Kevin Wolf -(cherry picked from commit f66afbe26f0c093d639610d70d16d7cc3183b652) -Signed-off-by: Miroslav Rezanina ---- - block/qcow2.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/block/qcow2.c b/block/qcow2.c -index b26cbbf..6e8f753 100644 ---- a/block/qcow2.c -+++ b/block/qcow2.c -@@ -4044,6 +4044,9 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, - error_report("Changing the encryption format is not supported"); - return -ENOTSUP; - } -+ } else if (g_str_has_prefix(desc->name, "encrypt.")) { -+ error_report("Changing the encryption parameters is not supported"); -+ return -ENOTSUP; - } else if (!strcmp(desc->name, BLOCK_OPT_CLUSTER_SIZE)) { - cluster_size = qemu_opt_get_size(opts, BLOCK_OPT_CLUSTER_SIZE, - cluster_size); --- -1.8.3.1 - diff --git a/SOURCES/kvm-qcow2-fix-image-corruption-after-committing-qcow2-im.patch b/SOURCES/kvm-qcow2-fix-image-corruption-after-committing-qcow2-im.patch deleted file mode 100644 index 37aaaf8..0000000 --- a/SOURCES/kvm-qcow2-fix-image-corruption-after-committing-qcow2-im.patch +++ /dev/null @@ -1,331 +0,0 @@ -From 97c8bc6029a1f88ee5bd737b2bf257139d533fea Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Wed, 29 Nov 2017 15:09:20 +0100 -Subject: [PATCH 02/36] qcow2: fix image corruption after committing qcow2 - image into base - -RH-Author: Daniel P. Berrange -Message-id: <20171129150920.8539-3-berrange@redhat.com> -Patchwork-id: 77975 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH 2/2] qcow2: fix image corruption after committing qcow2 image into base -Bugzilla: 1406803 -RH-Acked-by: Max Reitz -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Kevin Wolf - -After committing the qcow2 image contents into the base image, qemu-img -will call bdrv_make_empty to drop the payload in the layered image. - -When this is done for qcow2 images, it blows away the LUKS encryption -header, making the resulting image unusable. There are two codepaths -for emptying a qcow2 image, and the second (slower) codepath leaves -the LUKS header intact, so force use of that codepath. - -Reviewed-by: Eric Blake -Signed-off-by: Daniel P. Berrange -Signed-off-by: Kevin Wolf -(cherry picked from commit f06033295b51d4868c2b4921ad2287e8f55eb688) -Signed-off-by: Miroslav Rezanina - -Conflicts: - tests/qemu-iotests/group - some earlier tests don't exist yet ---- - block/qcow2.c | 6 +- - tests/qemu-iotests/198 | 104 ++++++++++++++++++++++++++++++++ - tests/qemu-iotests/198.out | 126 +++++++++++++++++++++++++++++++++++++++ - tests/qemu-iotests/common.filter | 4 +- - tests/qemu-iotests/group | 1 + - 5 files changed, 238 insertions(+), 3 deletions(-) - create mode 100755 tests/qemu-iotests/198 - create mode 100644 tests/qemu-iotests/198.out - -diff --git a/block/qcow2.c b/block/qcow2.c -index 6e8f753..a51efcc 100644 ---- a/block/qcow2.c -+++ b/block/qcow2.c -@@ -3567,12 +3567,14 @@ static int qcow2_make_empty(BlockDriverState *bs) - l1_clusters = DIV_ROUND_UP(s->l1_size, s->cluster_size / sizeof(uint64_t)); - - if (s->qcow_version >= 3 && !s->snapshots && -- 3 + l1_clusters <= s->refcount_block_size) { -+ 3 + l1_clusters <= s->refcount_block_size && -+ s->crypt_method_header != QCOW_CRYPT_LUKS) { - /* The following function only works for qcow2 v3 images (it requires - * the dirty flag) and only as long as there are no snapshots (because - * it completely empties the image). Furthermore, the L1 table and three - * additional clusters (image header, refcount table, one refcount -- * block) have to fit inside one refcount block. */ -+ * block) have to fit inside one refcount block. It cannot be used -+ * for LUKS (yet) as it throws away the LUKS header cluster(s) */ - return make_completely_empty(bs); - } - -diff --git a/tests/qemu-iotests/198 b/tests/qemu-iotests/198 -new file mode 100755 -index 0000000..34ef666 ---- /dev/null -+++ b/tests/qemu-iotests/198 -@@ -0,0 +1,104 @@ -+#!/bin/bash -+# -+# Test commit of encrypted qcow2 files -+# -+# Copyright (C) 2017 Red Hat, Inc. -+# -+# This program is free software; you can redistribute it and/or modify -+# it under the terms of the GNU General Public License as published by -+# the Free Software Foundation; either version 2 of the License, or -+# (at your option) any later version. -+# -+# This program is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with this program. If not, see . -+# -+ -+# creator -+owner=berrange@redhat.com -+ -+seq=`basename $0` -+echo "QA output created by $seq" -+ -+here=`pwd` -+status=1 # failure is the default! -+ -+_cleanup() -+{ -+ _cleanup_test_img -+} -+trap "_cleanup; exit \$status" 0 1 2 3 15 -+ -+# get standard environment, filters and checks -+. ./common.rc -+. ./common.filter -+ -+_supported_fmt qcow2 -+_supported_proto generic -+_supported_os Linux -+ -+ -+size=16M -+TEST_IMG_BASE=$TEST_IMG.base -+SECRET0="secret,id=sec0,data=astrochicken" -+SECRET1="secret,id=sec1,data=furby" -+ -+TEST_IMG_SAVE=$TEST_IMG -+TEST_IMG=$TEST_IMG_BASE -+echo "== create base ==" -+_make_test_img --object $SECRET0 -o "encrypt.format=luks,encrypt.key-secret=sec0,encrypt.iter-time=10" $size -+TEST_IMG=$TEST_IMG_SAVE -+ -+IMGSPECBASE="driver=$IMGFMT,file.filename=$TEST_IMG_BASE,encrypt.key-secret=sec0" -+IMGSPECLAYER="driver=$IMGFMT,file.filename=$TEST_IMG,encrypt.key-secret=sec1" -+IMGSPEC="$IMGSPECLAYER,backing.driver=$IMGFMT,backing.file.filename=$TEST_IMG_BASE,backing.encrypt.key-secret=sec0" -+QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT -+ -+echo -+echo "== writing whole image base ==" -+$QEMU_IO --object $SECRET0 -c "write -P 0xa 0 $size" --image-opts $IMGSPECBASE | _filter_qemu_io | _filter_testdir -+ -+echo "== create overlay ==" -+_make_test_img --object $SECRET1 -o "encrypt.format=luks,encrypt.key-secret=sec1,encrypt.iter-time=10" -u -b "$TEST_IMG_BASE" $size -+ -+echo -+echo "== writing whole image layer ==" -+$QEMU_IO --object $SECRET0 --object $SECRET1 -c "write -P 0x9 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir -+ -+echo -+echo "== verify pattern base ==" -+$QEMU_IO --object $SECRET0 -c "read -P 0xa 0 $size" --image-opts $IMGSPECBASE | _filter_qemu_io | _filter_testdir -+ -+echo -+echo "== verify pattern layer ==" -+$QEMU_IO --object $SECRET0 --object $SECRET1 -c "read -P 0x9 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir -+ -+echo -+echo "== committing layer into base ==" -+$QEMU_IMG commit --object $SECRET0 --object $SECRET1 --image-opts $IMGSPEC | _filter_testdir -+ -+echo -+echo "== verify pattern base ==" -+$QEMU_IO --object $SECRET0 -c "read -P 0x9 0 $size" --image-opts $IMGSPECBASE | _filter_qemu_io | _filter_testdir -+ -+echo -+echo "== verify pattern layer ==" -+$QEMU_IO --object $SECRET0 --object $SECRET1 -c "read -P 0x9 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir -+ -+echo -+echo "== checking image base ==" -+$QEMU_IMG info --image-opts $IMGSPECBASE | _filter_img_info | _filter_testdir | sed -e "/^disk size:/ D" -+ -+echo -+echo "== checking image layer ==" -+$QEMU_IMG info --image-opts $IMGSPECLAYER | _filter_img_info | _filter_testdir | sed -e "/^disk size:/ D" -+ -+ -+# success, all done -+echo "*** done" -+rm -f $seq.full -+status=0 -diff --git a/tests/qemu-iotests/198.out b/tests/qemu-iotests/198.out -new file mode 100644 -index 0000000..2db565e ---- /dev/null -+++ b/tests/qemu-iotests/198.out -@@ -0,0 +1,126 @@ -+QA output created by 198 -+== create base == -+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=16777216 encrypt.format=luks encrypt.key-secret=sec0 encrypt.iter-time=10 -+ -+== writing whole image base == -+wrote 16777216/16777216 bytes at offset 0 -+16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+== create overlay == -+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216 backing_file=TEST_DIR/t.IMGFMT.base encrypt.format=luks encrypt.key-secret=sec1 encrypt.iter-time=10 -+ -+== writing whole image layer == -+wrote 16777216/16777216 bytes at offset 0 -+16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+== verify pattern base == -+read 16777216/16777216 bytes at offset 0 -+16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+== verify pattern layer == -+read 16777216/16777216 bytes at offset 0 -+16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+== committing layer into base == -+Image committed. -+ -+== verify pattern base == -+read 16777216/16777216 bytes at offset 0 -+16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+== verify pattern layer == -+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"}} -+file format: IMGFMT -+virtual size: 16M (16777216 bytes) -+Format specific information: -+ compat: 1.1 -+ lazy refcounts: false -+ refcount bits: 16 -+ encrypt: -+ ivgen alg: plain64 -+ hash alg: sha256 -+ cipher alg: aes-256 -+ uuid: 00000000-0000-0000-0000-000000000000 -+ format: luks -+ cipher mode: xts -+ slots: -+ [0]: -+ active: true -+ iters: 1024 -+ key offset: 4096 -+ stripes: 4000 -+ [1]: -+ active: false -+ key offset: 262144 -+ [2]: -+ active: false -+ key offset: 520192 -+ [3]: -+ active: false -+ key offset: 778240 -+ [4]: -+ active: false -+ key offset: 1036288 -+ [5]: -+ active: false -+ key offset: 1294336 -+ [6]: -+ active: false -+ key offset: 1552384 -+ [7]: -+ active: false -+ key offset: 1810432 -+ payload offset: 2068480 -+ master key iters: 1024 -+ corrupt: false -+ -+== checking image layer == -+image: json:{"encrypt.key-secret": "sec1", "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}} -+file format: IMGFMT -+virtual size: 16M (16777216 bytes) -+backing file: TEST_DIR/t.IMGFMT.base -+Format specific information: -+ compat: 1.1 -+ lazy refcounts: false -+ refcount bits: 16 -+ encrypt: -+ ivgen alg: plain64 -+ hash alg: sha256 -+ cipher alg: aes-256 -+ uuid: 00000000-0000-0000-0000-000000000000 -+ format: luks -+ cipher mode: xts -+ slots: -+ [0]: -+ active: true -+ iters: 1024 -+ key offset: 4096 -+ stripes: 4000 -+ [1]: -+ active: false -+ key offset: 262144 -+ [2]: -+ active: false -+ key offset: 520192 -+ [3]: -+ active: false -+ key offset: 778240 -+ [4]: -+ active: false -+ key offset: 1036288 -+ [5]: -+ active: false -+ key offset: 1294336 -+ [6]: -+ active: false -+ key offset: 1552384 -+ [7]: -+ active: false -+ key offset: 1810432 -+ payload offset: 2068480 -+ master key iters: 1024 -+ corrupt: false -+*** done -diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter -index 9d5442e..b0140d8 100644 ---- a/tests/qemu-iotests/common.filter -+++ b/tests/qemu-iotests/common.filter -@@ -150,7 +150,9 @@ _filter_img_info() - -e "/lazy_refcounts: \\(on\\|off\\)/d" \ - -e "/block_size: [0-9]\\+/d" \ - -e "/block_state_zero: \\(on\\|off\\)/d" \ -- -e "/log_size: [0-9]\\+/d" -+ -e "/log_size: [0-9]\\+/d" \ -+ -e "s/iters: [0-9]\\+/iters: 1024/" \ -+ -e "s/uuid: [-a-f0-9]\\+/uuid: 00000000-0000-0000-0000-000000000000/" - } - - # filter out offsets and file names from qemu-img map; good for both -diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group -index 0c2bda3..13760b3 100644 ---- a/tests/qemu-iotests/group -+++ b/tests/qemu-iotests/group -@@ -188,3 +188,4 @@ - 190 rw auto quick - 192 rw auto quick - 194 rw auto migration quick -+198 rw auto --- -1.8.3.1 - diff --git a/SOURCES/kvm-qcow2-fix-return-error-code-in-qcow2_truncate.patch b/SOURCES/kvm-qcow2-fix-return-error-code-in-qcow2_truncate.patch deleted file mode 100644 index 9a098ff..0000000 --- a/SOURCES/kvm-qcow2-fix-return-error-code-in-qcow2_truncate.patch +++ /dev/null @@ -1,55 +0,0 @@ -From cf6287bc4212ad744d04e72ccdd015b9d9552e23 Mon Sep 17 00:00:00 2001 -From: Max Reitz -Date: Mon, 27 Nov 2017 16:19:56 +0100 -Subject: [PATCH 01/21] qcow2: fix return error code in qcow2_truncate() - -RH-Author: Max Reitz -Message-id: <20171127161959.13234-2-mreitz@redhat.com> -Patchwork-id: 77912 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH 1/4] qcow2: fix return error code in qcow2_truncate() -Bugzilla: 1414049 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Fam Zheng -RH-Acked-by: John Snow - -From: Pavel Butsykin - -Signed-off-by: Pavel Butsykin -Reviewed-by: Eric Blake -Reviewed-by: John Snow -Reviewed-by: Max Reitz -Message-id: 20170929121613.25997-2-pbutsykin@virtuozzo.com -Signed-off-by: Max Reitz -(cherry picked from commit 76a2a30a99c670e9ec1b4a5d976868059c6bc258) -Signed-off-by: Max Reitz -Signed-off-by: Miroslav Rezanina ---- - block/qcow2.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/block/qcow2.c b/block/qcow2.c -index 40ba26c..af7b1e7 100644 ---- a/block/qcow2.c -+++ b/block/qcow2.c -@@ -3159,7 +3159,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, - if (old_file_size < 0) { - error_setg_errno(errp, -old_file_size, - "Failed to inquire current file length"); -- return ret; -+ return old_file_size; - } - - nb_new_data_clusters = DIV_ROUND_UP(offset - old_length, -@@ -3188,7 +3188,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, - if (allocation_start < 0) { - error_setg_errno(errp, -allocation_start, - "Failed to resize refcount structures"); -- return -allocation_start; -+ return allocation_start; - } - - clusters_allocated = qcow2_alloc_clusters_at(bs, allocation_start, --- -1.8.3.1 - diff --git a/SOURCES/kvm-qdev-add-HotplugHandler-post_plug-callback.patch b/SOURCES/kvm-qdev-add-HotplugHandler-post_plug-callback.patch new file mode 100644 index 0000000..2609722 --- /dev/null +++ b/SOURCES/kvm-qdev-add-HotplugHandler-post_plug-callback.patch @@ -0,0 +1,109 @@ +From 5cdd4dfafc5280d312001371c6917ccaf2ba06c3 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Tue, 24 Jul 2018 15:13:07 +0200 +Subject: [PATCH 08/15] qdev: add HotplugHandler->post_plug() callback + +RH-Author: Stefan Hajnoczi +Message-id: <20180724151308.20500-2-stefanha@redhat.com> +Patchwork-id: 81485 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/2] qdev: add HotplugHandler->post_plug() callback +Bugzilla: 1607891 +RH-Acked-by: Igor Mammedov +RH-Acked-by: Pankaj Gupta +RH-Acked-by: Cornelia Huck + +The ->pre_plug() callback is invoked before the device is realized. The +->plug() callback is invoked when the device is being realized but +before it is reset. + +This patch adds a ->post_plug() callback which is invoked after the +device has been reset. This callback is needed by HotplugHandlers that +need to wait until after ->reset(). + +Signed-off-by: Stefan Hajnoczi +Message-Id: <20180716083732.3347-2-stefanha@redhat.com> +Signed-off-by: Paolo Bonzini +(cherry picked from commit 25e8978817a54745c44d956d8303e6be6f2c4047) +Signed-off-by: Stefan Hajnoczi +Signed-off-by: Miroslav Rezanina +--- + hw/core/hotplug.c | 10 ++++++++++ + hw/core/qdev.c | 4 ++++ + include/hw/hotplug.h | 11 +++++++++++ + 3 files changed, 25 insertions(+) + +diff --git a/hw/core/hotplug.c b/hw/core/hotplug.c +index 17ac986..2253072 100644 +--- a/hw/core/hotplug.c ++++ b/hw/core/hotplug.c +@@ -35,6 +35,16 @@ void hotplug_handler_plug(HotplugHandler *plug_handler, + } + } + ++void hotplug_handler_post_plug(HotplugHandler *plug_handler, ++ DeviceState *plugged_dev) ++{ ++ HotplugHandlerClass *hdc = HOTPLUG_HANDLER_GET_CLASS(plug_handler); ++ ++ if (hdc->post_plug) { ++ hdc->post_plug(plug_handler, plugged_dev); ++ } ++} ++ + void hotplug_handler_unplug_request(HotplugHandler *plug_handler, + DeviceState *plugged_dev, + Error **errp) +diff --git a/hw/core/qdev.c b/hw/core/qdev.c +index ce7c316..24f1ae7 100644 +--- a/hw/core/qdev.c ++++ b/hw/core/qdev.c +@@ -893,6 +893,10 @@ static void device_set_realized(Object *obj, bool value, Error **errp) + device_reset(dev); + } + dev->pending_deleted_event = false; ++ ++ if (hotplug_ctrl) { ++ hotplug_handler_post_plug(hotplug_ctrl, dev); ++ } + } else if (!value && dev->realized) { + Error **local_errp = NULL; + QLIST_FOREACH(bus, &dev->child_bus, sibling) { +diff --git a/include/hw/hotplug.h b/include/hw/hotplug.h +index 1a0516a..51541d6 100644 +--- a/include/hw/hotplug.h ++++ b/include/hw/hotplug.h +@@ -47,6 +47,8 @@ typedef void (*hotplug_fn)(HotplugHandler *plug_handler, + * @parent: Opaque parent interface. + * @pre_plug: pre plug callback called at start of device.realize(true) + * @plug: plug callback called at end of device.realize(true). ++ * @post_plug: post plug callback called after device.realize(true) and device ++ * reset + * @unplug_request: unplug request callback. + * Used as a means to initiate device unplug for devices that + * require asynchronous unplug handling. +@@ -61,6 +63,7 @@ typedef struct HotplugHandlerClass { + /* */ + hotplug_fn pre_plug; + hotplug_fn plug; ++ void (*post_plug)(HotplugHandler *plug_handler, DeviceState *plugged_dev); + hotplug_fn unplug_request; + hotplug_fn unplug; + } HotplugHandlerClass; +@@ -84,6 +87,14 @@ void hotplug_handler_pre_plug(HotplugHandler *plug_handler, + Error **errp); + + /** ++ * hotplug_handler_post_plug: ++ * ++ * Call #HotplugHandlerClass.post_plug callback of @plug_handler. ++ */ ++void hotplug_handler_post_plug(HotplugHandler *plug_handler, ++ DeviceState *plugged_dev); ++ ++/** + * hotplug_handler_unplug_request: + * + * Calls #HotplugHandlerClass.unplug_request callback of @plug_handler. +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qdev-defer-DEVICE_DEL-event-until-instance_finalize.patch b/SOURCES/kvm-qdev-defer-DEVICE_DEL-event-until-instance_finalize.patch deleted file mode 100644 index 6462807..0000000 --- a/SOURCES/kvm-qdev-defer-DEVICE_DEL-event-until-instance_finalize.patch +++ /dev/null @@ -1,111 +0,0 @@ -From 13bceabad00d232b71f34bc62b6bbda3f7279601 Mon Sep 17 00:00:00 2001 -From: Serhii Popovych -Date: Thu, 9 Nov 2017 15:30:05 +0100 -Subject: [PATCH 5/7] qdev: defer DEVICE_DEL event until instance_finalize() - -RH-Author: Serhii Popovych -Message-id: <1510241405-20597-4-git-send-email-spopovyc@redhat.com> -Patchwork-id: 77631 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 3/3] qdev: defer DEVICE_DEL event until instance_finalize() -Bugzilla: 1445460 -RH-Acked-by: David Gibson -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier - -From: Michael Roth - -DEVICE_DEL is currently emitted when a Device is unparented, as -opposed to when it is finalized. The main design motivation for this -seems to be that after unparent()/unrealize(), the Device is no -longer visible to the guest, and thus the operation is complete -from the perspective of management. - -However, there are cases where remaining host-side cleanup is also -pertinent to management. The is generally handled by treating these -resources as aspects of the "backend", which can be managed via -separate interfaces/events, such as blockdev_add/del, netdev_add/del, -object_add/del, etc, but some devices do not have this level of -compartmentalization, namely vfio-pci, and possibly to lend themselves -well to it. - -In the case of vfio-pci, the "backend" cleanup happens as part of -the finalization of the vfio-pci device itself, in particular the -cleanup of the VFIO group FD. Failing to wait for this cleanup can -result in tools like libvirt attempting to rebind the device to -the host while it's still being used by VFIO, which can result in -host crashes or other misbehavior depending on the host driver. - -Deferring DEVICE_DEL still affords us the ability to manage backends -explicitly, while also addressing cases like vfio-pci's, so we -implement that approach here. - -An alternative proposal involving having VFIO emit a separate event -to denote completion of host-side cleanup was discussed, but the -prevailing opinion seems to be that it is not worth the added -complexity, and leaves the issue open for other Device implementations -to solve in the future. - -Signed-off-by: Michael Roth -Reviewed-by: Greg Kurz -Tested-by: Eric Auger -Reviewed-by: David Gibson -Message-Id: <20171016222315.407-4-mdroth@linux.vnet.ibm.com> -Signed-off-by: Paolo Bonzini -(cherry picked from commit f7b879e072ae6839b1b1d1312f48fa7f256397e2) -Signed-off-by: Serhii Popovych -Signed-off-by: Miroslav Rezanina ---- - hw/core/qdev.c | 23 ++++++++++++----------- - 1 file changed, 12 insertions(+), 11 deletions(-) - -diff --git a/hw/core/qdev.c b/hw/core/qdev.c -index 418cdac..1111295 100644 ---- a/hw/core/qdev.c -+++ b/hw/core/qdev.c -@@ -1069,7 +1069,6 @@ static void device_finalize(Object *obj) - NamedGPIOList *ngl, *next; - - DeviceState *dev = DEVICE(obj); -- qemu_opts_del(dev->opts); - - QLIST_FOREACH_SAFE(ngl, &dev->gpios, node, next) { - QLIST_REMOVE(ngl, node); -@@ -1080,6 +1079,18 @@ static void device_finalize(Object *obj) - * here - */ - } -+ -+ /* Only send event if the device had been completely realized */ -+ if (dev->pending_deleted_event) { -+ g_assert(dev->canonical_path); -+ -+ qapi_event_send_device_deleted(!!dev->id, dev->id, dev->canonical_path, -+ &error_abort); -+ g_free(dev->canonical_path); -+ dev->canonical_path = NULL; -+ } -+ -+ qemu_opts_del(dev->opts); - } - - static void device_class_base_init(ObjectClass *class, void *data) -@@ -1109,16 +1120,6 @@ static void device_unparent(Object *obj) - object_unref(OBJECT(dev->parent_bus)); - dev->parent_bus = NULL; - } -- -- /* Only send event if the device had been completely realized */ -- if (dev->pending_deleted_event) { -- g_assert(dev->canonical_path); -- -- qapi_event_send_device_deleted(!!dev->id, dev->id, dev->canonical_path, -- &error_abort); -- g_free(dev->canonical_path); -- dev->canonical_path = NULL; -- } - } - - static void device_class_init(ObjectClass *class, void *data) --- -1.8.3.1 - diff --git a/SOURCES/kvm-qdev-store-DeviceState-s-canonical-path-to-use-when-.patch b/SOURCES/kvm-qdev-store-DeviceState-s-canonical-path-to-use-when-.patch deleted file mode 100644 index 3773609..0000000 --- a/SOURCES/kvm-qdev-store-DeviceState-s-canonical-path-to-use-when-.patch +++ /dev/null @@ -1,125 +0,0 @@ -From a6dae62ef051773c0198f8ebd47a79d8f1157000 Mon Sep 17 00:00:00 2001 -From: Serhii Popovych -Date: Thu, 9 Nov 2017 15:30:03 +0100 -Subject: [PATCH 3/7] qdev: store DeviceState's canonical path to use when - unparenting - -RH-Author: Serhii Popovych -Message-id: <1510241405-20597-2-git-send-email-spopovyc@redhat.com> -Patchwork-id: 77632 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 1/3] qdev: store DeviceState's canonical path to use when unparenting -Bugzilla: 1445460 -RH-Acked-by: David Gibson -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier - -From: Michael Roth - -device_unparent(dev, ...) is called when a device is unparented, -either directly, or as a result of a parent device being -finalized, and handles some final cleanup for the device. Part -of this includes emiting a DEVICE_DELETED QMP event to notify -management, which includes the device's path in the composition -tree as provided by object_get_canonical_path(). - -object_get_canonical_path() assumes the device is still connected -to the machine/root container, and will assert otherwise, but -in some situations this isn't the case: - -If the parent is finalized as a result of object_unparent(), it -will still be attached to the composition tree at the time any -children are unparented as a result of that same call to -object_unparent(). However, in some cases, object_unparent() -will complete without finalizing the parent device, due to -lingering references that won't be released till some time later. -One such example is if the parent has MemoryRegion children (which -take a ref on their parent), who in turn have AddressSpace's (which -take a ref on their regions), since those AddressSpaces get cleaned -up asynchronously by the RCU thread. - -In this case qdev:device_unparent() may be called for a child Device -that no longer has a path to the root/machine container, causing -object_get_canonical_path() to assert. - -Fix this by storing the canonical path during realize() so the -information will still be available for device_unparent() in such -cases. - -Cc: Michael S. Tsirkin -Cc: Paolo Bonzini -Signed-off-by: Michael Roth -Signed-off-by: Greg Kurz -Signed-off-by: Michael Roth -Tested-by: Eric Auger -Reviewed-by: David Gibson -Message-Id: <20171016222315.407-2-mdroth@linux.vnet.ibm.com> -[Clear dev->canonical_path at the post_realize_fail label, which is - cleaner. Suggested by David Gibson. - Paolo] -Signed-off-by: Paolo Bonzini - -(cherry picked from commit 04162f8f4bcf8c9ae2422def4357289b44208c8c) -Signed-off-by: Serhii Popovych -Signed-off-by: Miroslav Rezanina ---- - hw/core/qdev.c | 17 ++++++++++++++--- - include/hw/qdev-core.h | 1 + - 2 files changed, 15 insertions(+), 3 deletions(-) - -diff --git a/hw/core/qdev.c b/hw/core/qdev.c -index 606ab53..0019a49 100644 ---- a/hw/core/qdev.c -+++ b/hw/core/qdev.c -@@ -928,6 +928,13 @@ static void device_set_realized(Object *obj, bool value, Error **errp) - goto post_realize_fail; - } - -+ /* -+ * always free/re-initialize here since the value cannot be cleaned up -+ * in device_unrealize due to its usage later on in the unplug path -+ */ -+ g_free(dev->canonical_path); -+ 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, - dev->instance_id_alias, -@@ -984,6 +991,8 @@ child_realize_fail: - } - - post_realize_fail: -+ g_free(dev->canonical_path); -+ dev->canonical_path = NULL; - if (dc->unrealize) { - dc->unrealize(dev, NULL); - } -@@ -1102,10 +1111,12 @@ static void device_unparent(Object *obj) - - /* Only send event if the device had been completely realized */ - if (dev->pending_deleted_event) { -- gchar *path = object_get_canonical_path(OBJECT(dev)); -+ g_assert(dev->canonical_path); - -- qapi_event_send_device_deleted(!!dev->id, dev->id, path, &error_abort); -- g_free(path); -+ qapi_event_send_device_deleted(!!dev->id, dev->id, dev->canonical_path, -+ &error_abort); -+ g_free(dev->canonical_path); -+ dev->canonical_path = NULL; - } - - qemu_opts_del(dev->opts); -diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h -index ae31728..9237b68 100644 ---- a/include/hw/qdev-core.h -+++ b/include/hw/qdev-core.h -@@ -153,6 +153,7 @@ struct DeviceState { - /*< public >*/ - - const char *id; -+ char *canonical_path; - bool realized; - bool pending_deleted_event; - QemuOpts *opts; --- -1.8.3.1 - diff --git a/SOURCES/kvm-qemu-doc-Add-UUID-support-in-initiator-name.patch b/SOURCES/kvm-qemu-doc-Add-UUID-support-in-initiator-name.patch deleted file mode 100644 index 84a8d61..0000000 --- a/SOURCES/kvm-qemu-doc-Add-UUID-support-in-initiator-name.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 09899daebbc5b41e11de57442939e5b71ac28085 Mon Sep 17 00:00:00 2001 -From: Fam Zheng -Date: Thu, 30 Nov 2017 09:25:40 +0100 -Subject: [PATCH 03/36] qemu-doc: Add UUID support in initiator name - -RH-Author: Fam Zheng -Message-id: <20171130092544.19231-2-famz@redhat.com> -Patchwork-id: 78017 -O-Subject: [RHV7.5 qemu-kvm-ma PATCH 1/5] qemu-doc: Add UUID support in initiator name -Bugzilla: 1494210 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Jeffrey Cody -RH-Acked-by: John Snow - -From: Fred Rolland - -Update doc with the usage of UUID for initiator name. - -Related-To: https://bugzilla.redhat.com/1006468 -Signed-off-by: Fred Rolland -Message-id: 20170823084830.30500-1-frolland@redhat.com -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit fb9429ddc124c46731185b2781804d4fd39b658c) -Signed-off-by: Fam Zheng -Signed-off-by: Miroslav Rezanina - -Conflicts: - qemu-doc.texi -We use "qemu-kvm" in the text instead of "qemu" in downstream. ---- - qemu-doc.texi | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/qemu-doc.texi b/qemu-doc.texi -index da0e513..db09b7e 100644 ---- a/qemu-doc.texi -+++ b/qemu-doc.texi -@@ -1066,10 +1066,11 @@ in a configuration file provided via '-readconfig' or directly on the - command line. - - If the initiator-name is not specified qemu-kvm will use a default name --of 'iqn.2008-11.org.linux-kvm[:'] where is the name of the -+of 'iqn.2008-11.org.linux-kvm[:'] where is the UUID of the -+virtual machine. If the UUID is not specified qemu will use -+'iqn.2008-11.org.linux-kvm[:'] where is the name of the - virtual machine. - -- - @example - Setting a specific initiator name to use when logging in to the target - -iscsi initiator-name=iqn.qemu.test:my-initiator --- -1.8.3.1 - diff --git a/SOURCES/kvm-qemu-img-Add-C-option-for-convert-with-copy-offloadi.patch b/SOURCES/kvm-qemu-img-Add-C-option-for-convert-with-copy-offloadi.patch new file mode 100644 index 0000000..b9d59f9 --- /dev/null +++ b/SOURCES/kvm-qemu-img-Add-C-option-for-convert-with-copy-offloadi.patch @@ -0,0 +1,147 @@ +From 2d72f0886af14ab032974dd228e1c55e1501f117 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Wed, 1 Aug 2018 06:35:37 +0200 +Subject: [PATCH 01/13] qemu-img: Add -C option for convert with copy + offloading + +RH-Author: Fam Zheng +Message-id: <20180801063538.32582-2-famz@redhat.com> +Patchwork-id: 81560 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/2] qemu-img: Add -C option for convert with copy offloading +Bugzilla: 1607774 +RH-Acked-by: Kevin Wolf +RH-Acked-by: John Snow +RH-Acked-by: Miroslav Rezanina + +Signed-off-by: Fam Zheng +Signed-off-by: Kevin Wolf +(cherry picked from commit e11ce12f5eb26438419e486a3ae2c9bb58a23c1f) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina + +Conflicts: + + qemu-img-cmds.hx + qemu-img.texi + qemu-img.c + +All contextual conflicts. + +1) Downstream doesn't have 46e8d272ba (qemu-img: Remove deprecated -s +snapshot_id_or_name option). +2) Downstream doesn't have 88481329c0 (qemu-img: allow compressed +not-in-order writes). +--- + qemu-img-cmds.hx | 2 +- + qemu-img.c | 21 +++++++++++++++++---- + qemu-img.texi | 8 +++++++- + 3 files changed, 25 insertions(+), 6 deletions(-) + +diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx +index 2fe3189..48815c0 100644 +--- a/qemu-img-cmds.hx ++++ b/qemu-img-cmds.hx +@@ -41,7 +41,7 @@ STEXI + ETEXI + + DEF("convert", img_convert, +- "convert [--object objectdef] [--image-opts] [--target-image-opts] [-U] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-B backing_file] [-o options] [-s snapshot_id_or_name] [-l snapshot_param] [-S sparse_size] [-m num_coroutines] [-W] filename [filename2 [...]] output_filename") ++ "convert [--object objectdef] [--image-opts] [--target-image-opts] [-U] [-C] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-B backing_file] [-o options] [-s snapshot_id_or_name] [-l snapshot_param] [-S sparse_size] [-m num_coroutines] [-W] filename [filename2 [...]] output_filename") + STEXI + @item convert [--object @var{objectdef}] [--image-opts] [--target-image-opts] [-U] [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-B @var{backing_file}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-S @var{sparse_size}] [-m @var{num_coroutines}] [-W] @var{filename} [@var{filename2} [...]] @var{output_filename} + ETEXI +diff --git a/qemu-img.c b/qemu-img.c +index eaee6d6..c9ccc1e 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -2000,11 +2000,12 @@ static int img_convert(int argc, char **argv) + skip_create = false, progress = false, tgt_image_opts = false; + int64_t ret = -EINVAL; + bool force_share = false; ++ bool explict_min_sparse = false; + + ImgConvertState s = (ImgConvertState) { + /* Need at least 4k of zeros for sparse detection */ + .min_sparse = 8, +- .copy_range = true, ++ .copy_range = false, + .buf_sectors = IO_BUF_SIZE / BDRV_SECTOR_SIZE, + .wr_in_order = true, + .num_coroutines = 8, +@@ -2019,7 +2020,7 @@ static int img_convert(int argc, char **argv) + {"target-image-opts", no_argument, 0, OPTION_TARGET_IMAGE_OPTS}, + {0, 0, 0, 0} + }; +- c = getopt_long(argc, argv, ":hf:O:B:co:s:l:S:pt:T:qnm:WU", ++ c = getopt_long(argc, argv, ":hf:O:B:Cco:s:l:S:pt:T:qnm:WU", + long_options, NULL); + if (c == -1) { + break; +@@ -2043,9 +2044,11 @@ static int img_convert(int argc, char **argv) + case 'B': + out_baseimg = optarg; + break; ++ case 'C': ++ s.copy_range = true; ++ break; + case 'c': + s.compressed = true; +- s.copy_range = false; + break; + case 'o': + if (!is_valid_option_list(optarg)) { +@@ -2087,7 +2090,7 @@ static int img_convert(int argc, char **argv) + } + + s.min_sparse = sval / BDRV_SECTOR_SIZE; +- s.copy_range = false; ++ explict_min_sparse = true; + break; + } + case 'p': +@@ -2152,6 +2155,16 @@ static int img_convert(int argc, char **argv) + goto fail_getopt; + } + ++ if (s.compressed && s.copy_range) { ++ error_report("Cannot enable copy offloading when -c is used"); ++ goto fail_getopt; ++ } ++ ++ if (explict_min_sparse && s.copy_range) { ++ error_report("Cannot enable copy offloading when -S is used"); ++ goto fail_getopt; ++ } ++ + if (tgt_image_opts && !skip_create) { + error_report("--target-image-opts requires use of -n flag"); + goto fail_getopt; +diff --git a/qemu-img.texi b/qemu-img.texi +index 8a26400..74d7290 100644 +--- a/qemu-img.texi ++++ b/qemu-img.texi +@@ -172,6 +172,12 @@ Number of parallel coroutines for the convert process + Allow out-of-order writes to the destination. This option improves performance, + but is only recommended for preallocated devices like host devices or other + raw block devices. ++@item -C ++Try to use copy offloading to move data from source image to target. This may ++improve performance if the data is remote, such as with NFS or iSCSI backends, ++but will not automatically sparsify zero sectors, and may result in a fully ++allocated target image depending on the host support for getting allocation ++information. + @end table + + Parameters to dd subcommand: +@@ -340,7 +346,7 @@ Error on reading data + + @end table + +-@item convert [-c] [-p] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-B @var{backing_file}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-m @var{num_coroutines}] [-W] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename} ++@item convert [-C] [-c] [-p] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-B @var{backing_file}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-m @var{num_coroutines}] [-W] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename} + + Convert the disk image @var{filename} or a snapshot @var{snapshot_param}(@var{snapshot_id_or_name} is deprecated) + to disk image @var{output_filename} using format @var{output_fmt}. It can be optionally compressed (@code{-c} +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-img-Add-print_amend_option_help.patch b/SOURCES/kvm-qemu-img-Add-print_amend_option_help.patch new file mode 100644 index 0000000..7bc0118 --- /dev/null +++ b/SOURCES/kvm-qemu-img-Add-print_amend_option_help.patch @@ -0,0 +1,238 @@ +From dfc5e2a61a96cf4f727d2e7b4f41124933746f6d Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 14:59:40 +0200 +Subject: [PATCH 06/89] qemu-img: Add print_amend_option_help() + +RH-Author: Max Reitz +Message-id: <20180618145943.4489-5-mreitz@redhat.com> +Patchwork-id: 80753 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 4/7] qemu-img: Add print_amend_option_help() +Bugzilla: 1537956 +RH-Acked-by: John Snow +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi + +The more generic print_block_option_help() function is not really +suitable for qemu-img amend, for a couple of reasons: +(1) We do not need to append the protocol-level options, as amendment + happens only on one node and does not descend downwards to its + children. +(2) print_block_option_help() says those options are "supported". For + option amendment, we do not really know that. So this new function + explicitly says that those options are the creation options, and not + all of them may be supported. +(3) If the driver does not support option amendment, we should not print + anything (except for an error message that amendment is not + supported). + +Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1537956 +Signed-off-by: Max Reitz +Reviewed-by: John Snow +Reviewed-by: Eric Blake +Message-id: 20180509210023.20283-5-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit 51641351420e4f9dc6613d0dd03a5f0f214ed5b6) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + qemu-img.c | 30 ++++++++++++++++++++++++++++-- + tests/qemu-iotests/082.out | 44 +++++++++++++++++++++++++++----------------- + 2 files changed, 55 insertions(+), 19 deletions(-) + +diff --git a/qemu-img.c b/qemu-img.c +index cdeb01b..d4cbb63 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -3609,6 +3609,32 @@ static void amend_status_cb(BlockDriverState *bs, + qemu_progress_print(100.f * offset / total_work_size, 0); + } + ++static int print_amend_option_help(const char *format) ++{ ++ BlockDriver *drv; ++ ++ /* Find driver and parse its options */ ++ drv = bdrv_find_format(format); ++ if (!drv) { ++ error_report("Unknown file format '%s'", format); ++ return 1; ++ } ++ ++ if (!drv->bdrv_amend_options) { ++ error_report("Format driver '%s' does not support option amendment", ++ format); ++ return 1; ++ } ++ ++ /* Every driver supporting amendment must have create_opts */ ++ assert(drv->create_opts); ++ ++ printf("Creation options for '%s':\n", format); ++ qemu_opts_print_help(drv->create_opts); ++ printf("\nNote that not all of these options may be amendable.\n"); ++ return 0; ++} ++ + static int img_amend(int argc, char **argv) + { + Error *err = NULL; +@@ -3708,7 +3734,7 @@ static int img_amend(int argc, char **argv) + if (fmt && has_help_option(options)) { + /* If a format is explicitly specified (and possibly no filename is + * given), print option help here */ +- ret = print_block_option_help(filename, fmt); ++ ret = print_amend_option_help(fmt); + goto out; + } + +@@ -3737,7 +3763,7 @@ static int img_amend(int argc, char **argv) + + if (has_help_option(options)) { + /* If the format was auto-detected, print option help here */ +- ret = print_block_option_help(filename, fmt); ++ ret = print_amend_option_help(fmt); + goto out; + } + +diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out +index 1527fbe..4e52dce 100644 +--- a/tests/qemu-iotests/082.out ++++ b/tests/qemu-iotests/082.out +@@ -546,7 +546,7 @@ cluster_size: 65536 + === amend: help for -o === + + Testing: amend -f qcow2 -o help TEST_DIR/t.qcow2 +-Supported options: ++Creation options for 'qcow2': + size Virtual disk size + compat Compatibility level (0.10 or 1.1) + backing_file File name of a base image +@@ -564,10 +564,11 @@ cluster_size qcow2 cluster size + preallocation Preallocation mode (allowed values: off, metadata, falloc, full) + lazy_refcounts Postpone refcount updates + refcount_bits Width of a reference count entry in bits +-nocow Turn off copy-on-write (valid only on btrfs) ++ ++Note that not all of these options may be amendable. + + Testing: amend -f qcow2 -o ? TEST_DIR/t.qcow2 +-Supported options: ++Creation options for 'qcow2': + size Virtual disk size + compat Compatibility level (0.10 or 1.1) + backing_file File name of a base image +@@ -585,10 +586,11 @@ cluster_size qcow2 cluster size + preallocation Preallocation mode (allowed values: off, metadata, falloc, full) + lazy_refcounts Postpone refcount updates + refcount_bits Width of a reference count entry in bits +-nocow Turn off copy-on-write (valid only on btrfs) ++ ++Note that not all of these options may be amendable. + + Testing: amend -f qcow2 -o cluster_size=4k,help TEST_DIR/t.qcow2 +-Supported options: ++Creation options for 'qcow2': + size Virtual disk size + compat Compatibility level (0.10 or 1.1) + backing_file File name of a base image +@@ -606,10 +608,11 @@ cluster_size qcow2 cluster size + preallocation Preallocation mode (allowed values: off, metadata, falloc, full) + lazy_refcounts Postpone refcount updates + refcount_bits Width of a reference count entry in bits +-nocow Turn off copy-on-write (valid only on btrfs) ++ ++Note that not all of these options may be amendable. + + Testing: amend -f qcow2 -o cluster_size=4k,? TEST_DIR/t.qcow2 +-Supported options: ++Creation options for 'qcow2': + size Virtual disk size + compat Compatibility level (0.10 or 1.1) + backing_file File name of a base image +@@ -627,10 +630,11 @@ cluster_size qcow2 cluster size + preallocation Preallocation mode (allowed values: off, metadata, falloc, full) + lazy_refcounts Postpone refcount updates + refcount_bits Width of a reference count entry in bits +-nocow Turn off copy-on-write (valid only on btrfs) ++ ++Note that not all of these options may be amendable. + + Testing: amend -f qcow2 -o help,cluster_size=4k TEST_DIR/t.qcow2 +-Supported options: ++Creation options for 'qcow2': + size Virtual disk size + compat Compatibility level (0.10 or 1.1) + backing_file File name of a base image +@@ -648,10 +652,11 @@ cluster_size qcow2 cluster size + preallocation Preallocation mode (allowed values: off, metadata, falloc, full) + lazy_refcounts Postpone refcount updates + refcount_bits Width of a reference count entry in bits +-nocow Turn off copy-on-write (valid only on btrfs) ++ ++Note that not all of these options may be amendable. + + Testing: amend -f qcow2 -o ?,cluster_size=4k TEST_DIR/t.qcow2 +-Supported options: ++Creation options for 'qcow2': + size Virtual disk size + compat Compatibility level (0.10 or 1.1) + backing_file File name of a base image +@@ -669,10 +674,11 @@ cluster_size qcow2 cluster size + preallocation Preallocation mode (allowed values: off, metadata, falloc, full) + lazy_refcounts Postpone refcount updates + refcount_bits Width of a reference count entry in bits +-nocow Turn off copy-on-write (valid only on btrfs) ++ ++Note that not all of these options may be amendable. + + Testing: amend -f qcow2 -o cluster_size=4k -o help TEST_DIR/t.qcow2 +-Supported options: ++Creation options for 'qcow2': + size Virtual disk size + compat Compatibility level (0.10 or 1.1) + backing_file File name of a base image +@@ -690,10 +696,11 @@ cluster_size qcow2 cluster size + preallocation Preallocation mode (allowed values: off, metadata, falloc, full) + lazy_refcounts Postpone refcount updates + refcount_bits Width of a reference count entry in bits +-nocow Turn off copy-on-write (valid only on btrfs) ++ ++Note that not all of these options may be amendable. + + Testing: amend -f qcow2 -o cluster_size=4k -o ? TEST_DIR/t.qcow2 +-Supported options: ++Creation options for 'qcow2': + size Virtual disk size + compat Compatibility level (0.10 or 1.1) + backing_file File name of a base image +@@ -711,7 +718,8 @@ cluster_size qcow2 cluster size + preallocation Preallocation mode (allowed values: off, metadata, falloc, full) + lazy_refcounts Postpone refcount updates + refcount_bits Width of a reference count entry in bits +-nocow Turn off copy-on-write (valid only on btrfs) ++ ++Note that not all of these options may be amendable. + + Testing: amend -f qcow2 -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2 + +@@ -731,7 +739,7 @@ Testing: amend -f qcow2 -o backing_file=TEST_DIR/t.qcow2 -o ,, -o help TEST_DIR/ + qemu-img: Invalid option list: ,, + + Testing: amend -f qcow2 -o help +-Supported options: ++Creation options for 'qcow2': + size Virtual disk size + compat Compatibility level (0.10 or 1.1) + backing_file File name of a base image +@@ -750,6 +758,8 @@ preallocation Preallocation mode (allowed values: off, metadata, falloc, full + lazy_refcounts Postpone refcount updates + refcount_bits Width of a reference count entry in bits + ++Note that not all of these options may be amendable. ++ + Testing: convert -o help + Supported options: + size Virtual disk size +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-img-Amendment-support-implies-create_opts.patch b/SOURCES/kvm-qemu-img-Amendment-support-implies-create_opts.patch new file mode 100644 index 0000000..6a6691b --- /dev/null +++ b/SOURCES/kvm-qemu-img-Amendment-support-implies-create_opts.patch @@ -0,0 +1,61 @@ +From d43212510cea4b1eda20cb43f357473590d54ffd Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 14:59:37 +0200 +Subject: [PATCH 03/89] qemu-img: Amendment support implies create_opts + +RH-Author: Max Reitz +Message-id: <20180618145943.4489-2-mreitz@redhat.com> +Patchwork-id: 80758 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 1/7] qemu-img: Amendment support implies create_opts +Bugzilla: 1537956 +RH-Acked-by: John Snow +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi + +Instead of checking whether a driver has a non-NULL create_opts we +should check whether it supports image amendment in the first place. If +it does, it must have create_opts. + +On the other hand, if it does not have create_opts (so it does not +support amendment either), the error message "does not support any +options" is a bit useless. Stating clearly that the driver has no +amendment support whatsoever is probably better. + +Signed-off-by: Max Reitz +Reviewed-by: John Snow +Reviewed-by: Eric Blake +Message-id: 20180509210023.20283-2-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit 1f996683ad908fd41c572221a63d9fc31ce04d07) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + qemu-img.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/qemu-img.c b/qemu-img.c +index 60e45ec..2f7c491 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -3740,13 +3740,16 @@ static int img_amend(int argc, char **argv) + goto out; + } + +- if (!bs->drv->create_opts) { +- error_report("Format driver '%s' does not support any options to amend", ++ if (!bs->drv->bdrv_amend_options) { ++ error_report("Format driver '%s' does not support option amendment", + fmt); + ret = -1; + goto out; + } + ++ /* Every driver supporting amendment must have create_opts */ ++ assert(bs->drv->create_opts); ++ + create_opts = qemu_opts_append(create_opts, bs->drv->create_opts); + opts = qemu_opts_create(create_opts, NULL, 0, &error_abort); + qemu_opts_do_parse(opts, options, NULL, &err); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-img-Check-post-truncation-size.patch b/SOURCES/kvm-qemu-img-Check-post-truncation-size.patch new file mode 100644 index 0000000..1a43ecd --- /dev/null +++ b/SOURCES/kvm-qemu-img-Check-post-truncation-size.patch @@ -0,0 +1,100 @@ +From 28b3e17abefac49221fe9b8826ed10f4e0f3f585 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Wed, 16 May 2018 12:00:18 +0200 +Subject: [PATCH 1/8] qemu-img: Check post-truncation size + +RH-Author: Max Reitz +Message-id: <20180516120018.27565-2-mreitz@redhat.com> +Patchwork-id: 80281 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 1/1] qemu-img: Check post-truncation size +Bugzilla: 1523065 +RH-Acked-by: John Snow +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Kevin Wolf + +Some block drivers (iscsi and file-posix when dealing with device files) +do not actually support truncation, even though they provide a +.bdrv_truncate() method and will happily return success when providing a +new size that does not exceed the current size. This is because these +drivers expect the user to resize the image outside of qemu and then +provide qemu with that information through the block_resize command +(compare cb1b83e740384b4e0d950f3d7c81c02b8ce86c2e). + +Of course, anyone using qemu-img resize will find that behavior useless. +So we should check the actual size of the image after the supposedly +successful truncation took place, emit an error if nothing changed and +emit a warning if the target size was not met. + +Signed-off-by: Max Reitz +Message-id: 20180421163957.29872-1-mreitz@redhat.com +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Max Reitz +(cherry picked from commit 5279b30392da7a3248b320c75f20c61e3a95863c) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + qemu-img.c | 39 +++++++++++++++++++++++++++++++++++---- + 1 file changed, 35 insertions(+), 4 deletions(-) + +diff --git a/qemu-img.c b/qemu-img.c +index 855fa52..8320887 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -3381,7 +3381,7 @@ static int img_resize(int argc, char **argv) + Error *err = NULL; + int c, ret, relative; + const char *filename, *fmt, *size; +- int64_t n, total_size, current_size; ++ int64_t n, total_size, current_size, new_size; + bool quiet = false; + BlockBackend *blk = NULL; + PreallocMode prealloc = PREALLOC_MODE_OFF; +@@ -3557,11 +3557,42 @@ static int img_resize(int argc, char **argv) + } + + ret = blk_truncate(blk, total_size, prealloc, &err); +- if (!ret) { +- qprintf(quiet, "Image resized.\n"); +- } else { ++ if (ret < 0) { + error_report_err(err); ++ goto out; ++ } ++ ++ new_size = blk_getlength(blk); ++ if (new_size < 0) { ++ error_report("Failed to verify truncated image length: %s", ++ strerror(-new_size)); ++ ret = -1; ++ goto out; + } ++ ++ /* Some block drivers implement a truncation method, but only so ++ * the user can cause qemu to refresh the image's size from disk. ++ * The idea is that the user resizes the image outside of qemu and ++ * then invokes block_resize to inform qemu about it. ++ * (This includes iscsi and file-posix for device files.) ++ * Of course, that is not the behavior someone invoking ++ * qemu-img resize would find useful, so we catch that behavior ++ * here and tell the user. */ ++ if (new_size != total_size && new_size == current_size) { ++ error_report("Image was not resized; resizing may not be supported " ++ "for this image"); ++ ret = -1; ++ goto out; ++ } ++ ++ if (new_size != total_size) { ++ warn_report("Image should have been resized to %" PRIi64 ++ " bytes, but was resized to %" PRIi64 " bytes", ++ total_size, new_size); ++ } ++ ++ qprintf(quiet, "Image resized.\n"); ++ + out: + blk_unref(blk); + if (ret) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-img-Clarify-about-relative-backing-file-options.patch b/SOURCES/kvm-qemu-img-Clarify-about-relative-backing-file-options.patch deleted file mode 100644 index 7c1a595..0000000 --- a/SOURCES/kvm-qemu-img-Clarify-about-relative-backing-file-options.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 8da92a8a73295fe3239124d26507c5cf0276ddab Mon Sep 17 00:00:00 2001 -From: Fam Zheng -Date: Tue, 12 Dec 2017 02:19:20 +0100 -Subject: [PATCH 3/6] qemu-img: Clarify about relative backing file options - -RH-Author: Fam Zheng -Message-id: <20171212021920.25231-1-famz@redhat.com> -Patchwork-id: 78306 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH] qemu-img: Clarify about relative backing file options -Bugzilla: 1451269 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Peter Xu -RH-Acked-by: Jeffrey Cody - -It's not too surprising when a user specifies the backing file relative -to the current working directory instead of the top layer image. This -causes error when they differ. Though the error message has enough -information to infer the fact about the misunderstanding, it is better -if we document this explicitly, so that users don't have to learn from -mistakes. - -Signed-off-by: Fam Zheng -Reviewed-by: Eric Blake -Reviewed-by: Jeff Cody -Reviewed-by: Stefan Hajnoczi -Signed-off-by: Kevin Wolf -(cherry picked from commit a16efd53406bc8d89f87253ab10290f8d1b145a7) -Signed-off-by: Fam Zheng -Signed-off-by: Miroslav Rezanina ---- - qemu-img.texi | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/qemu-img.texi b/qemu-img.texi -index 72dabd6..90c7eab 100644 ---- a/qemu-img.texi -+++ b/qemu-img.texi -@@ -244,6 +244,9 @@ only the differences from @var{backing_file}. No size needs to be specified in - this case. @var{backing_file} will never be modified unless you use the - @code{commit} monitor command (or qemu-img commit). - -+If a relative path name is given, the backing file is looked up relative to -+the directory containing @var{filename}. -+ - Note that a given backing file will be opened to check that it is valid. Use - the @code{-u} option to enable unsafe backing file mode, which means that the - image will be created even if the associated backing file cannot be opened. A -@@ -343,6 +346,9 @@ created as a copy on write image of the specified base image; the - @var{backing_file} should have the same content as the input's base image, - however the path, image format, etc may differ. - -+If a relative path name is given, the backing file is looked up relative to -+the directory containing @var{output_filename}. -+ - If the @code{-n} option is specified, the target volume creation will be - skipped. This is useful for formats such as @code{rbd} if the target - volume has already been created with site specific options that cannot -@@ -490,6 +496,9 @@ The backing file is changed to @var{backing_file} and (if the image format of - string), then the image is rebased onto no backing file (i.e. it will exist - independently of any backing file). - -+If a relative path name is given, the backing file is looked up relative to -+the directory containing @var{filename}. -+ - @var{cache} specifies the cache mode to be used for @var{filename}, whereas - @var{src_cache} specifies the cache mode for reading backing files. - --- -1.8.3.1 - diff --git a/SOURCES/kvm-qemu-img-Convert-with-copy-offloading.patch b/SOURCES/kvm-qemu-img-Convert-with-copy-offloading.patch new file mode 100644 index 0000000..b3864b9 --- /dev/null +++ b/SOURCES/kvm-qemu-img-Convert-with-copy-offloading.patch @@ -0,0 +1,145 @@ +From 2b47a16d95ebd4d50a0a62d30acd007eb50ce0ea Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Wed, 4 Jul 2018 07:56:31 +0200 +Subject: [PATCH 46/57] qemu-img: Convert with copy offloading + +RH-Author: Fam Zheng +Message-id: <20180629061153.12687-11-famz@redhat.com> +Patchwork-id: 81158 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v2 10/13] qemu-img: Convert with copy offloading +Bugzilla: 1482537 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Kevin Wolf + +The new blk_co_copy_range interface offers a more efficient way in the +case of network based storage. Make use of it to allow faster convert +operation. + +Since copy offloading cannot do zero detection ('-S') and compression +(-c), only try it when these options are not used. + +Signed-off-by: Fam Zheng +Reviewed-by: Stefan Hajnoczi +Message-id: 20180601092648.24614-11-famz@redhat.com +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit ee5306d0923377439776e8a30b9fd2de34b5cbfb) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + qemu-img.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 48 insertions(+), 2 deletions(-) + +diff --git a/qemu-img.c b/qemu-img.c +index 9fc8e66..b2ef54e 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -1561,6 +1561,7 @@ typedef struct ImgConvertState { + bool target_has_backing; + int64_t target_backing_sectors; /* negative if unknown */ + bool wr_in_order; ++ bool copy_range; + int min_sparse; + size_t cluster_sectors; + size_t buf_sectors; +@@ -1765,6 +1766,37 @@ static int coroutine_fn convert_co_write(ImgConvertState *s, int64_t sector_num, + return 0; + } + ++static int coroutine_fn convert_co_copy_range(ImgConvertState *s, int64_t sector_num, ++ int nb_sectors) ++{ ++ int n, ret; ++ ++ while (nb_sectors > 0) { ++ BlockBackend *blk; ++ int src_cur; ++ int64_t bs_sectors, src_cur_offset; ++ int64_t offset; ++ ++ convert_select_part(s, sector_num, &src_cur, &src_cur_offset); ++ offset = (sector_num - src_cur_offset) << BDRV_SECTOR_BITS; ++ blk = s->src[src_cur]; ++ bs_sectors = s->src_sectors[src_cur]; ++ ++ n = MIN(nb_sectors, bs_sectors - (sector_num - src_cur_offset)); ++ ++ ret = blk_co_copy_range(blk, offset, s->target, ++ sector_num << BDRV_SECTOR_BITS, ++ n << BDRV_SECTOR_BITS, 0); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ sector_num += n; ++ nb_sectors -= n; ++ } ++ return 0; ++} ++ + static void coroutine_fn convert_co_do_copy(void *opaque) + { + ImgConvertState *s = opaque; +@@ -1787,6 +1819,7 @@ static void coroutine_fn convert_co_do_copy(void *opaque) + int n; + int64_t sector_num; + enum ImgConvertBlockStatus status; ++ bool copy_range; + + qemu_co_mutex_lock(&s->lock); + if (s->ret != -EINPROGRESS || s->sector_num >= s->total_sectors) { +@@ -1816,7 +1849,9 @@ static void coroutine_fn convert_co_do_copy(void *opaque) + s->allocated_sectors, 0); + } + +- if (status == BLK_DATA) { ++retry: ++ copy_range = s->copy_range && s->status == BLK_DATA; ++ if (status == BLK_DATA && !copy_range) { + ret = convert_co_read(s, sector_num, n, buf); + if (ret < 0) { + error_report("error while reading sector %" PRId64 +@@ -1838,7 +1873,15 @@ static void coroutine_fn convert_co_do_copy(void *opaque) + } + + if (s->ret == -EINPROGRESS) { +- ret = convert_co_write(s, sector_num, n, buf, status); ++ if (copy_range) { ++ ret = convert_co_copy_range(s, sector_num, n); ++ if (ret) { ++ s->copy_range = false; ++ goto retry; ++ } ++ } else { ++ ret = convert_co_write(s, sector_num, n, buf, status); ++ } + if (ret < 0) { + error_report("error while writing sector %" PRId64 + ": %s", sector_num, strerror(-ret)); +@@ -1961,6 +2004,7 @@ static int img_convert(int argc, char **argv) + ImgConvertState s = (ImgConvertState) { + /* Need at least 4k of zeros for sparse detection */ + .min_sparse = 8, ++ .copy_range = true, + .buf_sectors = IO_BUF_SIZE / BDRV_SECTOR_SIZE, + .wr_in_order = true, + .num_coroutines = 8, +@@ -2001,6 +2045,7 @@ static int img_convert(int argc, char **argv) + break; + case 'c': + s.compressed = true; ++ s.copy_range = false; + break; + case 'o': + if (!is_valid_option_list(optarg)) { +@@ -2042,6 +2087,7 @@ static int img_convert(int argc, char **argv) + } + + s.min_sparse = sval / BDRV_SECTOR_SIZE; ++ s.copy_range = false; + break; + } + case 'p': +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-img-Fix-assert-when-mapping-unaligned-raw-file.patch b/SOURCES/kvm-qemu-img-Fix-assert-when-mapping-unaligned-raw-file.patch new file mode 100644 index 0000000..f7bd9f8 --- /dev/null +++ b/SOURCES/kvm-qemu-img-Fix-assert-when-mapping-unaligned-raw-file.patch @@ -0,0 +1,61 @@ +From bd6ce734563c0308b021c013f1e622ff185be60b Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 6 Aug 2018 16:35:52 +0200 +Subject: [PATCH 03/13] qemu-img: Fix assert when mapping unaligned raw file + +RH-Author: Max Reitz +Message-id: <20180806163553.13344-2-mreitz@redhat.com> +Patchwork-id: 81647 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 1/2] qemu-img: Fix assert when mapping unaligned raw file +Bugzilla: 1601310 +RH-Acked-by: Eric Blake +RH-Acked-by: Kevin Wolf +RH-Acked-by: John Snow + +From: Eric Blake + +Commit a290f085 exposed a latent bug in qemu-img map introduced +during the conversion of block status to be byte-based. Earlier in +commit 5e344dd8, the internal interface get_block_status() switched +to take byte-based parameters, but still called a sector-based +block layer function; as such, rounding was added in the lone +caller to obey the contract. However, commit 237d78f8 changed +get_block_status() to truly be byte-based, at which point rounding +to sector boundaries can result in calling bdrv_block_status() with +'bytes == 0' (a coding error) when the boundary between data and a +hole falls mid-sector (true for the past-EOF implicit hole present +in POSIX files). Fix things by removing the rounding that is now +no longer necessary. + +See also https://bugzilla.redhat.com/1589738 + +Fixes: 237d78f8 +Reported-by: Dan Kenigsberg +Reported-by: Nir Soffer +Reported-by: Maor Lipchuk +CC: qemu-stable@nongnu.org +Signed-off-by: Eric Blake +Signed-off-by: Kevin Wolf +(cherry picked from commit e0b371ed5e2db079051139136fd0478728b6a58f) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + qemu-img.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/qemu-img.c b/qemu-img.c +index c9ccc1e..f42750a 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -2925,7 +2925,7 @@ static int img_map(int argc, char **argv) + int64_t n; + + /* Probe up to 1 GiB at a time. */ +- n = QEMU_ALIGN_DOWN(MIN(1 << 30, length - offset), BDRV_SECTOR_SIZE); ++ n = MIN(1 << 30, length - offset); + ret = get_block_status(bs, offset, n, &next); + + if (ret < 0) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-img-Recognize-no-creation-support-in-o-help.patch b/SOURCES/kvm-qemu-img-Recognize-no-creation-support-in-o-help.patch new file mode 100644 index 0000000..2135443 --- /dev/null +++ b/SOURCES/kvm-qemu-img-Recognize-no-creation-support-in-o-help.patch @@ -0,0 +1,74 @@ +From 7fafbdbc3b764038e30ec184edb1ec2207c86218 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 14:59:41 +0200 +Subject: [PATCH 07/89] qemu-img: Recognize no creation support in -o help + +RH-Author: Max Reitz +Message-id: <20180618145943.4489-6-mreitz@redhat.com> +Patchwork-id: 80759 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 5/7] qemu-img: Recognize no creation support in -o help +Bugzilla: 1537956 +RH-Acked-by: John Snow +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi + +The only users of print_block_option_help() are qemu-img create and +qemu-img convert for the output image, so this function is always used +for image creation (it used to be used for amendment also, but that is +no longer the case). + +So if image creation is not supported by either the format or the +protocol, there is no need to print any option description, because the +user cannot create an image like this anyway. + +This also fixes an assertion failure: + + $ qemu-img create -f bochs -o help + Supported options: + qemu-img: util/qemu-option.c:219: + qemu_opts_print_help: Assertion `list' failed. + [1] 24831 abort (core dumped) qemu-img create -f bochs -o help + +Signed-off-by: Max Reitz +Reviewed-by: John Snow +Reviewed-by: Eric Blake +Message-id: 20180509210023.20283-6-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit d402b6a21a825a5c07aac9251990860723d49f5d) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + qemu-img.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/qemu-img.c b/qemu-img.c +index d4cbb63..4bcf157 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -250,6 +250,11 @@ static int print_block_option_help(const char *filename, const char *fmt) + return 1; + } + ++ if (!drv->create_opts) { ++ error_report("Format driver '%s' does not support image creation", fmt); ++ return 1; ++ } ++ + create_opts = qemu_opts_append(create_opts, drv->create_opts); + if (filename) { + proto_drv = bdrv_find_protocol(filename, true, &local_err); +@@ -258,6 +263,11 @@ static int print_block_option_help(const char *filename, const char *fmt) + qemu_opts_free(create_opts); + return 1; + } ++ if (!proto_drv->create_opts) { ++ error_report("Protocal driver '%s' does not support image creation", ++ proto_drv->format_name); ++ return 1; ++ } + create_opts = qemu_opts_append(create_opts, proto_drv->create_opts); + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-img-Resolve-relative-backing-paths-in-rebase.patch b/SOURCES/kvm-qemu-img-Resolve-relative-backing-paths-in-rebase.patch new file mode 100644 index 0000000..e6b5a38 --- /dev/null +++ b/SOURCES/kvm-qemu-img-Resolve-relative-backing-paths-in-rebase.patch @@ -0,0 +1,90 @@ +From 3a3096956fec2d02a3ffe5bc4163a7a35e49707d Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 17:48:32 +0200 +Subject: [PATCH 10/89] qemu-img: Resolve relative backing paths in rebase + +RH-Author: Max Reitz +Message-id: <20180618174833.19439-2-mreitz@redhat.com> +Patchwork-id: 80790 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 1/2] qemu-img: Resolve relative backing paths in rebase +Bugzilla: 1569835 +RH-Acked-by: John Snow +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi + +Currently, rebase interprets a relative path for the new backing image +as follows: +(1) Open the new backing image with the given relative path (thus relative to + qemu-img's working directory). +(2) Write it directly into the overlay's backing path field (thus + relative to the overlay). + +If the overlay is not in qemu-img's working directory, both will be +different interpretations, which may either lead to an error somewhere +(either rebase fails because it cannot open the new backing image, or +your overlay becomes unusable because its backing path does not point to +a file), or, even worse, it may result in your rebase being performed +for a different backing file than what your overlay will point to after +the rebase. + +Fix this by interpreting the target backing path as relative to the +overlay, like qemu-img does everywhere else. + +Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1569835 +Cc: qemu-stable@nongnu.org +Signed-off-by: Max Reitz +Message-id: 20180509182002.8044-2-mreitz@redhat.com +Reviewed-by: Eric Blake +Signed-off-by: Max Reitz +(cherry picked from commit d16699b64671466b42079c45b89127aeea1ca565) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + qemu-img.c | 23 ++++++++++++++++++++++- + 1 file changed, 22 insertions(+), 1 deletion(-) + +diff --git a/qemu-img.c b/qemu-img.c +index 4bcf157..76d6e47 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -3202,6 +3202,9 @@ static int img_rebase(int argc, char **argv) + } + + if (out_baseimg[0]) { ++ const char *overlay_filename; ++ char *out_real_path; ++ + options = qdict_new(); + if (out_basefmt) { + qdict_put_str(options, "driver", out_basefmt); +@@ -3210,8 +3213,26 @@ static int img_rebase(int argc, char **argv) + qdict_put_bool(options, BDRV_OPT_FORCE_SHARE, true); + } + +- blk_new_backing = blk_new_open(out_baseimg, NULL, ++ overlay_filename = bs->exact_filename[0] ? bs->exact_filename ++ : bs->filename; ++ out_real_path = g_malloc(PATH_MAX); ++ ++ bdrv_get_full_backing_filename_from_filename(overlay_filename, ++ out_baseimg, ++ out_real_path, ++ PATH_MAX, ++ &local_err); ++ if (local_err) { ++ error_reportf_err(local_err, ++ "Could not resolve backing filename: "); ++ ret = -1; ++ g_free(out_real_path); ++ goto out; ++ } ++ ++ blk_new_backing = blk_new_open(out_real_path, NULL, + options, src_flags, &local_err); ++ g_free(out_real_path); + if (!blk_new_backing) { + error_reportf_err(local_err, + "Could not open new backing file '%s': ", +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-img-Special-post-backing-convert-handling.patch b/SOURCES/kvm-qemu-img-Special-post-backing-convert-handling.patch new file mode 100644 index 0000000..3781ae9 --- /dev/null +++ b/SOURCES/kvm-qemu-img-Special-post-backing-convert-handling.patch @@ -0,0 +1,113 @@ +From 66e67847293522848a74624c0477299cb87dafa4 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 18:04:50 +0200 +Subject: [PATCH 12/89] qemu-img: Special post-backing convert handling + +RH-Author: Max Reitz +Message-id: <20180618180451.23808-2-mreitz@redhat.com> +Patchwork-id: 80795 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 1/2] qemu-img: Special post-backing convert handling +Bugzilla: 1527898 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Kevin Wolf +RH-Acked-by: Jeffrey Cody + +Currently, qemu-img convert writes zeroes when it reads zeroes. +Sometimes it does not because the target is initialized to zeroes +anyway, so we do not need to overwrite (and thus potentially allocate) +it. This is never the case for targets with backing files, though. But +even they may have an area that is initialized to zeroes, and that is +the area past the end of the backing file (if that is shorter than the +overlay). + +So if the target format's unallocated blocks are zero and there is a gap +between the target's backing file's end and the target's end, we do not +have to explicitly write zeroes there. + +Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1527898 +Signed-off-by: Max Reitz +Message-id: 20180501165750.19242-2-mreitz@redhat.com +Reviewed-by: Eric Blake +Signed-off-by: Max Reitz +(cherry picked from commit 351c8efff9ad809c822d55620df54d575d536f68) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + qemu-img.c | 26 +++++++++++++++++++++++++- + 1 file changed, 25 insertions(+), 1 deletion(-) + +diff --git a/qemu-img.c b/qemu-img.c +index 76d6e47..e2395b9 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -1553,7 +1553,9 @@ typedef struct ImgConvertState { + BlockBackend *target; + bool has_zero_init; + bool compressed; ++ bool unallocated_blocks_are_zero; + bool target_has_backing; ++ int64_t target_backing_sectors; /* negative if unknown */ + bool wr_in_order; + int min_sparse; + size_t cluster_sectors; +@@ -1582,12 +1584,23 @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num) + { + int64_t src_cur_offset; + int ret, n, src_cur; ++ bool post_backing_zero = false; + + convert_select_part(s, sector_num, &src_cur, &src_cur_offset); + + assert(s->total_sectors > sector_num); + n = MIN(s->total_sectors - sector_num, BDRV_REQUEST_MAX_SECTORS); + ++ if (s->target_backing_sectors >= 0) { ++ if (sector_num >= s->target_backing_sectors) { ++ post_backing_zero = s->unallocated_blocks_are_zero; ++ } else if (sector_num + n > s->target_backing_sectors) { ++ /* Split requests around target_backing_sectors (because ++ * starting from there, zeros are handled differently) */ ++ n = s->target_backing_sectors - sector_num; ++ } ++ } ++ + if (s->sector_next_status <= sector_num) { + int64_t count = n * BDRV_SECTOR_SIZE; + +@@ -1609,7 +1622,7 @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num) + n = DIV_ROUND_UP(count, BDRV_SECTOR_SIZE); + + if (ret & BDRV_BLOCK_ZERO) { +- s->status = BLK_ZERO; ++ s->status = post_backing_zero ? BLK_BACKING_FILE : BLK_ZERO; + } else if (ret & BDRV_BLOCK_DATA) { + s->status = BLK_DATA; + } else { +@@ -2330,6 +2343,16 @@ static int img_convert(int argc, char **argv) + } + } + ++ if (s.target_has_backing) { ++ /* Errors are treated as "backing length unknown" (which means ++ * s.target_backing_sectors has to be negative, which it will ++ * be automatically). The backing file length is used only ++ * for optimizations, so such a case is not fatal. */ ++ s.target_backing_sectors = bdrv_nb_sectors(out_bs->backing->bs); ++ } else { ++ s.target_backing_sectors = -1; ++ } ++ + ret = bdrv_get_info(out_bs, &bdi); + if (ret < 0) { + if (s.compressed) { +@@ -2339,6 +2362,7 @@ static int img_convert(int argc, char **argv) + } else { + s.compressed = s.compressed || bdi.needs_compressed_writes; + s.cluster_sectors = bdi.cluster_size / BDRV_SECTOR_SIZE; ++ s.unallocated_blocks_are_zero = bdi.unallocated_blocks_are_zero; + } + + ret = convert_do_copy(&s); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-img-Use-only-string-options-in-img_open_opts.patch b/SOURCES/kvm-qemu-img-Use-only-string-options-in-img_open_opts.patch new file mode 100644 index 0000000..65635b9 --- /dev/null +++ b/SOURCES/kvm-qemu-img-Use-only-string-options-in-img_open_opts.patch @@ -0,0 +1,61 @@ +From b7988ef42d1a3b892c8b3cc99ad7782f2dc3e05c Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 25 Jun 2018 13:06:56 +0200 +Subject: [PATCH 38/54] qemu-img: Use only string options in img_open_opts + +RH-Author: Max Reitz +Message-id: <20180618163106.23010-3-mreitz@redhat.com> +Patchwork-id: 80774 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 2/3] qemu-img: Use only string options in img_open_opts +Bugzilla: 1576598 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Fam Zheng +RH-Acked-by: Miroslav Rezanina + +img_open_opts() takes a QemuOpts and converts them to a QDict, so all +values therein are strings. Then it may try to call qdict_get_bool(), +however, which will fail with a segmentation fault every time: + +$ ./qemu-img info -U --image-opts \ + driver=file,filename=/dev/null,force-share=off +[1] 27869 segmentation fault (core dumped) ./qemu-img info -U +--image-opts driver=file,filename=/dev/null,force-share=off + +Fix this by using qdict_get_str() and comparing the value as a string. +Also, when adding a force-share value to the QDict, add it as a string +so it fits the rest of the dict. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Max Reitz +Message-id: 20180502202051.15493-3-mreitz@redhat.com +Reviewed-by: Eric Blake +Signed-off-by: Max Reitz +(cherry picked from commit 4615f87832d2fcb7a544bedeece2741bf8c21f94) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + qemu-img.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/qemu-img.c b/qemu-img.c +index 62b29e7..60e45ec 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -277,12 +277,12 @@ static BlockBackend *img_open_opts(const char *optstr, + options = qemu_opts_to_qdict(opts, NULL); + if (force_share) { + if (qdict_haskey(options, BDRV_OPT_FORCE_SHARE) +- && !qdict_get_bool(options, BDRV_OPT_FORCE_SHARE)) { ++ && strcmp(qdict_get_str(options, BDRV_OPT_FORCE_SHARE), "on")) { + error_report("--force-share/-U conflicts with image options"); + qobject_unref(options); + return NULL; + } +- qdict_put_bool(options, BDRV_OPT_FORCE_SHARE, true); ++ qdict_put_str(options, BDRV_OPT_FORCE_SHARE, "on"); + } + blk = blk_new_open(NULL, NULL, options, flags, &local_err); + if (!blk) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-img-fix-regression-copying-secrets-during-conve.patch b/SOURCES/kvm-qemu-img-fix-regression-copying-secrets-during-conve.patch new file mode 100644 index 0000000..3b67a8b --- /dev/null +++ b/SOURCES/kvm-qemu-img-fix-regression-copying-secrets-during-conve.patch @@ -0,0 +1,124 @@ +From c8b73d0f85b2435aabbdec92452cb7a0446b1d36 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Mon, 3 Sep 2018 09:41:40 +0200 +Subject: [PATCH 27/29] qemu-img: fix regression copying secrets during convert +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Kevin Wolf +Message-id: <20180903094140.12988-2-kwolf@redhat.com> +Patchwork-id: 82031 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 1/1] qemu-img: fix regression copying secrets during convert +Bugzilla: 1575578 +RH-Acked-by: Max Reitz +RH-Acked-by: Daniel P. Berrange +RH-Acked-by: Miroslav Rezanina + +From: Daniel P. Berrangé + +When the convert command is creating an output file that needs +secrets, we need to ensure those secrets are passed to both the +blk_new_open and bdrv_create API calls. + +This is done by qemu-img extracting all opts matching the name +suffix "key-secret". Unfortunately the code doing this was run after the +call to bdrv_create(), which meant the QemuOpts it was extracting +secrets from was now empty. + +Previously this worked by luks as a bug meant the "key-secret" +parameters were not purged from the QemuOpts. This bug was fixed in + + commit b76b4f604521e59f857d6177bc55f6f2e41fd392 + Author: Kevin Wolf + Date: Thu Jan 11 16:18:08 2018 +0100 + + qcow2: Use visitor for options in qcow2_create() + +Exposing the latent bug in qemu-img. This fix simply moves the copying +of secrets to before the bdrv_create() call. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Daniel P. Berrangé +Signed-off-by: Kevin Wolf +(cherry picked from commit 8d65a3ccfd5db7f0436e095cd952f5d0c3a873ba) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + qemu-img.c | 32 +++++++++++++++----------------- + 1 file changed, 15 insertions(+), 17 deletions(-) + +diff --git a/qemu-img.c b/qemu-img.c +index f42750a..fa0cbd7 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -348,21 +348,6 @@ static int img_add_key_secrets(void *opaque, + return 0; + } + +-static BlockBackend *img_open_new_file(const char *filename, +- QemuOpts *create_opts, +- const char *fmt, int flags, +- bool writethrough, bool quiet, +- bool force_share) +-{ +- QDict *options = NULL; +- +- options = qdict_new(); +- qemu_opt_foreach(create_opts, img_add_key_secrets, options, &error_abort); +- +- return img_open_file(filename, options, fmt, flags, writethrough, quiet, +- force_share); +-} +- + + static BlockBackend *img_open(bool image_opts, + const char *filename, +@@ -1994,6 +1979,7 @@ static int img_convert(int argc, char **argv) + BlockDriverState *out_bs; + QemuOpts *opts = NULL, *sn_opts = NULL; + QemuOptsList *create_opts = NULL; ++ QDict *open_opts = NULL; + char *options = NULL; + Error *local_err = NULL; + bool writethrough, src_writethrough, quiet = false, image_opts = false, +@@ -2342,6 +2328,16 @@ static int img_convert(int argc, char **argv) + } + } + ++ /* ++ * The later open call will need any decryption secrets, and ++ * bdrv_create() will purge "opts", so extract them now before ++ * they are lost. ++ */ ++ if (!skip_create) { ++ open_opts = qdict_new(); ++ qemu_opt_foreach(opts, img_add_key_secrets, open_opts, &error_abort); ++ } ++ + if (!skip_create) { + /* Create the new image */ + ret = bdrv_create(drv, out_filename, opts, &local_err); +@@ -2368,8 +2364,9 @@ static int img_convert(int argc, char **argv) + * That has to wait for bdrv_create to be improved + * to allow filenames in option syntax + */ +- s.target = img_open_new_file(out_filename, opts, out_fmt, +- flags, writethrough, quiet, false); ++ s.target = img_open_file(out_filename, open_opts, out_fmt, ++ flags, writethrough, quiet, false); ++ open_opts = NULL; /* blk_new_open will have freed it */ + } + if (!s.target) { + ret = -1; +@@ -2437,6 +2434,7 @@ out: + qemu_opts_del(opts); + qemu_opts_free(create_opts); + qemu_opts_del(sn_opts); ++ qobject_unref(open_opts); + blk_unref(s.target); + if (s.src) { + for (bs_i = 0; bs_i < s.src_num; bs_i++) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-img-info-Force-U-downstream.patch b/SOURCES/kvm-qemu-img-info-Force-U-downstream.patch deleted file mode 100644 index 8df5d34..0000000 --- a/SOURCES/kvm-qemu-img-info-Force-U-downstream.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 40a03299cb7297e5b5c52b671f4c0b7af501673f Mon Sep 17 00:00:00 2001 -From: Fam Zheng -Date: Mon, 22 Jan 2018 03:07:16 +0100 -Subject: [PATCH 19/21] qemu-img: info: Force -U [downstream] - -RH-Author: Fam Zheng -Message-id: <20180122030716.611-1-famz@redhat.com> -Patchwork-id: 78688 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH] qemu-img: info: Force -U [downstream] -Bugzilla: 1535992 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Jeffrey Cody -RH-Acked-by: John Snow - -Current version of RHV has to work with the coming RHEL 7.5, which means -that customers will encounter error without this patch: RHV invokes -"qemu-img info" while VM is running, and only until the next release it -knows to use "-U". For the existing RHV, we need to ship one version of -qemu-img that doesn't enforce this option yet. - -Upstream already has releases (2.10 and 2.11) that has the new behavior, -so this "moving a step back" patch has no place there. - -I created BZ 1536912 so that we remember to revert this in RHEL -7.6.1536912 so that we remember to revert this in 7.6 time. - -Signed-off-by: Fam Zheng -Signed-off-by: Miroslav Rezanina ---- - qemu-img.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/qemu-img.c b/qemu-img.c -index 56ef49e..dccfc10 100644 ---- a/qemu-img.c -+++ b/qemu-img.c -@@ -2532,7 +2532,7 @@ static int img_info(int argc, char **argv) - const char *filename, *fmt, *output; - ImageInfoList *list; - bool image_opts = false; -- bool force_share = false; -+ bool force_share = true; - - fmt = NULL; - output = NULL; --- -1.8.3.1 - diff --git a/SOURCES/kvm-qemu-io-Drop-command-functions-return-values.patch b/SOURCES/kvm-qemu-io-Drop-command-functions-return-values.patch new file mode 100644 index 0000000..64ef59c --- /dev/null +++ b/SOURCES/kvm-qemu-io-Drop-command-functions-return-values.patch @@ -0,0 +1,1336 @@ +From c1bce8261e118c2efdf6b46a7f271552cb7dacbc Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 25 Jun 2018 13:09:51 +0200 +Subject: [PATCH 40/54] qemu-io: Drop command functions' return values + +RH-Author: Max Reitz +Message-id: <20180618164312.24423-2-mreitz@redhat.com> +Patchwork-id: 80778 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 1/5] qemu-io: Drop command functions' return values +Bugzilla: 1519617 +RH-Acked-by: John Snow +RH-Acked-by: Kevin Wolf +RH-Acked-by: Miroslav Rezanina + +For qemu-io, a function returns an integer with two possible values: 0 +for "qemu-io may continue execution", or 1 for "qemu-io should exit". +However, there is only a single command that returns 1, and that is +"quit". + +So let's turn this case into a global variable instead so we can make +better use of the return value in a later patch. + +Signed-off-by: Max Reitz +Reviewed-by: Eric Blake +Message-id: 20180509194302.21585-2-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit b444d0e9d1ae323fed1ef7c35a359ce064f36b32) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + include/qemu-io.h | 6 +- + qemu-io-cmds.c | 294 +++++++++++++++++++++++++----------------------------- + qemu-io.c | 36 +++---- + 3 files changed, 157 insertions(+), 179 deletions(-) + +diff --git a/include/qemu-io.h b/include/qemu-io.h +index 196fde0..06cdfbf 100644 +--- a/include/qemu-io.h ++++ b/include/qemu-io.h +@@ -22,7 +22,7 @@ + + #define CMD_FLAG_GLOBAL ((int)0x80000000) /* don't iterate "args" */ + +-typedef int (*cfunc_t)(BlockBackend *blk, int argc, char **argv); ++typedef void (*cfunc_t)(BlockBackend *blk, int argc, char **argv); + typedef void (*helpfunc_t)(void); + + typedef struct cmdinfo { +@@ -41,10 +41,10 @@ typedef struct cmdinfo { + + extern bool qemuio_misalign; + +-bool qemuio_command(BlockBackend *blk, const char *cmd); ++void qemuio_command(BlockBackend *blk, const char *cmd); + + void qemuio_add_command(const cmdinfo_t *ci); +-int qemuio_command_usage(const cmdinfo_t *ci); ++void qemuio_command_usage(const cmdinfo_t *ci); + void qemuio_complete_command(const char *input, + void (*fn)(const char *cmd, void *opaque), + void *opaque); +diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c +index 9b3cd00..c2fbaae 100644 +--- a/qemu-io-cmds.c ++++ b/qemu-io-cmds.c +@@ -48,10 +48,9 @@ void qemuio_add_command(const cmdinfo_t *ci) + qsort(cmdtab, ncmds, sizeof(*cmdtab), compare_cmdname); + } + +-int qemuio_command_usage(const cmdinfo_t *ci) ++void qemuio_command_usage(const cmdinfo_t *ci) + { + printf("%s %s -- %s\n", ci->name, ci->args, ci->oneline); +- return 0; + } + + static int init_check_command(BlockBackend *blk, const cmdinfo_t *ct) +@@ -66,13 +65,13 @@ static int init_check_command(BlockBackend *blk, const cmdinfo_t *ct) + return 1; + } + +-static int command(BlockBackend *blk, const cmdinfo_t *ct, int argc, +- char **argv) ++static void command(BlockBackend *blk, const cmdinfo_t *ct, int argc, ++ char **argv) + { + char *cmd = argv[0]; + + if (!init_check_command(blk, ct)) { +- return 0; ++ return; + } + + if (argc - 1 < ct->argmin || (ct->argmax != -1 && argc - 1 > ct->argmax)) { +@@ -89,7 +88,7 @@ static int command(BlockBackend *blk, const cmdinfo_t *ct, int argc, + "bad argument count %d to %s, expected between %d and %d arguments\n", + argc-1, cmd, ct->argmin, ct->argmax); + } +- return 0; ++ return; + } + + /* Request additional permissions if necessary for this command. The caller +@@ -109,13 +108,13 @@ static int command(BlockBackend *blk, const cmdinfo_t *ct, int argc, + ret = blk_set_perm(blk, new_perm, orig_shared_perm, &local_err); + if (ret < 0) { + error_report_err(local_err); +- return 0; ++ return; + } + } + } + + optind = 0; +- return ct->cfunc(blk, argc, argv); ++ ct->cfunc(blk, argc, argv); + } + + static const cmdinfo_t *find_command(const char *cmd) +@@ -634,7 +633,7 @@ static void read_help(void) + "\n"); + } + +-static int read_f(BlockBackend *blk, int argc, char **argv); ++static void read_f(BlockBackend *blk, int argc, char **argv); + + static const cmdinfo_t read_cmd = { + .name = "read", +@@ -647,7 +646,7 @@ static const cmdinfo_t read_cmd = { + .help = read_help, + }; + +-static int read_f(BlockBackend *blk, int argc, char **argv) ++static void read_f(BlockBackend *blk, int argc, char **argv) + { + struct timeval t1, t2; + bool Cflag = false, qflag = false, vflag = false; +@@ -674,7 +673,7 @@ static int read_f(BlockBackend *blk, int argc, char **argv) + pattern_count = cvtnum(optarg); + if (pattern_count < 0) { + print_cvtnum_err(pattern_count, optarg); +- return 0; ++ return; + } + break; + case 'p': +@@ -684,7 +683,7 @@ static int read_f(BlockBackend *blk, int argc, char **argv) + Pflag = true; + pattern = parse_pattern(optarg); + if (pattern < 0) { +- return 0; ++ return; + } + break; + case 'q': +@@ -695,40 +694,43 @@ static int read_f(BlockBackend *blk, int argc, char **argv) + pattern_offset = cvtnum(optarg); + if (pattern_offset < 0) { + print_cvtnum_err(pattern_offset, optarg); +- return 0; ++ return; + } + break; + case 'v': + vflag = true; + break; + default: +- return qemuio_command_usage(&read_cmd); ++ qemuio_command_usage(&read_cmd); ++ return; + } + } + + if (optind != argc - 2) { +- return qemuio_command_usage(&read_cmd); ++ qemuio_command_usage(&read_cmd); ++ return; + } + + offset = cvtnum(argv[optind]); + if (offset < 0) { + print_cvtnum_err(offset, argv[optind]); +- return 0; ++ return; + } + + optind++; + count = cvtnum(argv[optind]); + if (count < 0) { + print_cvtnum_err(count, argv[optind]); +- return 0; ++ return; + } else if (count > BDRV_REQUEST_MAX_BYTES) { + printf("length cannot exceed %" PRIu64 ", given %s\n", + (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]); +- return 0; ++ return; + } + + if (!Pflag && (lflag || sflag)) { +- return qemuio_command_usage(&read_cmd); ++ qemuio_command_usage(&read_cmd); ++ return; + } + + if (!lflag) { +@@ -737,19 +739,19 @@ static int read_f(BlockBackend *blk, int argc, char **argv) + + if ((pattern_count < 0) || (pattern_count + pattern_offset > count)) { + printf("pattern verification range exceeds end of read data\n"); +- return 0; ++ return; + } + + if (bflag) { + if (!QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE)) { + printf("%" PRId64 " is not a sector-aligned value for 'offset'\n", + offset); +- return 0; ++ return; + } + if (!QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE)) { + printf("%"PRId64" is not a sector-aligned value for 'count'\n", + count); +- return 0; ++ return; + } + } + +@@ -793,8 +795,6 @@ static int read_f(BlockBackend *blk, int argc, char **argv) + + out: + qemu_io_free(buf); +- +- return 0; + } + + static void readv_help(void) +@@ -816,7 +816,7 @@ static void readv_help(void) + "\n"); + } + +-static int readv_f(BlockBackend *blk, int argc, char **argv); ++static void readv_f(BlockBackend *blk, int argc, char **argv); + + static const cmdinfo_t readv_cmd = { + .name = "readv", +@@ -828,7 +828,7 @@ static const cmdinfo_t readv_cmd = { + .help = readv_help, + }; + +-static int readv_f(BlockBackend *blk, int argc, char **argv) ++static void readv_f(BlockBackend *blk, int argc, char **argv) + { + struct timeval t1, t2; + bool Cflag = false, qflag = false, vflag = false; +@@ -851,7 +851,7 @@ static int readv_f(BlockBackend *blk, int argc, char **argv) + Pflag = true; + pattern = parse_pattern(optarg); + if (pattern < 0) { +- return 0; ++ return; + } + break; + case 'q': +@@ -861,26 +861,28 @@ static int readv_f(BlockBackend *blk, int argc, char **argv) + vflag = true; + break; + default: +- return qemuio_command_usage(&readv_cmd); ++ qemuio_command_usage(&readv_cmd); ++ return; + } + } + + if (optind > argc - 2) { +- return qemuio_command_usage(&readv_cmd); ++ qemuio_command_usage(&readv_cmd); ++ return; + } + + + offset = cvtnum(argv[optind]); + if (offset < 0) { + print_cvtnum_err(offset, argv[optind]); +- return 0; ++ return; + } + optind++; + + nr_iov = argc - optind; + buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, 0xab); + if (buf == NULL) { +- return 0; ++ return; + } + + gettimeofday(&t1, NULL); +@@ -917,7 +919,6 @@ static int readv_f(BlockBackend *blk, int argc, char **argv) + out: + qemu_iovec_destroy(&qiov); + qemu_io_free(buf); +- return 0; + } + + static void write_help(void) +@@ -943,7 +944,7 @@ static void write_help(void) + "\n"); + } + +-static int write_f(BlockBackend *blk, int argc, char **argv); ++static void write_f(BlockBackend *blk, int argc, char **argv); + + static const cmdinfo_t write_cmd = { + .name = "write", +@@ -957,7 +958,7 @@ static const cmdinfo_t write_cmd = { + .help = write_help, + }; + +-static int write_f(BlockBackend *blk, int argc, char **argv) ++static void write_f(BlockBackend *blk, int argc, char **argv) + { + struct timeval t1, t2; + bool Cflag = false, qflag = false, bflag = false; +@@ -992,7 +993,7 @@ static int write_f(BlockBackend *blk, int argc, char **argv) + Pflag = true; + pattern = parse_pattern(optarg); + if (pattern < 0) { +- return 0; ++ return; + } + break; + case 'q': +@@ -1005,62 +1006,64 @@ static int write_f(BlockBackend *blk, int argc, char **argv) + zflag = true; + break; + default: +- return qemuio_command_usage(&write_cmd); ++ qemuio_command_usage(&write_cmd); ++ return; + } + } + + if (optind != argc - 2) { +- return qemuio_command_usage(&write_cmd); ++ qemuio_command_usage(&write_cmd); ++ return; + } + + if (bflag && zflag) { + printf("-b and -z cannot be specified at the same time\n"); +- return 0; ++ return; + } + + if ((flags & BDRV_REQ_FUA) && (bflag || cflag)) { + printf("-f and -b or -c cannot be specified at the same time\n"); +- return 0; ++ return; + } + + if ((flags & BDRV_REQ_MAY_UNMAP) && !zflag) { + printf("-u requires -z to be specified\n"); +- return 0; ++ return; + } + + if (zflag && Pflag) { + printf("-z and -P cannot be specified at the same time\n"); +- return 0; ++ return; + } + + offset = cvtnum(argv[optind]); + if (offset < 0) { + print_cvtnum_err(offset, argv[optind]); +- return 0; ++ return; + } + + optind++; + count = cvtnum(argv[optind]); + if (count < 0) { + print_cvtnum_err(count, argv[optind]); +- return 0; ++ return; + } else if (count > BDRV_REQUEST_MAX_BYTES) { + printf("length cannot exceed %" PRIu64 ", given %s\n", + (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]); +- return 0; ++ return; + } + + if (bflag || cflag) { + if (!QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE)) { + printf("%" PRId64 " is not a sector-aligned value for 'offset'\n", + offset); +- return 0; ++ return; + } + + if (!QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE)) { + printf("%"PRId64" is not a sector-aligned value for 'count'\n", + count); +- return 0; ++ return; + } + } + +@@ -1097,8 +1100,6 @@ out: + if (!zflag) { + qemu_io_free(buf); + } +- +- return 0; + } + + static void +@@ -1120,7 +1121,7 @@ writev_help(void) + "\n"); + } + +-static int writev_f(BlockBackend *blk, int argc, char **argv); ++static void writev_f(BlockBackend *blk, int argc, char **argv); + + static const cmdinfo_t writev_cmd = { + .name = "writev", +@@ -1133,7 +1134,7 @@ static const cmdinfo_t writev_cmd = { + .help = writev_help, + }; + +-static int writev_f(BlockBackend *blk, int argc, char **argv) ++static void writev_f(BlockBackend *blk, int argc, char **argv) + { + struct timeval t1, t2; + bool Cflag = false, qflag = false; +@@ -1161,29 +1162,31 @@ static int writev_f(BlockBackend *blk, int argc, char **argv) + case 'P': + pattern = parse_pattern(optarg); + if (pattern < 0) { +- return 0; ++ return; + } + break; + default: +- return qemuio_command_usage(&writev_cmd); ++ qemuio_command_usage(&writev_cmd); ++ return; + } + } + + if (optind > argc - 2) { +- return qemuio_command_usage(&writev_cmd); ++ qemuio_command_usage(&writev_cmd); ++ return; + } + + offset = cvtnum(argv[optind]); + if (offset < 0) { + print_cvtnum_err(offset, argv[optind]); +- return 0; ++ return; + } + optind++; + + nr_iov = argc - optind; + buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, pattern); + if (buf == NULL) { +- return 0; ++ return; + } + + gettimeofday(&t1, NULL); +@@ -1205,7 +1208,6 @@ static int writev_f(BlockBackend *blk, int argc, char **argv) + out: + qemu_iovec_destroy(&qiov); + qemu_io_free(buf); +- return 0; + } + + struct aio_ctx { +@@ -1320,7 +1322,7 @@ static void aio_read_help(void) + "\n"); + } + +-static int aio_read_f(BlockBackend *blk, int argc, char **argv); ++static void aio_read_f(BlockBackend *blk, int argc, char **argv); + + static const cmdinfo_t aio_read_cmd = { + .name = "aio_read", +@@ -1332,7 +1334,7 @@ static const cmdinfo_t aio_read_cmd = { + .help = aio_read_help, + }; + +-static int aio_read_f(BlockBackend *blk, int argc, char **argv) ++static void aio_read_f(BlockBackend *blk, int argc, char **argv) + { + int nr_iov, c; + struct aio_ctx *ctx = g_new0(struct aio_ctx, 1); +@@ -1348,14 +1350,14 @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv) + ctx->pattern = parse_pattern(optarg); + if (ctx->pattern < 0) { + g_free(ctx); +- return 0; ++ return; + } + break; + case 'i': + printf("injecting invalid read request\n"); + block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_READ); + g_free(ctx); +- return 0; ++ return; + case 'q': + ctx->qflag = true; + break; +@@ -1364,20 +1366,22 @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv) + break; + default: + g_free(ctx); +- return qemuio_command_usage(&aio_read_cmd); ++ qemuio_command_usage(&aio_read_cmd); ++ return; + } + } + + if (optind > argc - 2) { + g_free(ctx); +- return qemuio_command_usage(&aio_read_cmd); ++ qemuio_command_usage(&aio_read_cmd); ++ return; + } + + ctx->offset = cvtnum(argv[optind]); + if (ctx->offset < 0) { + print_cvtnum_err(ctx->offset, argv[optind]); + g_free(ctx); +- return 0; ++ return; + } + optind++; + +@@ -1386,14 +1390,13 @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv) + if (ctx->buf == NULL) { + block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_READ); + g_free(ctx); +- return 0; ++ return; + } + + gettimeofday(&ctx->t1, NULL); + block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size, + BLOCK_ACCT_READ); + blk_aio_preadv(blk, ctx->offset, &ctx->qiov, 0, aio_read_done, ctx); +- return 0; + } + + static void aio_write_help(void) +@@ -1420,7 +1423,7 @@ static void aio_write_help(void) + "\n"); + } + +-static int aio_write_f(BlockBackend *blk, int argc, char **argv); ++static void aio_write_f(BlockBackend *blk, int argc, char **argv); + + static const cmdinfo_t aio_write_cmd = { + .name = "aio_write", +@@ -1433,7 +1436,7 @@ static const cmdinfo_t aio_write_cmd = { + .help = aio_write_help, + }; + +-static int aio_write_f(BlockBackend *blk, int argc, char **argv) ++static void aio_write_f(BlockBackend *blk, int argc, char **argv) + { + int nr_iov, c; + int pattern = 0xcd; +@@ -1459,51 +1462,53 @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv) + pattern = parse_pattern(optarg); + if (pattern < 0) { + g_free(ctx); +- return 0; ++ return; + } + break; + case 'i': + printf("injecting invalid write request\n"); + block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_WRITE); + g_free(ctx); +- return 0; ++ return; + case 'z': + ctx->zflag = true; + break; + default: + g_free(ctx); +- return qemuio_command_usage(&aio_write_cmd); ++ qemuio_command_usage(&aio_write_cmd); ++ return; + } + } + + if (optind > argc - 2) { + g_free(ctx); +- return qemuio_command_usage(&aio_write_cmd); ++ qemuio_command_usage(&aio_write_cmd); ++ return; + } + + if (ctx->zflag && optind != argc - 2) { + printf("-z supports only a single length parameter\n"); + g_free(ctx); +- return 0; ++ return; + } + + if ((flags & BDRV_REQ_MAY_UNMAP) && !ctx->zflag) { + printf("-u requires -z to be specified\n"); + g_free(ctx); +- return 0; ++ return; + } + + if (ctx->zflag && ctx->Pflag) { + printf("-z and -P cannot be specified at the same time\n"); + g_free(ctx); +- return 0; ++ return; + } + + ctx->offset = cvtnum(argv[optind]); + if (ctx->offset < 0) { + print_cvtnum_err(ctx->offset, argv[optind]); + g_free(ctx); +- return 0; ++ return; + } + optind++; + +@@ -1512,7 +1517,7 @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv) + if (count < 0) { + print_cvtnum_err(count, argv[optind]); + g_free(ctx); +- return 0; ++ return; + } + + ctx->qiov.size = count; +@@ -1525,7 +1530,7 @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv) + if (ctx->buf == NULL) { + block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_WRITE); + g_free(ctx); +- return 0; ++ return; + } + + gettimeofday(&ctx->t1, NULL); +@@ -1535,16 +1540,14 @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv) + blk_aio_pwritev(blk, ctx->offset, &ctx->qiov, flags, aio_write_done, + ctx); + } +- return 0; + } + +-static int aio_flush_f(BlockBackend *blk, int argc, char **argv) ++static void aio_flush_f(BlockBackend *blk, int argc, char **argv) + { + BlockAcctCookie cookie; + block_acct_start(blk_get_stats(blk), &cookie, 0, BLOCK_ACCT_FLUSH); + blk_drain_all(); + block_acct_done(blk_get_stats(blk), &cookie); +- return 0; + } + + static const cmdinfo_t aio_flush_cmd = { +@@ -1553,10 +1556,9 @@ static const cmdinfo_t aio_flush_cmd = { + .oneline = "completes all outstanding aio requests" + }; + +-static int flush_f(BlockBackend *blk, int argc, char **argv) ++static void flush_f(BlockBackend *blk, int argc, char **argv) + { + blk_flush(blk); +- return 0; + } + + static const cmdinfo_t flush_cmd = { +@@ -1566,7 +1568,7 @@ static const cmdinfo_t flush_cmd = { + .oneline = "flush all in-core file state to disk", + }; + +-static int truncate_f(BlockBackend *blk, int argc, char **argv) ++static void truncate_f(BlockBackend *blk, int argc, char **argv) + { + Error *local_err = NULL; + int64_t offset; +@@ -1575,16 +1577,14 @@ static int truncate_f(BlockBackend *blk, int argc, char **argv) + offset = cvtnum(argv[1]); + if (offset < 0) { + print_cvtnum_err(offset, argv[1]); +- return 0; ++ return; + } + + ret = blk_truncate(blk, offset, PREALLOC_MODE_OFF, &local_err); + if (ret < 0) { + error_report_err(local_err); +- return 0; ++ return; + } +- +- return 0; + } + + static const cmdinfo_t truncate_cmd = { +@@ -1598,7 +1598,7 @@ static const cmdinfo_t truncate_cmd = { + .oneline = "truncates the current file at the given offset", + }; + +-static int length_f(BlockBackend *blk, int argc, char **argv) ++static void length_f(BlockBackend *blk, int argc, char **argv) + { + int64_t size; + char s1[64]; +@@ -1606,12 +1606,11 @@ static int length_f(BlockBackend *blk, int argc, char **argv) + size = blk_getlength(blk); + if (size < 0) { + printf("getlength: %s\n", strerror(-size)); +- return 0; ++ return; + } + + cvtstr(size, s1, sizeof(s1)); + printf("%s\n", s1); +- return 0; + } + + +@@ -1623,7 +1622,7 @@ static const cmdinfo_t length_cmd = { + }; + + +-static int info_f(BlockBackend *blk, int argc, char **argv) ++static void info_f(BlockBackend *blk, int argc, char **argv) + { + BlockDriverState *bs = blk_bs(blk); + BlockDriverInfo bdi; +@@ -1640,7 +1639,7 @@ static int info_f(BlockBackend *blk, int argc, char **argv) + + ret = bdrv_get_info(bs, &bdi); + if (ret) { +- return 0; ++ return; + } + + cvtstr(bdi.cluster_size, s1, sizeof(s1)); +@@ -1655,8 +1654,6 @@ static int info_f(BlockBackend *blk, int argc, char **argv) + bdrv_image_info_specific_dump(fprintf, stdout, spec_info); + qapi_free_ImageInfoSpecific(spec_info); + } +- +- return 0; + } + + +@@ -1683,7 +1680,7 @@ static void discard_help(void) + "\n"); + } + +-static int discard_f(BlockBackend *blk, int argc, char **argv); ++static void discard_f(BlockBackend *blk, int argc, char **argv); + + static const cmdinfo_t discard_cmd = { + .name = "discard", +@@ -1697,7 +1694,7 @@ static const cmdinfo_t discard_cmd = { + .help = discard_help, + }; + +-static int discard_f(BlockBackend *blk, int argc, char **argv) ++static void discard_f(BlockBackend *blk, int argc, char **argv) + { + struct timeval t1, t2; + bool Cflag = false, qflag = false; +@@ -1713,30 +1710,32 @@ static int discard_f(BlockBackend *blk, int argc, char **argv) + qflag = true; + break; + default: +- return qemuio_command_usage(&discard_cmd); ++ qemuio_command_usage(&discard_cmd); ++ return; + } + } + + if (optind != argc - 2) { +- return qemuio_command_usage(&discard_cmd); ++ qemuio_command_usage(&discard_cmd); ++ return; + } + + offset = cvtnum(argv[optind]); + if (offset < 0) { + print_cvtnum_err(offset, argv[optind]); +- return 0; ++ return; + } + + optind++; + bytes = cvtnum(argv[optind]); + if (bytes < 0) { + print_cvtnum_err(bytes, argv[optind]); +- return 0; ++ return; + } else if (bytes >> BDRV_SECTOR_BITS > BDRV_REQUEST_MAX_SECTORS) { + printf("length cannot exceed %"PRIu64", given %s\n", + (uint64_t)BDRV_REQUEST_MAX_SECTORS << BDRV_SECTOR_BITS, + argv[optind]); +- return 0; ++ return; + } + + gettimeofday(&t1, NULL); +@@ -1745,7 +1744,7 @@ static int discard_f(BlockBackend *blk, int argc, char **argv) + + if (ret < 0) { + printf("discard failed: %s\n", strerror(-ret)); +- goto out; ++ return; + } + + /* Finally, report back -- -C gives a parsable format */ +@@ -1753,12 +1752,9 @@ static int discard_f(BlockBackend *blk, int argc, char **argv) + t2 = tsub(t2, t1); + print_report("discard", &t2, offset, bytes, bytes, 1, Cflag); + } +- +-out: +- return 0; + } + +-static int alloc_f(BlockBackend *blk, int argc, char **argv) ++static void alloc_f(BlockBackend *blk, int argc, char **argv) + { + BlockDriverState *bs = blk_bs(blk); + int64_t offset, start, remaining, count; +@@ -1769,14 +1765,14 @@ static int alloc_f(BlockBackend *blk, int argc, char **argv) + start = offset = cvtnum(argv[1]); + if (offset < 0) { + print_cvtnum_err(offset, argv[1]); +- return 0; ++ return; + } + + if (argc == 3) { + count = cvtnum(argv[2]); + if (count < 0) { + print_cvtnum_err(count, argv[2]); +- return 0; ++ return; + } + } else { + count = BDRV_SECTOR_SIZE; +@@ -1788,7 +1784,7 @@ static int alloc_f(BlockBackend *blk, int argc, char **argv) + ret = bdrv_is_allocated(bs, offset, remaining, &num); + if (ret < 0) { + printf("is_allocated failed: %s\n", strerror(-ret)); +- return 0; ++ return; + } + offset += num; + remaining -= num; +@@ -1805,7 +1801,6 @@ static int alloc_f(BlockBackend *blk, int argc, char **argv) + + printf("%"PRId64"/%"PRId64" bytes allocated at offset %s\n", + sum_alloc, count, s1); +- return 0; + } + + static const cmdinfo_t alloc_cmd = { +@@ -1851,7 +1846,7 @@ static int map_is_allocated(BlockDriverState *bs, int64_t offset, + return firstret; + } + +-static int map_f(BlockBackend *blk, int argc, char **argv) ++static void map_f(BlockBackend *blk, int argc, char **argv) + { + int64_t offset, bytes; + char s1[64], s2[64]; +@@ -1863,17 +1858,17 @@ static int map_f(BlockBackend *blk, int argc, char **argv) + bytes = blk_getlength(blk); + if (bytes < 0) { + error_report("Failed to query image length: %s", strerror(-bytes)); +- return 0; ++ return; + } + + while (bytes) { + ret = map_is_allocated(blk_bs(blk), offset, bytes, &num); + if (ret < 0) { + error_report("Failed to get allocation status: %s", strerror(-ret)); +- return 0; ++ return; + } else if (!num) { + error_report("Unexpected end of image"); +- return 0; ++ return; + } + + retstr = ret ? " allocated" : "not allocated"; +@@ -1885,8 +1880,6 @@ static int map_f(BlockBackend *blk, int argc, char **argv) + offset += num; + bytes -= num; + } +- +- return 0; + } + + static const cmdinfo_t map_cmd = { +@@ -1914,7 +1907,7 @@ static void reopen_help(void) + "\n"); + } + +-static int reopen_f(BlockBackend *blk, int argc, char **argv); ++static void reopen_f(BlockBackend *blk, int argc, char **argv); + + static QemuOptsList reopen_opts = { + .name = "reopen", +@@ -1936,7 +1929,7 @@ static const cmdinfo_t reopen_cmd = { + .help = reopen_help, + }; + +-static int reopen_f(BlockBackend *blk, int argc, char **argv) ++static void reopen_f(BlockBackend *blk, int argc, char **argv) + { + BlockDriverState *bs = blk_bs(blk); + QemuOpts *qopts; +@@ -1954,19 +1947,19 @@ static int reopen_f(BlockBackend *blk, int argc, char **argv) + case 'c': + if (bdrv_parse_cache_mode(optarg, &flags, &writethrough) < 0) { + error_report("Invalid cache option: %s", optarg); +- return 0; ++ return; + } + break; + case 'o': + if (!qemu_opts_parse_noisily(&reopen_opts, optarg, 0)) { + qemu_opts_reset(&reopen_opts); +- return 0; ++ return; + } + break; + case 'r': + if (has_rw_option) { + error_report("Only one -r/-w option may be given"); +- return 0; ++ return; + } + flags &= ~BDRV_O_RDWR; + has_rw_option = true; +@@ -1974,20 +1967,22 @@ static int reopen_f(BlockBackend *blk, int argc, char **argv) + case 'w': + if (has_rw_option) { + error_report("Only one -r/-w option may be given"); +- return 0; ++ return; + } + flags |= BDRV_O_RDWR; + has_rw_option = true; + break; + default: + qemu_opts_reset(&reopen_opts); +- return qemuio_command_usage(&reopen_cmd); ++ qemuio_command_usage(&reopen_cmd); ++ return; + } + } + + if (optind != argc) { + qemu_opts_reset(&reopen_opts); +- return qemuio_command_usage(&reopen_cmd); ++ qemuio_command_usage(&reopen_cmd); ++ return; + } + + if (writethrough != blk_enable_write_cache(blk) && +@@ -1995,7 +1990,7 @@ static int reopen_f(BlockBackend *blk, int argc, char **argv) + { + error_report("Cannot change cache.writeback: Device attached"); + qemu_opts_reset(&reopen_opts); +- return 0; ++ return; + } + + if (!(flags & BDRV_O_RDWR)) { +@@ -2024,11 +2019,9 @@ static int reopen_f(BlockBackend *blk, int argc, char **argv) + } else { + blk_set_enable_write_cache(blk, !writethrough); + } +- +- return 0; + } + +-static int break_f(BlockBackend *blk, int argc, char **argv) ++static void break_f(BlockBackend *blk, int argc, char **argv) + { + int ret; + +@@ -2036,11 +2029,9 @@ static int break_f(BlockBackend *blk, int argc, char **argv) + if (ret < 0) { + printf("Could not set breakpoint: %s\n", strerror(-ret)); + } +- +- return 0; + } + +-static int remove_break_f(BlockBackend *blk, int argc, char **argv) ++static void remove_break_f(BlockBackend *blk, int argc, char **argv) + { + int ret; + +@@ -2048,8 +2039,6 @@ static int remove_break_f(BlockBackend *blk, int argc, char **argv) + if (ret < 0) { + printf("Could not remove breakpoint %s: %s\n", argv[1], strerror(-ret)); + } +- +- return 0; + } + + static const cmdinfo_t break_cmd = { +@@ -2071,7 +2060,7 @@ static const cmdinfo_t remove_break_cmd = { + .oneline = "remove a breakpoint by tag", + }; + +-static int resume_f(BlockBackend *blk, int argc, char **argv) ++static void resume_f(BlockBackend *blk, int argc, char **argv) + { + int ret; + +@@ -2079,8 +2068,6 @@ static int resume_f(BlockBackend *blk, int argc, char **argv) + if (ret < 0) { + printf("Could not resume request: %s\n", strerror(-ret)); + } +- +- return 0; + } + + static const cmdinfo_t resume_cmd = { +@@ -2092,13 +2079,11 @@ static const cmdinfo_t resume_cmd = { + .oneline = "resumes the request tagged as tag", + }; + +-static int wait_break_f(BlockBackend *blk, int argc, char **argv) ++static void wait_break_f(BlockBackend *blk, int argc, char **argv) + { + while (!bdrv_debug_is_suspended(blk_bs(blk), argv[1])) { + aio_poll(blk_get_aio_context(blk), true); + } +- +- return 0; + } + + static const cmdinfo_t wait_break_cmd = { +@@ -2110,7 +2095,7 @@ static const cmdinfo_t wait_break_cmd = { + .oneline = "waits for the suspension of a request", + }; + +-static int abort_f(BlockBackend *blk, int argc, char **argv) ++static void abort_f(BlockBackend *blk, int argc, char **argv) + { + abort(); + } +@@ -2136,7 +2121,7 @@ static void sigraise_help(void) + "\n", SIGTERM); + } + +-static int sigraise_f(BlockBackend *blk, int argc, char **argv); ++static void sigraise_f(BlockBackend *blk, int argc, char **argv); + + static const cmdinfo_t sigraise_cmd = { + .name = "sigraise", +@@ -2149,16 +2134,16 @@ static const cmdinfo_t sigraise_cmd = { + .help = sigraise_help, + }; + +-static int sigraise_f(BlockBackend *blk, int argc, char **argv) ++static void sigraise_f(BlockBackend *blk, int argc, char **argv) + { + int64_t sig = cvtnum(argv[1]); + if (sig < 0) { + print_cvtnum_err(sig, argv[1]); +- return 0; ++ return; + } else if (sig > NSIG) { + printf("signal argument '%s' is too large to be a valid signal\n", + argv[1]); +- return 0; ++ return; + } + + /* Using raise() to kill this process does not necessarily flush all open +@@ -2168,7 +2153,6 @@ static int sigraise_f(BlockBackend *blk, int argc, char **argv) + fflush(stderr); + + raise(sig); +- return 0; + } + + static void sleep_cb(void *opaque) +@@ -2177,7 +2161,7 @@ static void sleep_cb(void *opaque) + *expired = true; + } + +-static int sleep_f(BlockBackend *blk, int argc, char **argv) ++static void sleep_f(BlockBackend *blk, int argc, char **argv) + { + char *endptr; + long ms; +@@ -2187,7 +2171,7 @@ static int sleep_f(BlockBackend *blk, int argc, char **argv) + ms = strtol(argv[1], &endptr, 0); + if (ms < 0 || *endptr != '\0') { + printf("%s is not a valid number\n", argv[1]); +- return 0; ++ return; + } + + timer = timer_new_ns(QEMU_CLOCK_HOST, sleep_cb, &expired); +@@ -2198,8 +2182,6 @@ static int sleep_f(BlockBackend *blk, int argc, char **argv) + } + + timer_free(timer); +- +- return 0; + } + + static const cmdinfo_t sleep_cmd = { +@@ -2246,23 +2228,22 @@ static void help_all(void) + printf("\nUse 'help commandname' for extended help.\n"); + } + +-static int help_f(BlockBackend *blk, int argc, char **argv) ++static void help_f(BlockBackend *blk, int argc, char **argv) + { + const cmdinfo_t *ct; + + if (argc == 1) { + help_all(); +- return 0; ++ return; + } + + ct = find_command(argv[1]); + if (ct == NULL) { + printf("command %s not found\n", argv[1]); +- return 0; ++ return; + } + + help_onecmd(argv[1], ct); +- return 0; + } + + static const cmdinfo_t help_cmd = { +@@ -2276,14 +2257,13 @@ static const cmdinfo_t help_cmd = { + .oneline = "help for one or all commands", + }; + +-bool qemuio_command(BlockBackend *blk, const char *cmd) ++void qemuio_command(BlockBackend *blk, const char *cmd) + { + AioContext *ctx; + char *input; + const cmdinfo_t *ct; + char **v; + int c; +- bool done = false; + + input = g_strdup(cmd); + v = breakline(input, &c); +@@ -2292,7 +2272,7 @@ bool qemuio_command(BlockBackend *blk, const char *cmd) + if (ct) { + ctx = blk ? blk_get_aio_context(blk) : qemu_get_aio_context(); + aio_context_acquire(ctx); +- done = command(blk, ct, c, v); ++ command(blk, ct, c, v); + aio_context_release(ctx); + } else { + fprintf(stderr, "command \"%s\" not found\n", v[0]); +@@ -2300,8 +2280,6 @@ bool qemuio_command(BlockBackend *blk, const char *cmd) + } + g_free(input); + g_free(v); +- +- return done; + } + + static void __attribute((constructor)) init_qemuio_commands(void) +diff --git a/qemu-io.c b/qemu-io.c +index 73c638f..02a67c9 100644 +--- a/qemu-io.c ++++ b/qemu-io.c +@@ -37,6 +37,7 @@ + static char *progname; + + static BlockBackend *qemuio_blk; ++static bool quit_qemu_io; + + /* qemu-io commands passed using -c */ + static int ncmdline; +@@ -65,11 +66,10 @@ static int get_eof_char(void) + #endif + } + +-static int close_f(BlockBackend *blk, int argc, char **argv) ++static void close_f(BlockBackend *blk, int argc, char **argv) + { + blk_unref(qemuio_blk); + qemuio_blk = NULL; +- return 0; + } + + static const cmdinfo_t close_cmd = { +@@ -136,7 +136,7 @@ static void open_help(void) + "\n"); + } + +-static int open_f(BlockBackend *blk, int argc, char **argv); ++static void open_f(BlockBackend *blk, int argc, char **argv); + + static const cmdinfo_t open_cmd = { + .name = "open", +@@ -160,7 +160,7 @@ static QemuOptsList empty_opts = { + }, + }; + +-static int open_f(BlockBackend *blk, int argc, char **argv) ++static void open_f(BlockBackend *blk, int argc, char **argv) + { + int flags = BDRV_O_UNMAP; + int readonly = 0; +@@ -192,25 +192,25 @@ static int open_f(BlockBackend *blk, int argc, char **argv) + if (bdrv_parse_cache_mode(optarg, &flags, &writethrough) < 0) { + error_report("Invalid cache option: %s", optarg); + qemu_opts_reset(&empty_opts); +- return 0; ++ return; + } + break; + case 'd': + if (bdrv_parse_discard_flags(optarg, &flags) < 0) { + error_report("Invalid discard option: %s", optarg); + qemu_opts_reset(&empty_opts); +- return 0; ++ return; + } + break; + case 'o': + if (imageOpts) { + printf("--image-opts and 'open -o' are mutually exclusive\n"); + qemu_opts_reset(&empty_opts); +- return 0; ++ return; + } + if (!qemu_opts_parse_noisily(&empty_opts, optarg, false)) { + qemu_opts_reset(&empty_opts); +- return 0; ++ return; + } + break; + case 'U': +@@ -218,7 +218,8 @@ static int open_f(BlockBackend *blk, int argc, char **argv) + break; + default: + qemu_opts_reset(&empty_opts); +- return qemuio_command_usage(&open_cmd); ++ qemuio_command_usage(&open_cmd); ++ return; + } + } + +@@ -229,7 +230,7 @@ static int open_f(BlockBackend *blk, int argc, char **argv) + if (imageOpts && (optind == argc - 1)) { + if (!qemu_opts_parse_noisily(&empty_opts, argv[optind], false)) { + qemu_opts_reset(&empty_opts); +- return 0; ++ return; + } + optind++; + } +@@ -246,12 +247,11 @@ static int open_f(BlockBackend *blk, int argc, char **argv) + qobject_unref(opts); + qemuio_command_usage(&open_cmd); + } +- return 0; + } + +-static int quit_f(BlockBackend *blk, int argc, char **argv) ++static void quit_f(BlockBackend *blk, int argc, char **argv) + { +- return 1; ++ quit_qemu_io = true; + } + + static const cmdinfo_t quit_cmd = { +@@ -392,18 +392,18 @@ static void prep_fetchline(void *opaque) + + static void command_loop(void) + { +- int i, done = 0, fetchable = 0, prompted = 0; ++ int i, fetchable = 0, prompted = 0; + char *input; + +- for (i = 0; !done && i < ncmdline; i++) { +- done = qemuio_command(qemuio_blk, cmdline[i]); ++ for (i = 0; !quit_qemu_io && i < ncmdline; i++) { ++ qemuio_command(qemuio_blk, cmdline[i]); + } + if (cmdline) { + g_free(cmdline); + return; + } + +- while (!done) { ++ while (!quit_qemu_io) { + if (!prompted) { + printf("%s", get_prompt()); + fflush(stdout); +@@ -421,7 +421,7 @@ static void command_loop(void) + if (input == NULL) { + break; + } +- done = qemuio_command(qemuio_blk, input); ++ qemuio_command(qemuio_blk, input); + g_free(input); + + prompted = 0; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-io-Drop-write-permissions-before-read-only-reop.patch b/SOURCES/kvm-qemu-io-Drop-write-permissions-before-read-only-reop.patch deleted file mode 100644 index bdaf652..0000000 --- a/SOURCES/kvm-qemu-io-Drop-write-permissions-before-read-only-reop.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 1c4c0df8838e32c524c86ae7ab0fcdc56cb0cad0 Mon Sep 17 00:00:00 2001 -From: Kevin Wolf -Date: Mon, 4 Dec 2017 12:10:00 +0100 -Subject: [PATCH 29/36] qemu-io: Drop write permissions before read-only reopen - -RH-Author: Kevin Wolf -Message-id: <20171204121007.12964-2-kwolf@redhat.com> -Patchwork-id: 78106 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 1/8] qemu-io: Drop write permissions before read-only reopen -Bugzilla: 1492178 -RH-Acked-by: Fam Zheng -RH-Acked-by: Max Reitz -RH-Acked-by: Jeffrey Cody - -qemu-io provides a 'reopen' command that allows switching from writable -to read-only access. We need to make sure that we don't try to keep -write permissions to a BlockBackend that becomes read-only, otherwise -things are going to fail. - -This requires a bdrv_drain() call because otherwise in-flight AIO -write requests could issue new internal requests while the permission -has already gone away, which would cause assertion failures. Draining -the queue doesn't break AIO requests in any new way, bdrv_reopen() would -drain it anyway only a few lines later. - -Signed-off-by: Kevin Wolf -Reviewed-by: Fam Zheng -(cherry picked from commit f3adefb2cea1c63b7b198acaef5e40eb4b2d2d39) -Signed-off-by: Miroslav Rezanina ---- - qemu-io-cmds.c | 12 ++++++++++++ - tests/qemu-iotests/187.out | 2 +- - 2 files changed, 13 insertions(+), 1 deletion(-) - -diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c -index 2811a89..3727fb4 100644 ---- a/qemu-io-cmds.c -+++ b/qemu-io-cmds.c -@@ -2010,6 +2010,18 @@ static int reopen_f(BlockBackend *blk, int argc, char **argv) - return 0; - } - -+ if (!(flags & BDRV_O_RDWR)) { -+ uint64_t orig_perm, orig_shared_perm; -+ -+ bdrv_drain(bs); -+ -+ blk_get_perm(blk, &orig_perm, &orig_shared_perm); -+ blk_set_perm(blk, -+ orig_perm & ~(BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED), -+ orig_shared_perm, -+ &error_abort); -+ } -+ - qopts = qemu_opts_find(&reopen_opts, NULL); - opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL; - qemu_opts_reset(&reopen_opts); -diff --git a/tests/qemu-iotests/187.out b/tests/qemu-iotests/187.out -index 68fb944..30b987f 100644 ---- a/tests/qemu-iotests/187.out -+++ b/tests/qemu-iotests/187.out -@@ -12,7 +12,7 @@ Start from read-write - - wrote 65536/65536 bytes at offset 0 - 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) --write failed: Operation not permitted -+Block node is read-only - wrote 65536/65536 bytes at offset 0 - 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - *** done --- -1.8.3.1 - diff --git a/SOURCES/kvm-qemu-io-Exit-with-error-when-a-command-failed.patch b/SOURCES/kvm-qemu-io-Exit-with-error-when-a-command-failed.patch new file mode 100644 index 0000000..0c92993 --- /dev/null +++ b/SOURCES/kvm-qemu-io-Exit-with-error-when-a-command-failed.patch @@ -0,0 +1,116 @@ +From 4dad2c0644a22a935a87f86b4d63747a9598bb5d Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 16:43:10 +0200 +Subject: [PATCH 42/54] qemu-io: Exit with error when a command failed + +RH-Author: Max Reitz +Message-id: <20180618164312.24423-4-mreitz@redhat.com> +Patchwork-id: 80780 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 3/5] qemu-io: Exit with error when a command failed +Bugzilla: 1519617 +RH-Acked-by: John Snow +RH-Acked-by: Kevin Wolf +RH-Acked-by: Miroslav Rezanina + +Currently, qemu-io basically always returns success when it gets to +interactive mode (so once the whole command line has been parsed; even +before the commands on the command line are interpreted). That is not +very useful. + +This patch makes qemu-io return failure when any of the executed +commands failed. + +Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1519617 +Signed-off-by: Max Reitz +Reviewed-by: Eric Blake +Message-id: 20180509194302.21585-4-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit 6b3aa8485ca8e61b168f51d465188855cf549bd2) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + qemu-io.c | 28 ++++++++++++++++++++++------ + 1 file changed, 22 insertions(+), 6 deletions(-) + +diff --git a/qemu-io.c b/qemu-io.c +index ec66838..13829f5 100644 +--- a/qemu-io.c ++++ b/qemu-io.c +@@ -400,17 +400,21 @@ static void prep_fetchline(void *opaque) + *fetchable= 1; + } + +-static void command_loop(void) ++static int command_loop(void) + { + int i, fetchable = 0, prompted = 0; ++ int ret, last_error = 0; + char *input; + + for (i = 0; !quit_qemu_io && i < ncmdline; i++) { +- qemuio_command(qemuio_blk, cmdline[i]); ++ ret = qemuio_command(qemuio_blk, cmdline[i]); ++ if (ret < 0) { ++ last_error = ret; ++ } + } + if (cmdline) { + g_free(cmdline); +- return; ++ return last_error; + } + + while (!quit_qemu_io) { +@@ -431,13 +435,19 @@ static void command_loop(void) + if (input == NULL) { + break; + } +- qemuio_command(qemuio_blk, input); ++ ret = qemuio_command(qemuio_blk, input); + g_free(input); + ++ if (ret < 0) { ++ last_error = ret; ++ } ++ + prompted = 0; + fetchable = 0; + } + qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL); ++ ++ return last_error; + } + + static void add_user_command(char *optarg) +@@ -502,6 +512,7 @@ int main(int argc, char **argv) + int c; + int opt_index = 0; + int flags = BDRV_O_UNMAP; ++ int ret; + bool writethrough = true; + Error *local_error = NULL; + QDict *opts = NULL; +@@ -663,7 +674,7 @@ int main(int argc, char **argv) + } + } + } +- command_loop(); ++ ret = command_loop(); + + /* + * Make sure all outstanding requests complete before the program exits. +@@ -672,5 +683,10 @@ int main(int argc, char **argv) + + blk_unref(qemuio_blk); + g_free(readline_state); +- return 0; ++ ++ if (ret < 0) { ++ return 1; ++ } else { ++ return 0; ++ } + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-io-Let-command-functions-return-error-code.patch b/SOURCES/kvm-qemu-io-Let-command-functions-return-error-code.patch new file mode 100644 index 0000000..945e85b --- /dev/null +++ b/SOURCES/kvm-qemu-io-Let-command-functions-return-error-code.patch @@ -0,0 +1,1452 @@ +From cc8c7cffb3786855de0032b376c7b22c461b695c Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 25 Jun 2018 13:12:14 +0200 +Subject: [PATCH 41/54] qemu-io: Let command functions return error code + +RH-Author: Max Reitz +Message-id: <20180618164312.24423-3-mreitz@redhat.com> +Patchwork-id: 80781 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 2/5] qemu-io: Let command functions return error code +Bugzilla: 1519617 +RH-Acked-by: John Snow +RH-Acked-by: Kevin Wolf +RH-Acked-by: Miroslav Rezanina + +This is basically what everything else in the qemu code base does, so we +can do it here, too. + +Signed-off-by: Max Reitz +Reviewed-by: Eric Blake +Message-id: 20180509194302.21585-3-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit b32d7a39af488d280ce5f02a2ed94871d696f87a) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + include/qemu-io.h | 9 +- + qemu-io-cmds.c | 346 ++++++++++++++++++++++++++++++++---------------------- + qemu-io.c | 34 ++++-- + 3 files changed, 232 insertions(+), 157 deletions(-) + +diff --git a/include/qemu-io.h b/include/qemu-io.h +index 06cdfbf..7433239 100644 +--- a/include/qemu-io.h ++++ b/include/qemu-io.h +@@ -22,7 +22,12 @@ + + #define CMD_FLAG_GLOBAL ((int)0x80000000) /* don't iterate "args" */ + +-typedef void (*cfunc_t)(BlockBackend *blk, int argc, char **argv); ++/* Implement a qemu-io command. ++ * Operate on @blk using @argc/@argv as the command's arguments, and ++ * return 0 on success or negative errno on failure. ++ */ ++typedef int (*cfunc_t)(BlockBackend *blk, int argc, char **argv); ++ + typedef void (*helpfunc_t)(void); + + typedef struct cmdinfo { +@@ -41,7 +46,7 @@ typedef struct cmdinfo { + + extern bool qemuio_misalign; + +-void qemuio_command(BlockBackend *blk, const char *cmd); ++int qemuio_command(BlockBackend *blk, const char *cmd); + + void qemuio_add_command(const cmdinfo_t *ci); + void qemuio_command_usage(const cmdinfo_t *ci); +diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c +index c2fbaae..5bf5f28 100644 +--- a/qemu-io-cmds.c ++++ b/qemu-io-cmds.c +@@ -65,13 +65,13 @@ static int init_check_command(BlockBackend *blk, const cmdinfo_t *ct) + return 1; + } + +-static void command(BlockBackend *blk, const cmdinfo_t *ct, int argc, +- char **argv) ++static int command(BlockBackend *blk, const cmdinfo_t *ct, int argc, ++ char **argv) + { + char *cmd = argv[0]; + + if (!init_check_command(blk, ct)) { +- return; ++ return -EINVAL; + } + + if (argc - 1 < ct->argmin || (ct->argmax != -1 && argc - 1 > ct->argmax)) { +@@ -88,7 +88,7 @@ static void command(BlockBackend *blk, const cmdinfo_t *ct, int argc, + "bad argument count %d to %s, expected between %d and %d arguments\n", + argc-1, cmd, ct->argmin, ct->argmax); + } +- return; ++ return -EINVAL; + } + + /* Request additional permissions if necessary for this command. The caller +@@ -108,13 +108,13 @@ static void command(BlockBackend *blk, const cmdinfo_t *ct, int argc, + ret = blk_set_perm(blk, new_perm, orig_shared_perm, &local_err); + if (ret < 0) { + error_report_err(local_err); +- return; ++ return ret; + } + } + } + + optind = 0; +- ct->cfunc(blk, argc, argv); ++ return ct->cfunc(blk, argc, argv); + } + + static const cmdinfo_t *find_command(const char *cmd) +@@ -633,7 +633,7 @@ static void read_help(void) + "\n"); + } + +-static void read_f(BlockBackend *blk, int argc, char **argv); ++static int read_f(BlockBackend *blk, int argc, char **argv); + + static const cmdinfo_t read_cmd = { + .name = "read", +@@ -646,12 +646,12 @@ static const cmdinfo_t read_cmd = { + .help = read_help, + }; + +-static void read_f(BlockBackend *blk, int argc, char **argv) ++static int read_f(BlockBackend *blk, int argc, char **argv) + { + struct timeval t1, t2; + bool Cflag = false, qflag = false, vflag = false; + bool Pflag = false, sflag = false, lflag = false, bflag = false; +- int c, cnt; ++ int c, cnt, ret; + char *buf; + int64_t offset; + int64_t count; +@@ -673,7 +673,7 @@ static void read_f(BlockBackend *blk, int argc, char **argv) + pattern_count = cvtnum(optarg); + if (pattern_count < 0) { + print_cvtnum_err(pattern_count, optarg); +- return; ++ return pattern_count; + } + break; + case 'p': +@@ -683,7 +683,7 @@ static void read_f(BlockBackend *blk, int argc, char **argv) + Pflag = true; + pattern = parse_pattern(optarg); + if (pattern < 0) { +- return; ++ return -EINVAL; + } + break; + case 'q': +@@ -694,7 +694,7 @@ static void read_f(BlockBackend *blk, int argc, char **argv) + pattern_offset = cvtnum(optarg); + if (pattern_offset < 0) { + print_cvtnum_err(pattern_offset, optarg); +- return; ++ return pattern_offset; + } + break; + case 'v': +@@ -702,35 +702,35 @@ static void read_f(BlockBackend *blk, int argc, char **argv) + break; + default: + qemuio_command_usage(&read_cmd); +- return; ++ return -EINVAL; + } + } + + if (optind != argc - 2) { + qemuio_command_usage(&read_cmd); +- return; ++ return -EINVAL; + } + + offset = cvtnum(argv[optind]); + if (offset < 0) { + print_cvtnum_err(offset, argv[optind]); +- return; ++ return offset; + } + + optind++; + count = cvtnum(argv[optind]); + if (count < 0) { + print_cvtnum_err(count, argv[optind]); +- return; ++ return count; + } else if (count > BDRV_REQUEST_MAX_BYTES) { + printf("length cannot exceed %" PRIu64 ", given %s\n", + (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]); +- return; ++ return -EINVAL; + } + + if (!Pflag && (lflag || sflag)) { + qemuio_command_usage(&read_cmd); +- return; ++ return -EINVAL; + } + + if (!lflag) { +@@ -739,19 +739,19 @@ static void read_f(BlockBackend *blk, int argc, char **argv) + + if ((pattern_count < 0) || (pattern_count + pattern_offset > count)) { + printf("pattern verification range exceeds end of read data\n"); +- return; ++ return -EINVAL; + } + + if (bflag) { + if (!QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE)) { + printf("%" PRId64 " is not a sector-aligned value for 'offset'\n", + offset); +- return; ++ return -EINVAL; + } + if (!QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE)) { + printf("%"PRId64" is not a sector-aligned value for 'count'\n", + count); +- return; ++ return -EINVAL; + } + } + +@@ -759,16 +759,19 @@ static void read_f(BlockBackend *blk, int argc, char **argv) + + gettimeofday(&t1, NULL); + if (bflag) { +- cnt = do_load_vmstate(blk, buf, offset, count, &total); ++ ret = do_load_vmstate(blk, buf, offset, count, &total); + } else { +- cnt = do_pread(blk, buf, offset, count, &total); ++ ret = do_pread(blk, buf, offset, count, &total); + } + gettimeofday(&t2, NULL); + +- if (cnt < 0) { +- printf("read failed: %s\n", strerror(-cnt)); ++ if (ret < 0) { ++ printf("read failed: %s\n", strerror(-ret)); + goto out; + } ++ cnt = ret; ++ ++ ret = 0; + + if (Pflag) { + void *cmp_buf = g_malloc(pattern_count); +@@ -777,6 +780,7 @@ static void read_f(BlockBackend *blk, int argc, char **argv) + printf("Pattern verification failed at offset %" + PRId64 ", %"PRId64" bytes\n", + offset + pattern_offset, pattern_count); ++ ret = -EINVAL; + } + g_free(cmp_buf); + } +@@ -795,6 +799,7 @@ static void read_f(BlockBackend *blk, int argc, char **argv) + + out: + qemu_io_free(buf); ++ return ret; + } + + static void readv_help(void) +@@ -816,7 +821,7 @@ static void readv_help(void) + "\n"); + } + +-static void readv_f(BlockBackend *blk, int argc, char **argv); ++static int readv_f(BlockBackend *blk, int argc, char **argv); + + static const cmdinfo_t readv_cmd = { + .name = "readv", +@@ -828,11 +833,11 @@ static const cmdinfo_t readv_cmd = { + .help = readv_help, + }; + +-static void readv_f(BlockBackend *blk, int argc, char **argv) ++static int readv_f(BlockBackend *blk, int argc, char **argv) + { + struct timeval t1, t2; + bool Cflag = false, qflag = false, vflag = false; +- int c, cnt; ++ int c, cnt, ret; + char *buf; + int64_t offset; + /* Some compilers get confused and warn if this is not initialized. */ +@@ -851,7 +856,7 @@ static void readv_f(BlockBackend *blk, int argc, char **argv) + Pflag = true; + pattern = parse_pattern(optarg); + if (pattern < 0) { +- return; ++ return -EINVAL; + } + break; + case 'q': +@@ -862,37 +867,40 @@ static void readv_f(BlockBackend *blk, int argc, char **argv) + break; + default: + qemuio_command_usage(&readv_cmd); +- return; ++ return -EINVAL; + } + } + + if (optind > argc - 2) { + qemuio_command_usage(&readv_cmd); +- return; ++ return -EINVAL; + } + + + offset = cvtnum(argv[optind]); + if (offset < 0) { + print_cvtnum_err(offset, argv[optind]); +- return; ++ return offset; + } + optind++; + + nr_iov = argc - optind; + buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, 0xab); + if (buf == NULL) { +- return; ++ return -EINVAL; + } + + gettimeofday(&t1, NULL); +- cnt = do_aio_readv(blk, &qiov, offset, &total); ++ ret = do_aio_readv(blk, &qiov, offset, &total); + gettimeofday(&t2, NULL); + +- if (cnt < 0) { +- printf("readv failed: %s\n", strerror(-cnt)); ++ if (ret < 0) { ++ printf("readv failed: %s\n", strerror(-ret)); + goto out; + } ++ cnt = ret; ++ ++ ret = 0; + + if (Pflag) { + void *cmp_buf = g_malloc(qiov.size); +@@ -900,6 +908,7 @@ static void readv_f(BlockBackend *blk, int argc, char **argv) + if (memcmp(buf, cmp_buf, qiov.size)) { + printf("Pattern verification failed at offset %" + PRId64 ", %zd bytes\n", offset, qiov.size); ++ ret = -EINVAL; + } + g_free(cmp_buf); + } +@@ -919,6 +928,7 @@ static void readv_f(BlockBackend *blk, int argc, char **argv) + out: + qemu_iovec_destroy(&qiov); + qemu_io_free(buf); ++ return ret; + } + + static void write_help(void) +@@ -944,7 +954,7 @@ static void write_help(void) + "\n"); + } + +-static void write_f(BlockBackend *blk, int argc, char **argv); ++static int write_f(BlockBackend *blk, int argc, char **argv); + + static const cmdinfo_t write_cmd = { + .name = "write", +@@ -958,13 +968,13 @@ static const cmdinfo_t write_cmd = { + .help = write_help, + }; + +-static void write_f(BlockBackend *blk, int argc, char **argv) ++static int write_f(BlockBackend *blk, int argc, char **argv) + { + struct timeval t1, t2; + bool Cflag = false, qflag = false, bflag = false; + bool Pflag = false, zflag = false, cflag = false; + int flags = 0; +- int c, cnt; ++ int c, cnt, ret; + char *buf = NULL; + int64_t offset; + int64_t count; +@@ -993,7 +1003,7 @@ static void write_f(BlockBackend *blk, int argc, char **argv) + Pflag = true; + pattern = parse_pattern(optarg); + if (pattern < 0) { +- return; ++ return -EINVAL; + } + break; + case 'q': +@@ -1007,63 +1017,63 @@ static void write_f(BlockBackend *blk, int argc, char **argv) + break; + default: + qemuio_command_usage(&write_cmd); +- return; ++ return -EINVAL; + } + } + + if (optind != argc - 2) { + qemuio_command_usage(&write_cmd); +- return; ++ return -EINVAL; + } + + if (bflag && zflag) { + printf("-b and -z cannot be specified at the same time\n"); +- return; ++ return -EINVAL; + } + + if ((flags & BDRV_REQ_FUA) && (bflag || cflag)) { + printf("-f and -b or -c cannot be specified at the same time\n"); +- return; ++ return -EINVAL; + } + + if ((flags & BDRV_REQ_MAY_UNMAP) && !zflag) { + printf("-u requires -z to be specified\n"); +- return; ++ return -EINVAL; + } + + if (zflag && Pflag) { + printf("-z and -P cannot be specified at the same time\n"); +- return; ++ return -EINVAL; + } + + offset = cvtnum(argv[optind]); + if (offset < 0) { + print_cvtnum_err(offset, argv[optind]); +- return; ++ return offset; + } + + optind++; + count = cvtnum(argv[optind]); + if (count < 0) { + print_cvtnum_err(count, argv[optind]); +- return; ++ return count; + } else if (count > BDRV_REQUEST_MAX_BYTES) { + printf("length cannot exceed %" PRIu64 ", given %s\n", + (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]); +- return; ++ return -EINVAL; + } + + if (bflag || cflag) { + if (!QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE)) { + printf("%" PRId64 " is not a sector-aligned value for 'offset'\n", + offset); +- return; ++ return -EINVAL; + } + + if (!QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE)) { + printf("%"PRId64" is not a sector-aligned value for 'count'\n", + count); +- return; ++ return -EINVAL; + } + } + +@@ -1073,20 +1083,23 @@ static void write_f(BlockBackend *blk, int argc, char **argv) + + gettimeofday(&t1, NULL); + if (bflag) { +- cnt = do_save_vmstate(blk, buf, offset, count, &total); ++ ret = do_save_vmstate(blk, buf, offset, count, &total); + } else if (zflag) { +- cnt = do_co_pwrite_zeroes(blk, offset, count, flags, &total); ++ ret = do_co_pwrite_zeroes(blk, offset, count, flags, &total); + } else if (cflag) { +- cnt = do_write_compressed(blk, buf, offset, count, &total); ++ ret = do_write_compressed(blk, buf, offset, count, &total); + } else { +- cnt = do_pwrite(blk, buf, offset, count, flags, &total); ++ ret = do_pwrite(blk, buf, offset, count, flags, &total); + } + gettimeofday(&t2, NULL); + +- if (cnt < 0) { +- printf("write failed: %s\n", strerror(-cnt)); ++ if (ret < 0) { ++ printf("write failed: %s\n", strerror(-ret)); + goto out; + } ++ cnt = ret; ++ ++ ret = 0; + + if (qflag) { + goto out; +@@ -1100,6 +1113,7 @@ out: + if (!zflag) { + qemu_io_free(buf); + } ++ return ret; + } + + static void +@@ -1121,7 +1135,7 @@ writev_help(void) + "\n"); + } + +-static void writev_f(BlockBackend *blk, int argc, char **argv); ++static int writev_f(BlockBackend *blk, int argc, char **argv); + + static const cmdinfo_t writev_cmd = { + .name = "writev", +@@ -1134,12 +1148,12 @@ static const cmdinfo_t writev_cmd = { + .help = writev_help, + }; + +-static void writev_f(BlockBackend *blk, int argc, char **argv) ++static int writev_f(BlockBackend *blk, int argc, char **argv) + { + struct timeval t1, t2; + bool Cflag = false, qflag = false; + int flags = 0; +- int c, cnt; ++ int c, cnt, ret; + char *buf; + int64_t offset; + /* Some compilers get confused and warn if this is not initialized. */ +@@ -1162,41 +1176,44 @@ static void writev_f(BlockBackend *blk, int argc, char **argv) + case 'P': + pattern = parse_pattern(optarg); + if (pattern < 0) { +- return; ++ return -EINVAL; + } + break; + default: + qemuio_command_usage(&writev_cmd); +- return; ++ return -EINVAL; + } + } + + if (optind > argc - 2) { + qemuio_command_usage(&writev_cmd); +- return; ++ return -EINVAL; + } + + offset = cvtnum(argv[optind]); + if (offset < 0) { + print_cvtnum_err(offset, argv[optind]); +- return; ++ return offset; + } + optind++; + + nr_iov = argc - optind; + buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, pattern); + if (buf == NULL) { +- return; ++ return -EINVAL; + } + + gettimeofday(&t1, NULL); +- cnt = do_aio_writev(blk, &qiov, offset, flags, &total); ++ ret = do_aio_writev(blk, &qiov, offset, flags, &total); + gettimeofday(&t2, NULL); + +- if (cnt < 0) { +- printf("writev failed: %s\n", strerror(-cnt)); ++ if (ret < 0) { ++ printf("writev failed: %s\n", strerror(-ret)); + goto out; + } ++ cnt = ret; ++ ++ ret = 0; + + if (qflag) { + goto out; +@@ -1208,6 +1225,7 @@ static void writev_f(BlockBackend *blk, int argc, char **argv) + out: + qemu_iovec_destroy(&qiov); + qemu_io_free(buf); ++ return ret; + } + + struct aio_ctx { +@@ -1314,6 +1332,9 @@ static void aio_read_help(void) + " standard output stream (with -v option) for subsequent inspection.\n" + " The read is performed asynchronously and the aio_flush command must be\n" + " used to ensure all outstanding aio requests have been completed.\n" ++" Note that due to its asynchronous nature, this command will be\n" ++" considered successful once the request is submitted, independently\n" ++" of potential I/O errors or pattern mismatches.\n" + " -C, -- report statistics in a machine parsable format\n" + " -P, -- use a pattern to verify read data\n" + " -i, -- treat request as invalid, for exercising stats\n" +@@ -1322,7 +1343,7 @@ static void aio_read_help(void) + "\n"); + } + +-static void aio_read_f(BlockBackend *blk, int argc, char **argv); ++static int aio_read_f(BlockBackend *blk, int argc, char **argv); + + static const cmdinfo_t aio_read_cmd = { + .name = "aio_read", +@@ -1334,7 +1355,7 @@ static const cmdinfo_t aio_read_cmd = { + .help = aio_read_help, + }; + +-static void aio_read_f(BlockBackend *blk, int argc, char **argv) ++static int aio_read_f(BlockBackend *blk, int argc, char **argv) + { + int nr_iov, c; + struct aio_ctx *ctx = g_new0(struct aio_ctx, 1); +@@ -1350,14 +1371,14 @@ static void aio_read_f(BlockBackend *blk, int argc, char **argv) + ctx->pattern = parse_pattern(optarg); + if (ctx->pattern < 0) { + g_free(ctx); +- return; ++ return -EINVAL; + } + break; + case 'i': + printf("injecting invalid read request\n"); + block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_READ); + g_free(ctx); +- return; ++ return 0; + case 'q': + ctx->qflag = true; + break; +@@ -1367,21 +1388,22 @@ static void aio_read_f(BlockBackend *blk, int argc, char **argv) + default: + g_free(ctx); + qemuio_command_usage(&aio_read_cmd); +- return; ++ return -EINVAL; + } + } + + if (optind > argc - 2) { + g_free(ctx); + qemuio_command_usage(&aio_read_cmd); +- return; ++ return -EINVAL; + } + + ctx->offset = cvtnum(argv[optind]); + if (ctx->offset < 0) { +- print_cvtnum_err(ctx->offset, argv[optind]); ++ int ret = ctx->offset; ++ print_cvtnum_err(ret, argv[optind]); + g_free(ctx); +- return; ++ return ret; + } + optind++; + +@@ -1390,13 +1412,14 @@ static void aio_read_f(BlockBackend *blk, int argc, char **argv) + if (ctx->buf == NULL) { + block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_READ); + g_free(ctx); +- return; ++ return -EINVAL; + } + + gettimeofday(&ctx->t1, NULL); + block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size, + BLOCK_ACCT_READ); + blk_aio_preadv(blk, ctx->offset, &ctx->qiov, 0, aio_read_done, ctx); ++ return 0; + } + + static void aio_write_help(void) +@@ -1413,6 +1436,9 @@ static void aio_write_help(void) + " filled with a set pattern (0xcdcdcdcd).\n" + " The write is performed asynchronously and the aio_flush command must be\n" + " used to ensure all outstanding aio requests have been completed.\n" ++" Note that due to its asynchronous nature, this command will be\n" ++" considered successful once the request is submitted, independently\n" ++" of potential I/O errors or pattern mismatches.\n" + " -P, -- use different pattern to fill file\n" + " -C, -- report statistics in a machine parsable format\n" + " -f, -- use Force Unit Access semantics\n" +@@ -1423,7 +1449,7 @@ static void aio_write_help(void) + "\n"); + } + +-static void aio_write_f(BlockBackend *blk, int argc, char **argv); ++static int aio_write_f(BlockBackend *blk, int argc, char **argv); + + static const cmdinfo_t aio_write_cmd = { + .name = "aio_write", +@@ -1436,7 +1462,7 @@ static const cmdinfo_t aio_write_cmd = { + .help = aio_write_help, + }; + +-static void aio_write_f(BlockBackend *blk, int argc, char **argv) ++static int aio_write_f(BlockBackend *blk, int argc, char **argv) + { + int nr_iov, c; + int pattern = 0xcd; +@@ -1462,53 +1488,54 @@ static void aio_write_f(BlockBackend *blk, int argc, char **argv) + pattern = parse_pattern(optarg); + if (pattern < 0) { + g_free(ctx); +- return; ++ return -EINVAL; + } + break; + case 'i': + printf("injecting invalid write request\n"); + block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_WRITE); + g_free(ctx); +- return; ++ return 0; + case 'z': + ctx->zflag = true; + break; + default: + g_free(ctx); + qemuio_command_usage(&aio_write_cmd); +- return; ++ return -EINVAL; + } + } + + if (optind > argc - 2) { + g_free(ctx); + qemuio_command_usage(&aio_write_cmd); +- return; ++ return -EINVAL; + } + + if (ctx->zflag && optind != argc - 2) { + printf("-z supports only a single length parameter\n"); + g_free(ctx); +- return; ++ return -EINVAL; + } + + if ((flags & BDRV_REQ_MAY_UNMAP) && !ctx->zflag) { + printf("-u requires -z to be specified\n"); + g_free(ctx); +- return; ++ return -EINVAL; + } + + if (ctx->zflag && ctx->Pflag) { + printf("-z and -P cannot be specified at the same time\n"); + g_free(ctx); +- return; ++ return -EINVAL; + } + + ctx->offset = cvtnum(argv[optind]); + if (ctx->offset < 0) { +- print_cvtnum_err(ctx->offset, argv[optind]); ++ int ret = ctx->offset; ++ print_cvtnum_err(ret, argv[optind]); + g_free(ctx); +- return; ++ return ret; + } + optind++; + +@@ -1517,7 +1544,7 @@ static void aio_write_f(BlockBackend *blk, int argc, char **argv) + if (count < 0) { + print_cvtnum_err(count, argv[optind]); + g_free(ctx); +- return; ++ return count; + } + + ctx->qiov.size = count; +@@ -1530,7 +1557,7 @@ static void aio_write_f(BlockBackend *blk, int argc, char **argv) + if (ctx->buf == NULL) { + block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_WRITE); + g_free(ctx); +- return; ++ return -EINVAL; + } + + gettimeofday(&ctx->t1, NULL); +@@ -1540,14 +1567,17 @@ static void aio_write_f(BlockBackend *blk, int argc, char **argv) + blk_aio_pwritev(blk, ctx->offset, &ctx->qiov, flags, aio_write_done, + ctx); + } ++ ++ return 0; + } + +-static void aio_flush_f(BlockBackend *blk, int argc, char **argv) ++static int aio_flush_f(BlockBackend *blk, int argc, char **argv) + { + BlockAcctCookie cookie; + block_acct_start(blk_get_stats(blk), &cookie, 0, BLOCK_ACCT_FLUSH); + blk_drain_all(); + block_acct_done(blk_get_stats(blk), &cookie); ++ return 0; + } + + static const cmdinfo_t aio_flush_cmd = { +@@ -1556,9 +1586,9 @@ static const cmdinfo_t aio_flush_cmd = { + .oneline = "completes all outstanding aio requests" + }; + +-static void flush_f(BlockBackend *blk, int argc, char **argv) ++static int flush_f(BlockBackend *blk, int argc, char **argv) + { +- blk_flush(blk); ++ return blk_flush(blk); + } + + static const cmdinfo_t flush_cmd = { +@@ -1568,7 +1598,7 @@ static const cmdinfo_t flush_cmd = { + .oneline = "flush all in-core file state to disk", + }; + +-static void truncate_f(BlockBackend *blk, int argc, char **argv) ++static int truncate_f(BlockBackend *blk, int argc, char **argv) + { + Error *local_err = NULL; + int64_t offset; +@@ -1577,14 +1607,16 @@ static void truncate_f(BlockBackend *blk, int argc, char **argv) + offset = cvtnum(argv[1]); + if (offset < 0) { + print_cvtnum_err(offset, argv[1]); +- return; ++ return offset; + } + + ret = blk_truncate(blk, offset, PREALLOC_MODE_OFF, &local_err); + if (ret < 0) { + error_report_err(local_err); +- return; ++ return ret; + } ++ ++ return 0; + } + + static const cmdinfo_t truncate_cmd = { +@@ -1598,7 +1630,7 @@ static const cmdinfo_t truncate_cmd = { + .oneline = "truncates the current file at the given offset", + }; + +-static void length_f(BlockBackend *blk, int argc, char **argv) ++static int length_f(BlockBackend *blk, int argc, char **argv) + { + int64_t size; + char s1[64]; +@@ -1606,11 +1638,12 @@ static void length_f(BlockBackend *blk, int argc, char **argv) + size = blk_getlength(blk); + if (size < 0) { + printf("getlength: %s\n", strerror(-size)); +- return; ++ return size; + } + + cvtstr(size, s1, sizeof(s1)); + printf("%s\n", s1); ++ return 0; + } + + +@@ -1622,7 +1655,7 @@ static const cmdinfo_t length_cmd = { + }; + + +-static void info_f(BlockBackend *blk, int argc, char **argv) ++static int info_f(BlockBackend *blk, int argc, char **argv) + { + BlockDriverState *bs = blk_bs(blk); + BlockDriverInfo bdi; +@@ -1639,7 +1672,7 @@ static void info_f(BlockBackend *blk, int argc, char **argv) + + ret = bdrv_get_info(bs, &bdi); + if (ret) { +- return; ++ return ret; + } + + cvtstr(bdi.cluster_size, s1, sizeof(s1)); +@@ -1654,6 +1687,8 @@ static void info_f(BlockBackend *blk, int argc, char **argv) + bdrv_image_info_specific_dump(fprintf, stdout, spec_info); + qapi_free_ImageInfoSpecific(spec_info); + } ++ ++ return 0; + } + + +@@ -1680,7 +1715,7 @@ static void discard_help(void) + "\n"); + } + +-static void discard_f(BlockBackend *blk, int argc, char **argv); ++static int discard_f(BlockBackend *blk, int argc, char **argv); + + static const cmdinfo_t discard_cmd = { + .name = "discard", +@@ -1694,7 +1729,7 @@ static const cmdinfo_t discard_cmd = { + .help = discard_help, + }; + +-static void discard_f(BlockBackend *blk, int argc, char **argv) ++static int discard_f(BlockBackend *blk, int argc, char **argv) + { + struct timeval t1, t2; + bool Cflag = false, qflag = false; +@@ -1711,31 +1746,31 @@ static void discard_f(BlockBackend *blk, int argc, char **argv) + break; + default: + qemuio_command_usage(&discard_cmd); +- return; ++ return -EINVAL; + } + } + + if (optind != argc - 2) { + qemuio_command_usage(&discard_cmd); +- return; ++ return -EINVAL; + } + + offset = cvtnum(argv[optind]); + if (offset < 0) { + print_cvtnum_err(offset, argv[optind]); +- return; ++ return offset; + } + + optind++; + bytes = cvtnum(argv[optind]); + if (bytes < 0) { + print_cvtnum_err(bytes, argv[optind]); +- return; ++ return bytes; + } else if (bytes >> BDRV_SECTOR_BITS > BDRV_REQUEST_MAX_SECTORS) { + printf("length cannot exceed %"PRIu64", given %s\n", + (uint64_t)BDRV_REQUEST_MAX_SECTORS << BDRV_SECTOR_BITS, + argv[optind]); +- return; ++ return -EINVAL; + } + + gettimeofday(&t1, NULL); +@@ -1744,7 +1779,7 @@ static void discard_f(BlockBackend *blk, int argc, char **argv) + + if (ret < 0) { + printf("discard failed: %s\n", strerror(-ret)); +- return; ++ return ret; + } + + /* Finally, report back -- -C gives a parsable format */ +@@ -1752,9 +1787,11 @@ static void discard_f(BlockBackend *blk, int argc, char **argv) + t2 = tsub(t2, t1); + print_report("discard", &t2, offset, bytes, bytes, 1, Cflag); + } ++ ++ return 0; + } + +-static void alloc_f(BlockBackend *blk, int argc, char **argv) ++static int alloc_f(BlockBackend *blk, int argc, char **argv) + { + BlockDriverState *bs = blk_bs(blk); + int64_t offset, start, remaining, count; +@@ -1765,14 +1802,14 @@ static void alloc_f(BlockBackend *blk, int argc, char **argv) + start = offset = cvtnum(argv[1]); + if (offset < 0) { + print_cvtnum_err(offset, argv[1]); +- return; ++ return offset; + } + + if (argc == 3) { + count = cvtnum(argv[2]); + if (count < 0) { + print_cvtnum_err(count, argv[2]); +- return; ++ return count; + } + } else { + count = BDRV_SECTOR_SIZE; +@@ -1784,7 +1821,7 @@ static void alloc_f(BlockBackend *blk, int argc, char **argv) + ret = bdrv_is_allocated(bs, offset, remaining, &num); + if (ret < 0) { + printf("is_allocated failed: %s\n", strerror(-ret)); +- return; ++ return ret; + } + offset += num; + remaining -= num; +@@ -1801,6 +1838,7 @@ static void alloc_f(BlockBackend *blk, int argc, char **argv) + + printf("%"PRId64"/%"PRId64" bytes allocated at offset %s\n", + sum_alloc, count, s1); ++ return 0; + } + + static const cmdinfo_t alloc_cmd = { +@@ -1846,7 +1884,7 @@ static int map_is_allocated(BlockDriverState *bs, int64_t offset, + return firstret; + } + +-static void map_f(BlockBackend *blk, int argc, char **argv) ++static int map_f(BlockBackend *blk, int argc, char **argv) + { + int64_t offset, bytes; + char s1[64], s2[64]; +@@ -1858,17 +1896,17 @@ static void map_f(BlockBackend *blk, int argc, char **argv) + bytes = blk_getlength(blk); + if (bytes < 0) { + error_report("Failed to query image length: %s", strerror(-bytes)); +- return; ++ return bytes; + } + + while (bytes) { + ret = map_is_allocated(blk_bs(blk), offset, bytes, &num); + if (ret < 0) { + error_report("Failed to get allocation status: %s", strerror(-ret)); +- return; ++ return ret; + } else if (!num) { + error_report("Unexpected end of image"); +- return; ++ return -EIO; + } + + retstr = ret ? " allocated" : "not allocated"; +@@ -1880,6 +1918,8 @@ static void map_f(BlockBackend *blk, int argc, char **argv) + offset += num; + bytes -= num; + } ++ ++ return 0; + } + + static const cmdinfo_t map_cmd = { +@@ -1907,7 +1947,7 @@ static void reopen_help(void) + "\n"); + } + +-static void reopen_f(BlockBackend *blk, int argc, char **argv); ++static int reopen_f(BlockBackend *blk, int argc, char **argv); + + static QemuOptsList reopen_opts = { + .name = "reopen", +@@ -1929,7 +1969,7 @@ static const cmdinfo_t reopen_cmd = { + .help = reopen_help, + }; + +-static void reopen_f(BlockBackend *blk, int argc, char **argv) ++static int reopen_f(BlockBackend *blk, int argc, char **argv) + { + BlockDriverState *bs = blk_bs(blk); + QemuOpts *qopts; +@@ -1947,19 +1987,19 @@ static void reopen_f(BlockBackend *blk, int argc, char **argv) + case 'c': + if (bdrv_parse_cache_mode(optarg, &flags, &writethrough) < 0) { + error_report("Invalid cache option: %s", optarg); +- return; ++ return -EINVAL; + } + break; + case 'o': + if (!qemu_opts_parse_noisily(&reopen_opts, optarg, 0)) { + qemu_opts_reset(&reopen_opts); +- return; ++ return -EINVAL; + } + break; + case 'r': + if (has_rw_option) { + error_report("Only one -r/-w option may be given"); +- return; ++ return -EINVAL; + } + flags &= ~BDRV_O_RDWR; + has_rw_option = true; +@@ -1967,7 +2007,7 @@ static void reopen_f(BlockBackend *blk, int argc, char **argv) + case 'w': + if (has_rw_option) { + error_report("Only one -r/-w option may be given"); +- return; ++ return -EINVAL; + } + flags |= BDRV_O_RDWR; + has_rw_option = true; +@@ -1975,14 +2015,14 @@ static void reopen_f(BlockBackend *blk, int argc, char **argv) + default: + qemu_opts_reset(&reopen_opts); + qemuio_command_usage(&reopen_cmd); +- return; ++ return -EINVAL; + } + } + + if (optind != argc) { + qemu_opts_reset(&reopen_opts); + qemuio_command_usage(&reopen_cmd); +- return; ++ return -EINVAL; + } + + if (writethrough != blk_enable_write_cache(blk) && +@@ -1990,7 +2030,7 @@ static void reopen_f(BlockBackend *blk, int argc, char **argv) + { + error_report("Cannot change cache.writeback: Device attached"); + qemu_opts_reset(&reopen_opts); +- return; ++ return -EBUSY; + } + + if (!(flags & BDRV_O_RDWR)) { +@@ -2016,29 +2056,37 @@ static void reopen_f(BlockBackend *blk, int argc, char **argv) + + if (local_err) { + error_report_err(local_err); +- } else { +- blk_set_enable_write_cache(blk, !writethrough); ++ return -EINVAL; + } ++ ++ blk_set_enable_write_cache(blk, !writethrough); ++ return 0; + } + +-static void break_f(BlockBackend *blk, int argc, char **argv) ++static int break_f(BlockBackend *blk, int argc, char **argv) + { + int ret; + + ret = bdrv_debug_breakpoint(blk_bs(blk), argv[1], argv[2]); + if (ret < 0) { + printf("Could not set breakpoint: %s\n", strerror(-ret)); ++ return ret; + } ++ ++ return 0; + } + +-static void remove_break_f(BlockBackend *blk, int argc, char **argv) ++static int remove_break_f(BlockBackend *blk, int argc, char **argv) + { + int ret; + + ret = bdrv_debug_remove_breakpoint(blk_bs(blk), argv[1]); + if (ret < 0) { + printf("Could not remove breakpoint %s: %s\n", argv[1], strerror(-ret)); ++ return ret; + } ++ ++ return 0; + } + + static const cmdinfo_t break_cmd = { +@@ -2060,14 +2108,17 @@ static const cmdinfo_t remove_break_cmd = { + .oneline = "remove a breakpoint by tag", + }; + +-static void resume_f(BlockBackend *blk, int argc, char **argv) ++static int resume_f(BlockBackend *blk, int argc, char **argv) + { + int ret; + + ret = bdrv_debug_resume(blk_bs(blk), argv[1]); + if (ret < 0) { + printf("Could not resume request: %s\n", strerror(-ret)); ++ return ret; + } ++ ++ return 0; + } + + static const cmdinfo_t resume_cmd = { +@@ -2079,11 +2130,12 @@ static const cmdinfo_t resume_cmd = { + .oneline = "resumes the request tagged as tag", + }; + +-static void wait_break_f(BlockBackend *blk, int argc, char **argv) ++static int wait_break_f(BlockBackend *blk, int argc, char **argv) + { + while (!bdrv_debug_is_suspended(blk_bs(blk), argv[1])) { + aio_poll(blk_get_aio_context(blk), true); + } ++ return 0; + } + + static const cmdinfo_t wait_break_cmd = { +@@ -2095,7 +2147,7 @@ static const cmdinfo_t wait_break_cmd = { + .oneline = "waits for the suspension of a request", + }; + +-static void abort_f(BlockBackend *blk, int argc, char **argv) ++static int abort_f(BlockBackend *blk, int argc, char **argv) + { + abort(); + } +@@ -2121,7 +2173,7 @@ static void sigraise_help(void) + "\n", SIGTERM); + } + +-static void sigraise_f(BlockBackend *blk, int argc, char **argv); ++static int sigraise_f(BlockBackend *blk, int argc, char **argv); + + static const cmdinfo_t sigraise_cmd = { + .name = "sigraise", +@@ -2134,16 +2186,16 @@ static const cmdinfo_t sigraise_cmd = { + .help = sigraise_help, + }; + +-static void sigraise_f(BlockBackend *blk, int argc, char **argv) ++static int sigraise_f(BlockBackend *blk, int argc, char **argv) + { + int64_t sig = cvtnum(argv[1]); + if (sig < 0) { + print_cvtnum_err(sig, argv[1]); +- return; ++ return sig; + } else if (sig > NSIG) { + printf("signal argument '%s' is too large to be a valid signal\n", + argv[1]); +- return; ++ return -EINVAL; + } + + /* Using raise() to kill this process does not necessarily flush all open +@@ -2153,6 +2205,8 @@ static void sigraise_f(BlockBackend *blk, int argc, char **argv) + fflush(stderr); + + raise(sig); ++ ++ return 0; + } + + static void sleep_cb(void *opaque) +@@ -2161,7 +2215,7 @@ static void sleep_cb(void *opaque) + *expired = true; + } + +-static void sleep_f(BlockBackend *blk, int argc, char **argv) ++static int sleep_f(BlockBackend *blk, int argc, char **argv) + { + char *endptr; + long ms; +@@ -2171,7 +2225,7 @@ static void sleep_f(BlockBackend *blk, int argc, char **argv) + ms = strtol(argv[1], &endptr, 0); + if (ms < 0 || *endptr != '\0') { + printf("%s is not a valid number\n", argv[1]); +- return; ++ return -EINVAL; + } + + timer = timer_new_ns(QEMU_CLOCK_HOST, sleep_cb, &expired); +@@ -2182,6 +2236,7 @@ static void sleep_f(BlockBackend *blk, int argc, char **argv) + } + + timer_free(timer); ++ return 0; + } + + static const cmdinfo_t sleep_cmd = { +@@ -2228,22 +2283,23 @@ static void help_all(void) + printf("\nUse 'help commandname' for extended help.\n"); + } + +-static void help_f(BlockBackend *blk, int argc, char **argv) ++static int help_f(BlockBackend *blk, int argc, char **argv) + { + const cmdinfo_t *ct; + + if (argc == 1) { + help_all(); +- return; ++ return 0; + } + + ct = find_command(argv[1]); + if (ct == NULL) { + printf("command %s not found\n", argv[1]); +- return; ++ return -EINVAL; + } + + help_onecmd(argv[1], ct); ++ return 0; + } + + static const cmdinfo_t help_cmd = { +@@ -2257,13 +2313,14 @@ static const cmdinfo_t help_cmd = { + .oneline = "help for one or all commands", + }; + +-void qemuio_command(BlockBackend *blk, const char *cmd) ++int qemuio_command(BlockBackend *blk, const char *cmd) + { + AioContext *ctx; + char *input; + const cmdinfo_t *ct; + char **v; + int c; ++ int ret = 0; + + input = g_strdup(cmd); + v = breakline(input, &c); +@@ -2272,14 +2329,17 @@ void qemuio_command(BlockBackend *blk, const char *cmd) + if (ct) { + ctx = blk ? blk_get_aio_context(blk) : qemu_get_aio_context(); + aio_context_acquire(ctx); +- command(blk, ct, c, v); ++ ret = command(blk, ct, c, v); + aio_context_release(ctx); + } else { + fprintf(stderr, "command \"%s\" not found\n", v[0]); ++ ret = -EINVAL; + } + } + g_free(input); + g_free(v); ++ ++ return ret; + } + + static void __attribute((constructor)) init_qemuio_commands(void) +diff --git a/qemu-io.c b/qemu-io.c +index 02a67c9..ec66838 100644 +--- a/qemu-io.c ++++ b/qemu-io.c +@@ -66,10 +66,11 @@ static int get_eof_char(void) + #endif + } + +-static void close_f(BlockBackend *blk, int argc, char **argv) ++static int close_f(BlockBackend *blk, int argc, char **argv) + { + blk_unref(qemuio_blk); + qemuio_blk = NULL; ++ return 0; + } + + static const cmdinfo_t close_cmd = { +@@ -136,7 +137,7 @@ static void open_help(void) + "\n"); + } + +-static void open_f(BlockBackend *blk, int argc, char **argv); ++static int open_f(BlockBackend *blk, int argc, char **argv); + + static const cmdinfo_t open_cmd = { + .name = "open", +@@ -160,12 +161,13 @@ static QemuOptsList empty_opts = { + }, + }; + +-static void open_f(BlockBackend *blk, int argc, char **argv) ++static int open_f(BlockBackend *blk, int argc, char **argv) + { + int flags = BDRV_O_UNMAP; + int readonly = 0; + bool writethrough = true; + int c; ++ int ret; + QemuOpts *qopts; + QDict *opts; + bool force_share = false; +@@ -192,25 +194,25 @@ static void open_f(BlockBackend *blk, int argc, char **argv) + if (bdrv_parse_cache_mode(optarg, &flags, &writethrough) < 0) { + error_report("Invalid cache option: %s", optarg); + qemu_opts_reset(&empty_opts); +- return; ++ return -EINVAL; + } + break; + case 'd': + if (bdrv_parse_discard_flags(optarg, &flags) < 0) { + error_report("Invalid discard option: %s", optarg); + qemu_opts_reset(&empty_opts); +- return; ++ return -EINVAL; + } + break; + case 'o': + if (imageOpts) { + printf("--image-opts and 'open -o' are mutually exclusive\n"); + qemu_opts_reset(&empty_opts); +- return; ++ return -EINVAL; + } + if (!qemu_opts_parse_noisily(&empty_opts, optarg, false)) { + qemu_opts_reset(&empty_opts); +- return; ++ return -EINVAL; + } + break; + case 'U': +@@ -219,7 +221,7 @@ static void open_f(BlockBackend *blk, int argc, char **argv) + default: + qemu_opts_reset(&empty_opts); + qemuio_command_usage(&open_cmd); +- return; ++ return -EINVAL; + } + } + +@@ -230,7 +232,7 @@ static void open_f(BlockBackend *blk, int argc, char **argv) + if (imageOpts && (optind == argc - 1)) { + if (!qemu_opts_parse_noisily(&empty_opts, argv[optind], false)) { + qemu_opts_reset(&empty_opts); +- return; ++ return -EINVAL; + } + optind++; + } +@@ -240,18 +242,26 @@ static void open_f(BlockBackend *blk, int argc, char **argv) + qemu_opts_reset(&empty_opts); + + if (optind == argc - 1) { +- openfile(argv[optind], flags, writethrough, force_share, opts); ++ ret = openfile(argv[optind], flags, writethrough, force_share, opts); + } else if (optind == argc) { +- openfile(NULL, flags, writethrough, force_share, opts); ++ ret = openfile(NULL, flags, writethrough, force_share, opts); + } else { + qobject_unref(opts); + qemuio_command_usage(&open_cmd); ++ return -EINVAL; ++ } ++ ++ if (ret) { ++ return -EINVAL; + } ++ ++ return 0; + } + +-static void quit_f(BlockBackend *blk, int argc, char **argv) ++static int quit_f(BlockBackend *blk, int argc, char **argv) + { + quit_qemu_io = true; ++ return 0; + } + + static const cmdinfo_t quit_cmd = { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-io-Use-purely-string-blockdev-options.patch b/SOURCES/kvm-qemu-io-Use-purely-string-blockdev-options.patch new file mode 100644 index 0000000..e656b42 --- /dev/null +++ b/SOURCES/kvm-qemu-io-Use-purely-string-blockdev-options.patch @@ -0,0 +1,65 @@ +From 31e4b214ef764476e99ddbbfd4b039235e3a4ea1 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 25 Jun 2018 13:04:46 +0200 +Subject: [PATCH 37/54] qemu-io: Use purely string blockdev options + +RH-Author: Max Reitz +Message-id: <20180618163106.23010-2-mreitz@redhat.com> +Patchwork-id: 80775 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 1/3] qemu-io: Use purely string blockdev options +Bugzilla: 1576598 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Fam Zheng +RH-Acked-by: Miroslav Rezanina + +Currently, qemu-io only uses string-valued blockdev options (as all are +converted directly from QemuOpts) -- with one exception: -U adds the +force-share option as a boolean. This in itself is already a bit +questionable, but a real issue is that it also assumes the value already +existing in the options QDict would be a boolean, which is wrong. + +That has the following effect: + +$ ./qemu-io -r -U --image-opts \ + driver=file,filename=/dev/null,force-share=off +[1] 15200 segmentation fault (core dumped) ./qemu-io -r -U +--image-opts driver=file,filename=/dev/null,force-share=off + +Since @opts is converted from QemuOpts, the value must be a string, and +we have to compare it as such. Consequently, it makes sense to also set +it as a string instead of a boolean. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Max Reitz +Message-id: 20180502202051.15493-2-mreitz@redhat.com +Reviewed-by: Eric Blake +Signed-off-by: Max Reitz +(cherry picked from commit 2a01c01f9ecb43af4c0a85fe6adc429ffc9c31b5) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + qemu-io.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/qemu-io.c b/qemu-io.c +index 72fee0d..73c638f 100644 +--- a/qemu-io.c ++++ b/qemu-io.c +@@ -95,12 +95,12 @@ static int openfile(char *name, int flags, bool writethrough, bool force_share, + opts = qdict_new(); + } + if (qdict_haskey(opts, BDRV_OPT_FORCE_SHARE) +- && !qdict_get_bool(opts, BDRV_OPT_FORCE_SHARE)) { ++ && strcmp(qdict_get_str(opts, BDRV_OPT_FORCE_SHARE), "on")) { + error_report("-U conflicts with image options"); + qobject_unref(opts); + return 1; + } +- qdict_put_bool(opts, BDRV_OPT_FORCE_SHARE, true); ++ qdict_put_str(opts, BDRV_OPT_FORCE_SHARE, "on"); + } + qemuio_blk = blk_new_open(name, NULL, opts, flags, &local_err); + if (!qemuio_blk) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-iotest-add-test-for-blockjob-coroutine-race-con.patch b/SOURCES/kvm-qemu-iotest-add-test-for-blockjob-coroutine-race-con.patch deleted file mode 100644 index b66a394..0000000 --- a/SOURCES/kvm-qemu-iotest-add-test-for-blockjob-coroutine-race-con.patch +++ /dev/null @@ -1,165 +0,0 @@ -From 1d27a8067135c09ecbb2aa7e4af6184aba67e86c Mon Sep 17 00:00:00 2001 -From: Miroslav Rezanina -Date: Mon, 11 Dec 2017 09:06:23 +0100 -Subject: [PATCH 06/21] qemu-iotest: add test for blockjob coroutine race - condition - -RH-Author: Jeffrey Cody -Message-id: -Patchwork-id: 78042 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 06/11] qemu-iotest: add test for blockjob coroutine race condition -Bugzilla: 1506531 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: John Snow - -Signed-off-by: Jeff Cody -Reviewed-by: Stefan Hajnoczi -(cherry picked from commit d975301dc8ae56fb3154348878e47a6211843c0b) -Signed-off-by: Jeff Cody -Signed-off-by: Miroslav Rezanina ---- - tests/qemu-iotests/200 | 99 ++++++++++++++++++++++++++++++++++++++++++++++ - tests/qemu-iotests/200.out | 14 +++++++ - tests/qemu-iotests/group | 1 + - 3 files changed, 114 insertions(+) - create mode 100644 tests/qemu-iotests/200 - create mode 100644 tests/qemu-iotests/200.out - -diff --git a/tests/qemu-iotests/200 b/tests/qemu-iotests/200 -new file mode 100644 -index 0000000..d8787dd ---- /dev/null -+++ b/tests/qemu-iotests/200 -@@ -0,0 +1,99 @@ -+#!/bin/bash -+# -+# Block job co-routine race condition test. -+# -+# See: https://bugzilla.redhat.com/show_bug.cgi?id=1508708 -+# -+# Copyright (C) 2017 Red Hat, Inc. -+# -+# This program is free software; you can redistribute it and/or modify -+# it under the terms of the GNU General Public License as published by -+# the Free Software Foundation; either version 2 of the License, or -+# (at your option) any later version. -+# -+# This program is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with this program. If not, see . -+# -+ -+# creator -+owner=jcody@redhat.com -+ -+seq=`basename $0` -+echo "QA output created by $seq" -+ -+here=`pwd` -+status=1 # failure is the default! -+ -+_cleanup() -+{ -+ _cleanup_qemu -+ rm -f "${TEST_IMG}" "${BACKING_IMG}" -+} -+trap "_cleanup; exit \$status" 0 1 2 3 15 -+ -+# get standard environment, filters and checks -+. ./common.rc -+. ./common.filter -+. ./common.qemu -+ -+_supported_fmt qcow2 qed -+_supported_proto file -+_supported_os Linux -+ -+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 -+ -+${QEMU_IO} -c "write -P 0xa5 512 300M" "${BACKING_IMG}" | _filter_qemu_io -+ -+echo -+echo === Starting QEMU VM === -+echo -+qemu_comm_method="qmp" -+_launch_qemu -device pci-bridge,id=bridge1,chassis_nr=1,bus=pci.0 \ -+ -object iothread,id=iothread0 \ -+ -device virtio-scsi-pci,bus=bridge1,addr=0x1f,id=scsi0,iothread=iothread0 \ -+ -drive file="${TEST_IMG}",media=disk,if=none,cache=none,id=drive_sysdisk,aio=native,format=$IMGFMT \ -+ -device scsi-hd,drive=drive_sysdisk,bus=scsi0.0,id=sysdisk,bootindex=0 -+h1=$QEMU_HANDLE -+ -+_send_qemu_cmd $h1 "{ 'execute': 'qmp_capabilities' }" 'return' -+ -+echo -+echo === Sending stream/cancel, checking for SIGSEGV only === -+echo -+for (( i=1;i<500;i++ )) -+do -+ mismatch_only='y' qemu_error_no_exit='n' _send_qemu_cmd $h1 \ -+ "{ -+ 'execute': 'block-stream', -+ 'arguments': { -+ 'device': 'drive_sysdisk', -+ 'speed': 10000000, -+ 'on-error': 'report', -+ 'job-id': 'job-$i' -+ } -+ } -+ { -+ 'execute': 'block-job-cancel', -+ 'arguments': { -+ 'device': 'job-$i' -+ } -+ }" \ -+ "{.*{.*}.*}" # should match all well-formed QMP responses -+done -+ -+silent='y' _send_qemu_cmd $h1 "{ 'execute': 'quit' }" 'return' -+ -+echo "$i iterations performed" -+ -+echo "*** done" -+rm -f $seq.full -+status=0 -diff --git a/tests/qemu-iotests/200.out b/tests/qemu-iotests/200.out -new file mode 100644 -index 0000000..af6a809 ---- /dev/null -+++ b/tests/qemu-iotests/200.out -@@ -0,0 +1,14 @@ -+QA output created by 200 -+Formatting 'TEST_DIR/backing.img', fmt=IMGFMT size=536870912 -+Formatting 'TEST_DIR/test.img', fmt=IMGFMT size=536870912 backing_file=TEST_DIR/backing.img backing_fmt=IMGFMT -+wrote 314572800/314572800 bytes at offset 512 -+300 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+=== Starting QEMU VM === -+ -+{"return": {}} -+ -+=== Sending stream/cancel, checking for SIGSEGV only === -+ -+500 iterations performed -+*** done -diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group -index 491a5f5..39b61ce 100644 ---- a/tests/qemu-iotests/group -+++ b/tests/qemu-iotests/group -@@ -190,3 +190,4 @@ - 194 rw auto migration quick - 195 rw auto quick - 198 rw auto -+200 rw auto --- -1.8.3.1 - diff --git a/SOURCES/kvm-qemu-iotests-Add-VM.get_qmp_events_filtered.patch b/SOURCES/kvm-qemu-iotests-Add-VM.get_qmp_events_filtered.patch new file mode 100644 index 0000000..cd39ba4 --- /dev/null +++ b/SOURCES/kvm-qemu-iotests-Add-VM.get_qmp_events_filtered.patch @@ -0,0 +1,46 @@ +From a1633706e8bd21f323a9718b495b101590b9c985 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:41 +0200 +Subject: [PATCH 72/89] qemu-iotests: Add VM.get_qmp_events_filtered() + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-59-kwolf@redhat.com> +Patchwork-id: 81122 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 58/73] qemu-iotests: Add VM.get_qmp_events_filtered() +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This adds a helper function that returns a list of QMP events that are +already filtered through filter_qmp_event(). + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +Reviewed-by: Jeff Cody +(cherry picked from commit 5ad1dbf76a97b6f07d685585175832e990fe9a92) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/iotests.py | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py +index daf008a..7e311ed 100644 +--- a/tests/qemu-iotests/iotests.py ++++ b/tests/qemu-iotests/iotests.py +@@ -392,6 +392,11 @@ class VM(qtest.QEMUQtestMachine): + output_list += [key + '=' + obj[key]] + return ','.join(output_list) + ++ def get_qmp_events_filtered(self, wait=True): ++ result = [] ++ for ev in self.get_qmp_events(wait=wait): ++ result.append(filter_qmp_event(ev)) ++ return result + + + index_re = re.compile(r'([^\[]+)\[([^\]]+)\]') +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-iotests-Add-VM.qmp_log.patch b/SOURCES/kvm-qemu-iotests-Add-VM.qmp_log.patch new file mode 100644 index 0000000..fc05bf5 --- /dev/null +++ b/SOURCES/kvm-qemu-iotests-Add-VM.qmp_log.patch @@ -0,0 +1,59 @@ +From d44774708b8db31c5e2658ea64ee930ffdae39be Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:42 +0200 +Subject: [PATCH 73/89] qemu-iotests: Add VM.qmp_log() + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-60-kwolf@redhat.com> +Patchwork-id: 81067 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 59/73] qemu-iotests: Add VM.qmp_log() +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This adds a helper function that logs both the QMP request and the +received response before returning it. + +Signed-off-by: Kevin Wolf +Reviewed-by: Jeff Cody +Reviewed-by: Max Reitz +(cherry picked from commit e234398a8e142fd0cfe571f7efb0e6a2f34fe73d) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/iotests.py | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py +index 7e311ed..bc5731a 100644 +--- a/tests/qemu-iotests/iotests.py ++++ b/tests/qemu-iotests/iotests.py +@@ -215,6 +215,10 @@ def filter_qmp_event(event): + event['timestamp']['microseconds'] = 'USECS' + return event + ++def filter_testfiles(msg): ++ prefix = os.path.join(test_dir, "%s-" % (os.getpid())) ++ return msg.replace(prefix, 'TEST_DIR/PID-') ++ + def log(msg, filters=[]): + for flt in filters: + msg = flt(msg) +@@ -398,6 +402,13 @@ class VM(qtest.QEMUQtestMachine): + result.append(filter_qmp_event(ev)) + return result + ++ def qmp_log(self, cmd, filters=[filter_testfiles], **kwargs): ++ logmsg = "{'execute': '%s', 'arguments': %s}" % (cmd, kwargs) ++ log(logmsg, filters) ++ result = self.qmp(cmd, **kwargs) ++ log(str(result), filters) ++ return result ++ + + index_re = re.compile(r'([^\[]+)\[([^\]]+)\]') + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-iotests-Add-VM.run_job.patch b/SOURCES/kvm-qemu-iotests-Add-VM.run_job.patch new file mode 100644 index 0000000..ff0c2d5 --- /dev/null +++ b/SOURCES/kvm-qemu-iotests-Add-VM.run_job.patch @@ -0,0 +1,61 @@ +From f841d0a47ba5ba9a731d41e949f4261bd335a2c2 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:44 +0200 +Subject: [PATCH 75/89] qemu-iotests: Add VM.run_job() + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-62-kwolf@redhat.com> +Patchwork-id: 81080 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 61/73] qemu-iotests: Add VM.run_job() +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +Add an iotests.py function that runs a job and only returns when it is +destroyed. An error is logged when the job failed and job-finalize and +job-dismiss commands are issued if necessary. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +Reviewed-by: Jeff Cody +(cherry picked from commit fc47d8513b45b1968b0ae32d4bb2f96d3aca066a) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/iotests.py | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py +index 4b0760f..390da6b 100644 +--- a/tests/qemu-iotests/iotests.py ++++ b/tests/qemu-iotests/iotests.py +@@ -427,6 +427,25 @@ class VM(qtest.QEMUQtestMachine): + log(str(result), filters) + return result + ++ def run_job(self, job, auto_finalize=True, auto_dismiss=False): ++ while True: ++ for ev in self.get_qmp_events_filtered(wait=True): ++ if ev['event'] == 'JOB_STATUS_CHANGE': ++ status = ev['data']['status'] ++ if status == 'aborting': ++ result = self.qmp('query-jobs') ++ for j in result['return']: ++ if j['id'] == job: ++ log('Job failed: %s' % (j['error'])) ++ elif status == 'pending' and not auto_finalize: ++ self.qmp_log('job-finalize', id=job) ++ elif status == 'concluded' and not auto_dismiss: ++ self.qmp_log('job-dismiss', id=job) ++ elif status == 'null': ++ return ++ else: ++ iotests.log(ev) ++ + + index_re = re.compile(r'([^\[]+)\[([^\]]+)\]') + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-iotests-Add-iotests.img_info_log.patch b/SOURCES/kvm-qemu-iotests-Add-iotests.img_info_log.patch new file mode 100644 index 0000000..83a047f --- /dev/null +++ b/SOURCES/kvm-qemu-iotests-Add-iotests.img_info_log.patch @@ -0,0 +1,67 @@ +From ca9184bc1b0c0748b2c2e1395518f402be6f69e3 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:43 +0200 +Subject: [PATCH 74/89] qemu-iotests: Add iotests.img_info_log() + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-61-kwolf@redhat.com> +Patchwork-id: 81082 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 60/73] qemu-iotests: Add iotests.img_info_log() +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This adds a filter function to postprocess 'qemu-img info' input +(similar to what _img_info does), and an img_info_log() function that +calls 'qemu-img info' and logs the filtered output. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +Reviewed-by: Jeff Cody +(cherry picked from commit 6b605adec4d7491488d9cfb50bc256e667d8caf1) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/iotests.py | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py +index bc5731a..4b0760f 100644 +--- a/tests/qemu-iotests/iotests.py ++++ b/tests/qemu-iotests/iotests.py +@@ -109,6 +109,12 @@ def qemu_img_pipe(*args): + sys.stderr.write('qemu-img received signal %i: %s\n' % (-exitcode, ' '.join(qemu_img_args + list(args)))) + return subp.communicate()[0] + ++def img_info_log(filename, filter_path=None): ++ output = qemu_img_pipe('info', '-f', imgfmt, filename) ++ if not filter_path: ++ filter_path = filename ++ log(filter_img_info(output, filter_path)) ++ + def qemu_io(*args): + '''Run qemu-io and return the stdout data''' + args = qemu_io_args + list(args) +@@ -219,6 +225,18 @@ def filter_testfiles(msg): + prefix = os.path.join(test_dir, "%s-" % (os.getpid())) + return msg.replace(prefix, 'TEST_DIR/PID-') + ++def filter_img_info(output, filename): ++ lines = [] ++ for line in output.split('\n'): ++ if 'disk size' in line or 'actual-size' in line: ++ continue ++ line = line.replace(filename, 'TEST_IMG') \ ++ .replace(imgfmt, 'IMGFMT') ++ line = re.sub('iters: [0-9]+', 'iters: XXX', line) ++ line = re.sub('uuid: [-a-f0-9]+', 'uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', line) ++ lines.append(line) ++ return '\n'.join(lines) ++ + def log(msg, filters=[]): + for flt in filters: + msg = flt(msg) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-iotests-Rewrite-206-for-blockdev-create-job.patch b/SOURCES/kvm-qemu-iotests-Rewrite-206-for-blockdev-create-job.patch new file mode 100644 index 0000000..3ac27b4 --- /dev/null +++ b/SOURCES/kvm-qemu-iotests-Rewrite-206-for-blockdev-create-job.patch @@ -0,0 +1,1080 @@ +From 9b3ed457aa8c255cb8a5975f5aacd149d0b0397a Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:46 +0200 +Subject: [PATCH 77/89] qemu-iotests: Rewrite 206 for blockdev-create job + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-64-kwolf@redhat.com> +Patchwork-id: 81077 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 63/73] qemu-iotests: Rewrite 206 for blockdev-create job +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This rewrites the test case 206 to work with the new x-blockdev-create +job rather than the old synchronous version of the command. + +All of the test cases stay the same as before, but in order to be able +to implement proper job handling, the test case is rewritten in Python. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +(cherry picked from commit 4de110f8fd2811171013254fd7ed2384f1de87b4) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/206 | 680 ++++++++++++++++++--------------------------- + tests/qemu-iotests/206.out | 253 ++++++++++------- + tests/qemu-iotests/group | 2 +- + 3 files changed, 414 insertions(+), 521 deletions(-) + +diff --git a/tests/qemu-iotests/206 b/tests/qemu-iotests/206 +index 0a18b2b..b8cf2e7 100755 +--- a/tests/qemu-iotests/206 ++++ b/tests/qemu-iotests/206 +@@ -1,9 +1,11 @@ +-#!/bin/bash ++#!/usr/bin/env python + # + # Test qcow2 and file image creation + # + # Copyright (C) 2018 Red Hat, Inc. + # ++# Creator/Owner: Kevin Wolf ++# + # 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 +@@ -18,419 +20,263 @@ + # along with this program. If not, see . + # + +-# creator +-owner=kwolf@redhat.com +- +-seq=`basename $0` +-echo "QA output created by $seq" +- +-here=`pwd` +-status=1 # failure is the default! +- +-# get standard environment, filters and checks +-. ./common.rc +-. ./common.filter +- +-_supported_fmt qcow2 +-_supported_proto file +-_supported_os Linux +- +-function do_run_qemu() +-{ +- echo Testing: "$@" +- $QEMU -nographic -qmp stdio -serial none "$@" +- echo +-} +- +-function run_qemu() +-{ +- do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \ +- | _filter_qemu | _filter_imgfmt \ +- | _filter_actual_image_size +-} +- +-echo +-echo "=== Successful image creation (defaults) ===" +-echo +- +-size=$((128 * 1024 * 1024)) +- +-run_qemu < +Date: Tue, 26 Jun 2018 09:48:47 +0200 +Subject: [PATCH 78/89] qemu-iotests: Rewrite 207 for blockdev-create job + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-65-kwolf@redhat.com> +Patchwork-id: 81083 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 64/73] qemu-iotests: Rewrite 207 for blockdev-create job +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This rewrites the test case 207 to work with the new x-blockdev-create +job rather than the old synchronous version of the command. + +Most of the test cases stay the same as before (the exception being some +improved 'size' options that allow distinguishing which command created +the image), but in order to be able to implement proper job handling, +the test case is rewritten in Python. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +(cherry picked from commit 00af19359e8d77e53a09de9a5d3ed6f6e149e0d2) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/207 | 440 ++++++++++++++++++++------------------------- + tests/qemu-iotests/207.out | 107 +++++------ + tests/qemu-iotests/group | 6 +- + 3 files changed, 257 insertions(+), 296 deletions(-) + +diff --git a/tests/qemu-iotests/207 b/tests/qemu-iotests/207 +index f5c7785..b595c92 100755 +--- a/tests/qemu-iotests/207 ++++ b/tests/qemu-iotests/207 +@@ -1,9 +1,11 @@ +-#!/bin/bash ++#!/usr/bin/env python + # + # Test ssh image creation + # + # Copyright (C) 2018 Red Hat, Inc. + # ++# Creator/Owner: Kevin Wolf ++# + # 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 +@@ -18,244 +20,198 @@ + # along with this program. If not, see . + # + +-# creator +-owner=kwolf@redhat.com +- +-seq=`basename $0` +-echo "QA output created by $seq" +- +-here=`pwd` +-status=1 # failure is the default! +- +-# get standard environment, filters and checks +-. ./common.rc +-. ./common.filter +- +-_supported_fmt raw +-_supported_proto ssh +-_supported_os Linux +- +-function do_run_qemu() +-{ +- echo Testing: "$@" +- $QEMU -nographic -qmp stdio -serial none "$@" +- echo +-} +- +-function run_qemu() +-{ +- do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \ +- | _filter_qemu | _filter_imgfmt \ +- | _filter_actual_image_size +-} +- +-echo +-echo "=== Successful image creation (defaults) ===" +-echo +- +-run_qemu </dev/null | grep -v "\\^#" | +- cut -d" " -f3 | base64 -d | md5sum -b | cut -d" " -f1) +- +-run_qemu </dev/null | grep -v "\\^#" | +- cut -d" " -f3 | base64 -d | sha1sum -b | cut -d" " -f1) +- +-run_qemu </dev/null | grep -v "\\^#" | ' + ++ 'cut -d" " -f3 | base64 -d | md5sum -b | cut -d" " -f1', ++ shell=True).rstrip() ++ ++ vm.launch() ++ blockdev_create(vm, { 'driver': 'ssh', ++ 'location': { ++ 'path': disk_path, ++ 'server': { ++ 'host': '127.0.0.1', ++ 'port': '22' ++ }, ++ 'host-key-check': { ++ 'mode': 'hash', ++ 'type': 'md5', ++ 'hash': 'wrong', ++ } ++ }, ++ 'size': 2097152 }) ++ blockdev_create(vm, { 'driver': 'ssh', ++ 'location': { ++ 'path': disk_path, ++ 'server': { ++ 'host': '127.0.0.1', ++ 'port': '22' ++ }, ++ 'host-key-check': { ++ 'mode': 'hash', ++ 'type': 'md5', ++ 'hash': md5_key, ++ } ++ }, ++ 'size': 8388608 }) ++ vm.shutdown() ++ ++ iotests.img_info_log(remote_path, filter_path=disk_path) ++ ++ sha1_key = subprocess.check_output( ++ 'ssh-keyscan -t rsa 127.0.0.1 2>/dev/null | grep -v "\\^#" | ' + ++ 'cut -d" " -f3 | base64 -d | sha1sum -b | cut -d" " -f1', ++ shell=True).rstrip() ++ ++ vm.launch() ++ blockdev_create(vm, { 'driver': 'ssh', ++ 'location': { ++ 'path': disk_path, ++ 'server': { ++ 'host': '127.0.0.1', ++ 'port': '22' ++ }, ++ 'host-key-check': { ++ 'mode': 'hash', ++ 'type': 'sha1', ++ 'hash': 'wrong', ++ } ++ }, ++ 'size': 2097152 }) ++ blockdev_create(vm, { 'driver': 'ssh', ++ 'location': { ++ 'path': disk_path, ++ 'server': { ++ 'host': '127.0.0.1', ++ 'port': '22' ++ }, ++ 'host-key-check': { ++ 'mode': 'hash', ++ 'type': 'sha1', ++ 'hash': sha1_key, ++ } ++ }, ++ 'size': 4194304 }) ++ vm.shutdown() ++ ++ iotests.img_info_log(remote_path, filter_path=disk_path) ++ ++ # ++ # Invalid path and user ++ # ++ iotests.log("=== Invalid path and user ===") ++ iotests.log("") ++ ++ vm.launch() ++ blockdev_create(vm, { 'driver': 'ssh', ++ 'location': { ++ 'path': '/this/is/not/an/existing/path', ++ 'server': { ++ 'host': '127.0.0.1', ++ 'port': '22' ++ }, ++ 'host-key-check': { ++ 'mode': 'none' ++ } ++ }, ++ 'size': 4194304 }) ++ blockdev_create(vm, { 'driver': 'ssh', ++ 'location': { ++ 'path': disk_path, ++ 'user': 'invalid user', ++ 'server': { ++ 'host': '127.0.0.1', ++ 'port': '22' ++ }, ++ 'host-key-check': { ++ 'mode': 'none' ++ } ++ }, ++ 'size': 4194304 }) ++ vm.shutdown() +diff --git a/tests/qemu-iotests/207.out b/tests/qemu-iotests/207.out +index 417deee..5eee17b 100644 +--- a/tests/qemu-iotests/207.out ++++ b/tests/qemu-iotests/207.out +@@ -1,75 +1,80 @@ +-QA output created by 207 +- + === Successful image creation (defaults) === + +-Testing: +-QMP_VERSION +-{"return": {}} +-{"return": {}} +-{"return": {}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} ++{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}} ++{u'return': {}} ++{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} ++{u'return': {}} + +-image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}} ++image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}} + file format: IMGFMT + virtual size: 4.0M (4194304 bytes) + +-image: TEST_DIR/t.IMGFMT ++ ++image: TEST_IMG + file format: IMGFMT + virtual size: 4.0M (4194304 bytes) + + === Test host-key-check options === + +-Testing: +-QMP_VERSION +-{"return": {}} +-{"return": {}} +-{"return": {}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} ++{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'mode': 'none'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 8388608}}} ++{u'return': {}} ++{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} ++{u'return': {}} + +-image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}} ++image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}} + file format: IMGFMT + virtual size: 8.0M (8388608 bytes) +-Testing: +-QMP_VERSION +-{"return": {}} +-{"return": {}} +-{"return": {}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} +- +-image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}} ++ ++{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'mode': 'known_hosts'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}} ++{u'return': {}} ++{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} ++{u'return': {}} ++ ++image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}} + file format: IMGFMT + virtual size: 4.0M (4194304 bytes) +-Testing: +-QMP_VERSION +-{"return": {}} +-{"error": {"class": "GenericError", "desc": "remote host key does not match host_key_check 'wrong'"}} +-{"return": {}} +-{"return": {}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} +- +-image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}} ++ ++{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': 'wrong', 'type': 'md5', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 2097152}}} ++{u'return': {}} ++Job failed: remote host key does not match host_key_check 'wrong' ++{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} ++{u'return': {}} ++ ++{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': HASH, 'type': 'md5', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 8388608}}} ++{u'return': {}} ++{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} ++{u'return': {}} ++ ++image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}} + file format: IMGFMT + virtual size: 8.0M (8388608 bytes) +-Testing: +-QMP_VERSION +-{"return": {}} +-{"error": {"class": "GenericError", "desc": "remote host key does not match host_key_check 'wrong'"}} +-{"return": {}} +-{"return": {}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} +- +-image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}} ++ ++{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': 'wrong', 'type': 'sha1', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 2097152}}} ++{u'return': {}} ++Job failed: remote host key does not match host_key_check 'wrong' ++{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} ++{u'return': {}} ++ ++{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'hash': HASH, 'type': 'sha1', 'mode': 'hash'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}} ++{u'return': {}} ++{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} ++{u'return': {}} ++ ++image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}} + file format: IMGFMT + virtual size: 4.0M (4194304 bytes) + + === Invalid path and user === + +-Testing: +-QMP_VERSION +-{"return": {}} +-{"error": {"class": "GenericError", "desc": "failed to open remote file '/this/is/not/an/existing/path': Failed opening remote file (libssh2 error code: -31)"}} +-{"error": {"class": "GenericError", "desc": "failed to authenticate using publickey authentication and the identities held by your ssh-agent"}} +-{"return": {}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} ++{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': '/this/is/not/an/existing/path', 'host-key-check': {'mode': 'none'}, 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}} ++{u'return': {}} ++Job failed: failed to open remote file '/this/is/not/an/existing/path': Failed opening remote file (libssh2 error code: -31) ++{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} ++{u'return': {}} ++ ++{'execute': 'x-blockdev-create', 'arguments': {'job_id': 'job0', 'options': {'driver': 'ssh', 'location': {'path': 'TEST_DIR/PID-t.img', 'host-key-check': {'mode': 'none'}, 'user': 'invalid user', 'server': {'host': '127.0.0.1', 'port': '22'}}, 'size': 4194304}}} ++{u'return': {}} ++Job failed: failed to authenticate using publickey authentication and the identities held by your ssh-agent ++{'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} ++{u'return': {}} + +-*** done +diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group +index 3d6ae02..649291a 100644 +--- a/tests/qemu-iotests/group ++++ b/tests/qemu-iotests/group +@@ -205,11 +205,11 @@ + 204 rw auto quick + 205 rw auto quick + 206 rw auto +-# TODO The following commented out tests need to be reworked to work +-# with the x-blockdev-create job +-#207 rw auto ++207 rw auto + 208 rw auto quick + 209 rw auto quick ++# TODO The following commented out tests need to be reworked to work ++# with the x-blockdev-create job + #210 rw auto + #211 rw auto quick + #212 rw auto quick +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-iotests-Rewrite-210-for-blockdev-create-job.patch b/SOURCES/kvm-qemu-iotests-Rewrite-210-for-blockdev-create-job.patch new file mode 100644 index 0000000..d644f06 --- /dev/null +++ b/SOURCES/kvm-qemu-iotests-Rewrite-210-for-blockdev-create-job.patch @@ -0,0 +1,745 @@ +From 609b0ba5919f07e407127911ae6f3b15cc15e324 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:48 +0200 +Subject: [PATCH 79/89] qemu-iotests: Rewrite 210 for blockdev-create job + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-66-kwolf@redhat.com> +Patchwork-id: 81090 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 65/73] qemu-iotests: Rewrite 210 for blockdev-create job +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This rewrites the test case 210 to work with the new x-blockdev-create +job rather than the old synchronous version of the command. + +All of the test cases stay the same as before, but in order to be able +to implement proper job handling, the test case is rewritten in Python. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +Reviewed-by: Jeff Cody +(cherry picked from commit 5ba141dc6f17ca0f250f107aace2df19558c8bc4) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/210 | 393 ++++++++++++++++++------------------------ + tests/qemu-iotests/210.out | 197 ++++++++++++++------- + tests/qemu-iotests/group | 2 +- + tests/qemu-iotests/iotests.py | 12 +- + 4 files changed, 314 insertions(+), 290 deletions(-) + +diff --git a/tests/qemu-iotests/210 b/tests/qemu-iotests/210 +index e607c0d..ff4fdde 100755 +--- a/tests/qemu-iotests/210 ++++ b/tests/qemu-iotests/210 +@@ -1,9 +1,11 @@ +-#!/bin/bash ++#!/usr/bin/env python + # + # Test luks and file image creation + # + # Copyright (C) 2018 Red Hat, Inc. + # ++# Creator/Owner: Kevin Wolf ++# + # 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 +@@ -18,230 +20,165 @@ + # along with this program. If not, see . + # + +-# creator +-owner=kwolf@redhat.com +- +-seq=`basename $0` +-echo "QA output created by $seq" +- +-here=`pwd` +-status=1 # failure is the default! +- +-# get standard environment, filters and checks +-. ./common.rc +-. ./common.filter +- +-_supported_fmt luks +-_supported_proto file +-_supported_os Linux +- +-function do_run_qemu() +-{ +- echo Testing: "$@" +- $QEMU -nographic -qmp stdio -serial none "$@" +- echo +-} +- +-function run_qemu() +-{ +- do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \ +- | _filter_qemu | _filter_imgfmt \ +- | _filter_actual_image_size +-} +- +-echo +-echo "=== Successful image creation (defaults) ===" +-echo +- +-size=$((128 * 1024 * 1024)) +- +-run_qemu -object secret,id=keysec0,data="foo" <0 size"}} +-{"return": {}} +-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} +- +-image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "key-secret": "keysec0"} ++{'execute': 'block_resize', 'arguments': {'size': 9223372036854775296, 'node_name': 'node1'}} ++{u'error': {u'class': u'GenericError', u'desc': u'The requested file size is too large'}} ++{'execute': 'block_resize', 'arguments': {'size': 9223372036854775808L, 'node_name': 'node1'}} ++{u'error': {u'class': u'GenericError', u'desc': u"Invalid parameter type for 'size', expected: integer"}} ++{'execute': 'block_resize', 'arguments': {'size': 18446744073709551104L, 'node_name': 'node1'}} ++{u'error': {u'class': u'GenericError', u'desc': u"Invalid parameter type for 'size', expected: integer"}} ++{'execute': 'block_resize', 'arguments': {'size': -9223372036854775808, 'node_name': 'node1'}} ++{u'error': {u'class': u'GenericError', u'desc': u"Parameter 'size' expects a >0 size"}} ++image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_IMG"}, "key-secret": "keysec0"} + file format: IMGFMT + virtual size: 0 (0 bytes) +-*** done ++encrypted: yes ++Format specific information: ++ ivgen alg: plain64 ++ hash alg: sha256 ++ cipher alg: aes-256 ++ uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX ++ cipher mode: xts ++ slots: ++ [0]: ++ active: true ++ iters: XXX ++ key offset: 4096 ++ stripes: 4000 ++ [1]: ++ active: false ++ key offset: 262144 ++ [2]: ++ active: false ++ key offset: 520192 ++ [3]: ++ active: false ++ key offset: 778240 ++ [4]: ++ active: false ++ key offset: 1036288 ++ [5]: ++ active: false ++ key offset: 1294336 ++ [6]: ++ active: false ++ key offset: 1552384 ++ [7]: ++ active: false ++ key offset: 1810432 ++ payload offset: 2068480 ++ master key iters: XXX ++ +diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group +index 649291a..3ecdafa 100644 +--- a/tests/qemu-iotests/group ++++ b/tests/qemu-iotests/group +@@ -208,9 +208,9 @@ + 207 rw auto + 208 rw auto quick + 209 rw auto quick ++210 rw auto + # TODO The following commented out tests need to be reworked to work + # with the x-blockdev-create job +-#210 rw auto + #211 rw auto quick + #212 rw auto quick + #213 rw auto quick +diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py +index 9f1759d..0b204dc 100644 +--- a/tests/qemu-iotests/iotests.py ++++ b/tests/qemu-iotests/iotests.py +@@ -109,8 +109,16 @@ def qemu_img_pipe(*args): + sys.stderr.write('qemu-img received signal %i: %s\n' % (-exitcode, ' '.join(qemu_img_args + list(args)))) + return subp.communicate()[0] + +-def img_info_log(filename, filter_path=None): +- output = qemu_img_pipe('info', '-f', imgfmt, filename) ++def img_info_log(filename, filter_path=None, imgopts=False, extra_args=[]): ++ args = [ 'info' ] ++ if imgopts: ++ args.append('--image-opts') ++ else: ++ args += [ '-f', imgfmt ] ++ args += extra_args ++ args.append(filename) ++ ++ output = qemu_img_pipe(*args) + if not filter_path: + filter_path = filename + log(filter_img_info(output, filter_path)) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-iotests-Rewrite-211-for-blockdev-create-job.patch b/SOURCES/kvm-qemu-iotests-Rewrite-211-for-blockdev-create-job.patch new file mode 100644 index 0000000..e0ae39a --- /dev/null +++ b/SOURCES/kvm-qemu-iotests-Rewrite-211-for-blockdev-create-job.patch @@ -0,0 +1,623 @@ +From 71efcd6903a5a857fb6a4b03ee19bb62c47b9dfd Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:49 +0200 +Subject: [PATCH 80/89] qemu-iotests: Rewrite 211 for blockdev-create job + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-67-kwolf@redhat.com> +Patchwork-id: 81096 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 66/73] qemu-iotests: Rewrite 211 for blockdev-create job +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This rewrites the test case 211 to work with the new x-blockdev-create +job rather than the old synchronous version of the command. + +All of the test cases stay the same as before, but in order to be able +to implement proper job handling, the test case is rewritten in Python. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +(cherry picked from commit abbab72cad2eafcaf3b0f4e970add813b4264e5f) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/211 | 381 ++++++++++++++++++--------------------------- + tests/qemu-iotests/211.out | 133 +++++++++------- + tests/qemu-iotests/group | 2 +- + 3 files changed, 229 insertions(+), 287 deletions(-) + +diff --git a/tests/qemu-iotests/211 b/tests/qemu-iotests/211 +index 1edec26..b45f886 100755 +--- a/tests/qemu-iotests/211 ++++ b/tests/qemu-iotests/211 +@@ -1,9 +1,11 @@ +-#!/bin/bash ++#!/usr/bin/env python + # + # Test VDI and file image creation + # + # Copyright (C) 2018 Red Hat, Inc. + # ++# Creator/Owner: Kevin Wolf ++# + # 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 +@@ -18,229 +20,154 @@ + # along with this program. If not, see . + # + +-# creator +-owner=kwolf@redhat.com +- +-seq=`basename $0` +-echo "QA output created by $seq" +- +-here=`pwd` +-status=1 # failure is the default! +- +-# get standard environment, filters and checks +-. ./common.rc +-. ./common.filter +- +-_supported_fmt vdi +-_supported_proto file +-_supported_os Linux +- +-function do_run_qemu() +-{ +- echo Testing: "$@" +- $QEMU -nographic -qmp stdio -serial none "$@" +- echo +-} +- +-function run_qemu() +-{ +- do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \ +- | _filter_qemu | _filter_imgfmt \ +- | _filter_actual_image_size +-} +- +-echo +-echo "=== Successful image creation (defaults) ===" +-echo +- +-size=$((128 * 1024 * 1024)) +- +-run_qemu < +Date: Tue, 26 Jun 2018 09:48:50 +0200 +Subject: [PATCH 81/89] qemu-iotests: Rewrite 212 for blockdev-create job + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-68-kwolf@redhat.com> +Patchwork-id: 81100 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 67/73] qemu-iotests: Rewrite 212 for blockdev-create job +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This rewrites the test case 212 to work with the new x-blockdev-create +job rather than the old synchronous version of the command. + +All of the test cases stay the same as before, but in order to be able +to implement proper job handling, the test case is rewritten in Python. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +(cherry picked from commit 2d7abfbeb75fbe624a8b3a2ff253dbf5674ccb65) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/212 | 483 +++++++++++++++++---------------------------- + tests/qemu-iotests/212.out | 191 +++++++++++------- + tests/qemu-iotests/group | 2 +- + 3 files changed, 295 insertions(+), 381 deletions(-) + +diff --git a/tests/qemu-iotests/212 b/tests/qemu-iotests/212 +index e5a1ba7..03cf41d 100755 +--- a/tests/qemu-iotests/212 ++++ b/tests/qemu-iotests/212 +@@ -1,9 +1,11 @@ +-#!/bin/bash ++#!/usr/bin/env python + # + # Test parallels and file image creation + # + # Copyright (C) 2018 Red Hat, Inc. + # ++# Creator/Owner: Kevin Wolf ++# + # 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 +@@ -18,309 +20,176 @@ + # along with this program. If not, see . + # + +-# creator +-owner=kwolf@redhat.com +- +-seq=`basename $0` +-echo "QA output created by $seq" +- +-here=`pwd` +-status=1 # failure is the default! +- +-# get standard environment, filters and checks +-. ./common.rc +-. ./common.filter +- +-_supported_fmt parallels +-_supported_proto file +-_supported_os Linux +- +-function do_run_qemu() +-{ +- echo Testing: "$@" +- $QEMU -nographic -qmp stdio -serial none "$@" +- echo +-} +- +-function run_qemu() +-{ +- do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \ +- | _filter_qemu | _filter_imgfmt \ +- | _filter_actual_image_size +-} +- +-echo +-echo "=== Successful image creation (defaults) ===" +-echo +- +-size=$((128 * 1024 * 1024)) +- +-run_qemu < +Date: Tue, 26 Jun 2018 09:48:51 +0200 +Subject: [PATCH 82/89] qemu-iotests: Rewrite 213 for blockdev-create job + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-69-kwolf@redhat.com> +Patchwork-id: 81109 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 68/73] qemu-iotests: Rewrite 213 for blockdev-create job +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This rewrites the test case 213 to work with the new x-blockdev-create +job rather than the old synchronous version of the command. + +All of the test cases stay the same as before, but in order to be able +to implement proper job handling, the test case is rewritten in Python. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +(cherry picked from commit 0c46a69a5eb8a061134719a0a85898854eb8e533) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/213 | 520 +++++++++++++++++---------------------------- + tests/qemu-iotests/213.out | 208 +++++++++++------- + tests/qemu-iotests/group | 4 +- + 3 files changed, 319 insertions(+), 413 deletions(-) + +diff --git a/tests/qemu-iotests/213 b/tests/qemu-iotests/213 +index 3a00a0f..29d25bc 100755 +--- a/tests/qemu-iotests/213 ++++ b/tests/qemu-iotests/213 +@@ -1,9 +1,11 @@ +-#!/bin/bash ++#!/usr/bin/env python + # + # Test vhdx and file image creation + # + # Copyright (C) 2018 Red Hat, Inc. + # ++# Creator/Owner: Kevin Wolf ++# + # 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 +@@ -18,332 +20,190 @@ + # along with this program. If not, see . + # + +-# creator +-owner=kwolf@redhat.com +- +-seq=`basename $0` +-echo "QA output created by $seq" +- +-here=`pwd` +-status=1 # failure is the default! +- +-# get standard environment, filters and checks +-. ./common.rc +-. ./common.filter +- +-_supported_fmt vhdx +-_supported_proto file +-_supported_os Linux +- +-function do_run_qemu() +-{ +- echo Testing: "$@" +- $QEMU -nographic -qmp stdio -serial none "$@" +- echo +-} +- +-function run_qemu() +-{ +- do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \ +- | _filter_qemu | _filter_imgfmt \ +- | _filter_actual_image_size +-} +- +-echo +-echo "=== Successful image creation (defaults) ===" +-echo +- +-size=$((128 * 1024 * 1024)) +- +-run_qemu < -Date: Fri, 17 Nov 2017 11:19:07 +0100 -Subject: [PATCH 08/15] qemu-iotests: Test I/O limits with removable media - -RH-Author: Stefan Hajnoczi -Message-id: <20171117111908.8815-9-stefanha@redhat.com> -Patchwork-id: 77743 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 8/9] qemu-iotests: Test I/O limits with removable media -Bugzilla: 1492295 -RH-Acked-by: John Snow -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth - -From: Alberto Garcia - -This test hotplugs a CD drive to a VM and checks that I/O limits can -be set only when the drive has media inserted and that they are kept -when the media is replaced. - -This also tests the removal of a device with valid I/O limits set but -no media inserted. This involves deleting and disabling the limits -of a BlockBackend without BlockDriverState, a scenario that has been -crashing until the fixes from the last couple of patches. - -[Python PEP8 fixup: "Don't use spaces are the = sign when used to -indicate a keyword argument or a default parameter value" ---Stefan] - -Signed-off-by: Alberto Garcia -Reviewed-by: Max Reitz -Message-id: 071eb397118ed207c5a7f01d58766e415ee18d6a.1510339534.git.berto@igalia.com -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit 0761562687e0d8135310a94b1d3e08376387c027) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - tests/qemu-iotests/093 | 62 ++++++++++++++++++++++++++++++++++++++++++++++ - tests/qemu-iotests/093.out | 4 +-- - 2 files changed, 64 insertions(+), 2 deletions(-) - -diff --git a/tests/qemu-iotests/093 b/tests/qemu-iotests/093 -index ef39972..5c36a5f 100755 ---- a/tests/qemu-iotests/093 -+++ b/tests/qemu-iotests/093 -@@ -308,6 +308,68 @@ class ThrottleTestGroupNames(iotests.QMPTestCase): - groupname = "group%d" % i - self.verify_name(devname, groupname) - -+class ThrottleTestRemovableMedia(iotests.QMPTestCase): -+ def setUp(self): -+ self.vm = iotests.VM() -+ if iotests.qemu_default_machine == 's390-ccw-virtio': -+ self.vm.add_device("virtio-scsi-ccw,id=virtio-scsi") -+ else: -+ self.vm.add_device("virtio-scsi-pci,id=virtio-scsi") -+ self.vm.launch() -+ -+ def tearDown(self): -+ self.vm.shutdown() -+ -+ def test_removable_media(self): -+ # Add a couple of dummy nodes named cd0 and cd1 -+ result = self.vm.qmp("blockdev-add", driver="null-aio", -+ node_name="cd0") -+ self.assert_qmp(result, 'return', {}) -+ result = self.vm.qmp("blockdev-add", driver="null-aio", -+ node_name="cd1") -+ self.assert_qmp(result, 'return', {}) -+ -+ # Attach a CD drive with cd0 inserted -+ result = self.vm.qmp("device_add", driver="scsi-cd", -+ id="dev0", drive="cd0") -+ self.assert_qmp(result, 'return', {}) -+ -+ # Set I/O limits -+ args = { "id": "dev0", "iops": 100, "iops_rd": 0, "iops_wr": 0, -+ "bps": 50, "bps_rd": 0, "bps_wr": 0 } -+ result = self.vm.qmp("block_set_io_throttle", conv_keys=False, **args) -+ self.assert_qmp(result, 'return', {}) -+ -+ # Check that the I/O limits have been set -+ result = self.vm.qmp("query-block") -+ self.assert_qmp(result, 'return[0]/inserted/iops', 100) -+ self.assert_qmp(result, 'return[0]/inserted/bps', 50) -+ -+ # Now eject cd0 and insert cd1 -+ result = self.vm.qmp("blockdev-open-tray", id='dev0') -+ self.assert_qmp(result, 'return', {}) -+ result = self.vm.qmp("x-blockdev-remove-medium", id='dev0') -+ self.assert_qmp(result, 'return', {}) -+ result = self.vm.qmp("x-blockdev-insert-medium", id='dev0', node_name='cd1') -+ self.assert_qmp(result, 'return', {}) -+ -+ # Check that the I/O limits are still the same -+ result = self.vm.qmp("query-block") -+ self.assert_qmp(result, 'return[0]/inserted/iops', 100) -+ self.assert_qmp(result, 'return[0]/inserted/bps', 50) -+ -+ # Eject cd1 -+ result = self.vm.qmp("x-blockdev-remove-medium", id='dev0') -+ self.assert_qmp(result, 'return', {}) -+ -+ # Check that we can't set limits if the device has no medium -+ result = self.vm.qmp("block_set_io_throttle", conv_keys=False, **args) -+ self.assert_qmp(result, 'error/class', 'GenericError') -+ -+ # Remove the CD drive -+ result = self.vm.qmp("device_del", id='dev0') -+ self.assert_qmp(result, 'return', {}) -+ - - if __name__ == '__main__': - iotests.main(supported_fmts=["raw"]) -diff --git a/tests/qemu-iotests/093.out b/tests/qemu-iotests/093.out -index 2f7d390..594c16f 100644 ---- a/tests/qemu-iotests/093.out -+++ b/tests/qemu-iotests/093.out -@@ -1,5 +1,5 @@ --....... -+........ - ---------------------------------------------------------------------- --Ran 7 tests -+Ran 8 tests - - OK --- -1.8.3.1 - diff --git a/SOURCES/kvm-qemu-iotests-Test-change-backing-file-command.patch b/SOURCES/kvm-qemu-iotests-Test-change-backing-file-command.patch deleted file mode 100644 index 49a4f52..0000000 --- a/SOURCES/kvm-qemu-iotests-Test-change-backing-file-command.patch +++ /dev/null @@ -1,224 +0,0 @@ -From f3eb0c097a879c9bc80a5a2589560b7ebde3720b Mon Sep 17 00:00:00 2001 -From: Miroslav Rezanina -Date: Tue, 5 Dec 2017 10:26:10 +0100 -Subject: [PATCH 35/36] qemu-iotests: Test change-backing-file command - -RH-Author: Kevin Wolf -Message-id: <20171204121007.12964-8-kwolf@redhat.com> -Patchwork-id: 78111 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 7/8] qemu-iotests: Test change-backing-file command -Bugzilla: 1492178 -RH-Acked-by: Fam Zheng -RH-Acked-by: Max Reitz -RH-Acked-by: Jeffrey Cody - -This involves a temporary read-write reopen if the backing file link in -the middle of a backing file chain should be changed and is therefore a -good test for the latest bdrv_reopen() vs. op blockers fixes. - -Signed-off-by: Kevin Wolf -(cherry picked from commit 3fb23e07516aae13d1ba566740c1c81ae12184b7) -Signed-off-by: Miroslav Rezanina ---- - tests/qemu-iotests/195 | 92 ++++++++++++++++++++++++++++++++++++++++++++++ - tests/qemu-iotests/195.out | 78 +++++++++++++++++++++++++++++++++++++++ - tests/qemu-iotests/group | 1 + - 3 files changed, 171 insertions(+) - create mode 100644 tests/qemu-iotests/195 - create mode 100644 tests/qemu-iotests/195.out - -diff --git a/tests/qemu-iotests/195 b/tests/qemu-iotests/195 -new file mode 100644 -index 0000000..05a239c ---- /dev/null -+++ b/tests/qemu-iotests/195 -@@ -0,0 +1,92 @@ -+#!/bin/bash -+# -+# Test change-backing-file command -+# -+# Copyright (C) 2017 Red Hat, Inc. -+# -+# This program is free software; you can redistribute it and/or modify -+# it under the terms of the GNU General Public License as published by -+# the Free Software Foundation; either version 2 of the License, or -+# (at your option) any later version. -+# -+# This program is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with this program. If not, see . -+# -+ -+# creator -+owner=kwolf@redhat.com -+ -+seq=`basename $0` -+echo "QA output created by $seq" -+ -+here=`pwd` -+status=1 # failure is the default! -+ -+_cleanup() -+{ -+ _cleanup_test_img -+ rm -f "$TEST_IMG.mid" -+} -+trap "_cleanup; exit \$status" 0 1 2 3 15 -+ -+# get standard environment, filters and checks -+. ./common.rc -+. ./common.filter -+ -+_supported_fmt qcow2 -+_supported_proto file -+_supported_os Linux -+ -+function do_run_qemu() -+{ -+ echo Testing: "$@" | _filter_imgfmt -+ $QEMU -nographic -qmp-pretty stdio -serial none "$@" -+ echo -+} -+ -+function run_qemu() -+{ -+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp \ -+ | _filter_qemu_io | _filter_generated_node_ids -+} -+ -+size=64M -+TEST_IMG="$TEST_IMG.base" _make_test_img $size -+TEST_IMG="$TEST_IMG.mid" _make_test_img -b "$TEST_IMG.base" -+_make_test_img -b "$TEST_IMG.mid" -+ -+echo -+echo "Change backing file of mid (opened read-only)" -+echo -+ -+run_qemu -drive if=none,file="$TEST_IMG",backing.node-name=mid < +Date: Tue, 11 Sep 2018 13:07:04 +0200 +Subject: [PATCH 02/49] qemu-iotests: Test commit with top-node/base-node + +RH-Author: Kevin Wolf +Message-id: <20180911130704.6641-3-kwolf@redhat.com> +Patchwork-id: 82115 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 2/2] qemu-iotests: Test commit with top-node/base-node +Bugzilla: 1624012 +RH-Acked-by: Max Reitz +RH-Acked-by: John Snow +RH-Acked-by: Fam Zheng + +This adds some tests for block-commit with the new options top-node and +base-node (taking node names) instead of top and base (taking file +names). + +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/040 | 52 ++++++++++++++++++++++++++++++++++++++++++++-- + tests/qemu-iotests/040.out | 4 ++-- + 2 files changed, 52 insertions(+), 4 deletions(-) + +diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040 +index 1beb5e6..1cb1cee 100755 +--- a/tests/qemu-iotests/040 ++++ b/tests/qemu-iotests/040 +@@ -57,9 +57,12 @@ class ImageCommitTestCase(iotests.QMPTestCase): + self.assert_no_active_block_jobs() + self.vm.shutdown() + +- def run_commit_test(self, top, base, need_ready=False): ++ def run_commit_test(self, top, base, need_ready=False, node_names=False): + self.assert_no_active_block_jobs() +- result = self.vm.qmp('block-commit', device='drive0', top=top, base=base) ++ if node_names: ++ result = self.vm.qmp('block-commit', device='drive0', top_node=top, base_node=base) ++ else: ++ result = self.vm.qmp('block-commit', device='drive0', top=top, base=base) + self.assert_qmp(result, 'return', {}) + self.wait_for_complete(need_ready) + +@@ -101,6 +104,11 @@ class TestSingleDrive(ImageCommitTestCase): + self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img).find("verification failed")) + self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed")) + ++ def test_commit_node(self): ++ self.run_commit_test("mid", "base", node_names=True) ++ self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img).find("verification failed")) ++ self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed")) ++ + def test_device_not_found(self): + result = self.vm.qmp('block-commit', device='nonexistent', top='%s' % mid_img) + self.assert_qmp(result, 'error/class', 'DeviceNotFound') +@@ -123,6 +131,30 @@ class TestSingleDrive(ImageCommitTestCase): + self.assert_qmp(result, 'error/class', 'GenericError') + self.assert_qmp(result, 'error/desc', 'Base \'badfile\' not found') + ++ def test_top_node_invalid(self): ++ self.assert_no_active_block_jobs() ++ result = self.vm.qmp('block-commit', device='drive0', top_node='badfile', base_node='base') ++ self.assert_qmp(result, 'error/class', 'GenericError') ++ self.assert_qmp(result, 'error/desc', "Cannot find device= nor node_name=badfile") ++ ++ def test_base_node_invalid(self): ++ self.assert_no_active_block_jobs() ++ result = self.vm.qmp('block-commit', device='drive0', top_node='mid', base_node='badfile') ++ self.assert_qmp(result, 'error/class', 'GenericError') ++ self.assert_qmp(result, 'error/desc', "Cannot find device= nor node_name=badfile") ++ ++ def test_top_path_and_node(self): ++ self.assert_no_active_block_jobs() ++ result = self.vm.qmp('block-commit', device='drive0', top_node='mid', base_node='base', top='%s' % mid_img) ++ self.assert_qmp(result, 'error/class', 'GenericError') ++ self.assert_qmp(result, 'error/desc', "'top-node' and 'top' are mutually exclusive") ++ ++ def test_base_path_and_node(self): ++ self.assert_no_active_block_jobs() ++ result = self.vm.qmp('block-commit', device='drive0', top_node='mid', base_node='base', base='%s' % backing_img) ++ self.assert_qmp(result, 'error/class', 'GenericError') ++ self.assert_qmp(result, 'error/desc', "'base-node' and 'base' are mutually exclusive") ++ + def test_top_is_active(self): + self.run_commit_test(test_img, backing_img, need_ready=True) + self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img).find("verification failed")) +@@ -139,6 +171,22 @@ class TestSingleDrive(ImageCommitTestCase): + self.assert_qmp(result, 'error/class', 'GenericError') + self.assert_qmp(result, 'error/desc', 'Base \'%s\' not found' % mid_img) + ++ def test_top_and_base_node_reversed(self): ++ self.assert_no_active_block_jobs() ++ result = self.vm.qmp('block-commit', device='drive0', top_node='base', base_node='top') ++ self.assert_qmp(result, 'error/class', 'GenericError') ++ self.assert_qmp(result, 'error/desc', "'top' is not in this backing file chain") ++ ++ def test_top_node_in_wrong_chain(self): ++ self.assert_no_active_block_jobs() ++ ++ result = self.vm.qmp('blockdev-add', driver='null-co', node_name='null') ++ self.assert_qmp(result, 'return', {}) ++ ++ result = self.vm.qmp('block-commit', device='drive0', top_node='null', base_node='base') ++ self.assert_qmp(result, 'error/class', 'GenericError') ++ self.assert_qmp(result, 'error/desc', "'null' is not in this backing file chain") ++ + # When the job is running on a BB that is automatically deleted on hot + # unplug, the job is cancelled when the device disappears + def test_hot_unplug(self): +diff --git a/tests/qemu-iotests/040.out b/tests/qemu-iotests/040.out +index e20a75c..802ffaa 100644 +--- a/tests/qemu-iotests/040.out ++++ b/tests/qemu-iotests/040.out +@@ -1,5 +1,5 @@ +-............................. ++........................................... + ---------------------------------------------------------------------- +-Ran 29 tests ++Ran 43 tests + + OK +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-iotests-Test-job-with-block-jobs.patch b/SOURCES/kvm-qemu-iotests-Test-job-with-block-jobs.patch new file mode 100644 index 0000000..a0ade44 --- /dev/null +++ b/SOURCES/kvm-qemu-iotests-Test-job-with-block-jobs.patch @@ -0,0 +1,589 @@ +From 5649220e08e99f848e013f1e0b432d6d2fc706fc Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:36 +0200 +Subject: [PATCH 67/89] qemu-iotests: Test job-* with block jobs + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-54-kwolf@redhat.com> +Patchwork-id: 81101 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 53/73] qemu-iotests: Test job-* with block jobs +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This adds a test case that tests the new job-* QMP commands with +mirror and backup block jobs. + +Signed-off-by: Kevin Wolf +(cherry picked from commit bdebdc712b06ba82e103d617c335830682cde242) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/219 | 209 +++++++++++++++++++++++++++++ + tests/qemu-iotests/219.out | 327 +++++++++++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/group | 1 + + 3 files changed, 537 insertions(+) + create mode 100755 tests/qemu-iotests/219 + create mode 100644 tests/qemu-iotests/219.out + +diff --git a/tests/qemu-iotests/219 b/tests/qemu-iotests/219 +new file mode 100755 +index 0000000..898a26e +--- /dev/null ++++ b/tests/qemu-iotests/219 +@@ -0,0 +1,209 @@ ++#!/usr/bin/env python ++# ++# Copyright (C) 2018 Red Hat, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++# Creator/Owner: Kevin Wolf ++# ++# Check using the job-* QMP commands with block jobs ++ ++import iotests ++ ++iotests.verify_image_format(supported_fmts=['qcow2']) ++ ++def pause_wait(vm, job_id): ++ with iotests.Timeout(3, "Timeout waiting for job to pause"): ++ while True: ++ result = vm.qmp('query-jobs') ++ for job in result['return']: ++ if job['id'] == job_id and job['status'] in ['paused', 'standby']: ++ return job ++ ++# Test that block-job-pause/resume and job-pause/resume can be mixed ++def test_pause_resume(vm): ++ for pause_cmd, pause_arg in [('block-job-pause', 'device'), ++ ('job-pause', 'id')]: ++ for resume_cmd, resume_arg in [('block-job-resume', 'device'), ++ ('job-resume', 'id')]: ++ iotests.log('=== Testing %s/%s ===' % (pause_cmd, resume_cmd)) ++ ++ iotests.log(vm.qmp(pause_cmd, **{pause_arg: 'job0'})) ++ pause_wait(vm, 'job0') ++ iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE'))) ++ iotests.log(vm.qmp('query-jobs')) ++ ++ iotests.log(vm.qmp(resume_cmd, **{resume_arg: 'job0'})) ++ iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE'))) ++ iotests.log(vm.qmp('query-jobs')) ++ ++def test_job_lifecycle(vm, job, job_args, has_ready=False): ++ iotests.log('') ++ iotests.log('') ++ iotests.log('Starting block job: %s (auto-finalize: %s; auto-dismiss: %s)' % ++ (job, ++ job_args.get('auto-finalize', True), ++ job_args.get('auto-dismiss', True))) ++ iotests.log(vm.qmp(job, job_id='job0', **job_args)) ++ ++ # Depending on the storage, the first request may or may not have completed ++ # yet, so filter out the progress. Later query-job calls don't need the ++ # filtering because the progress is made deterministic by the block job ++ # speed ++ result = vm.qmp('query-jobs') ++ for j in result['return']: ++ del j['current-progress'] ++ iotests.log(result) ++ ++ # undefined -> created -> running ++ iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE'))) ++ iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE'))) ++ ++ # RUNNING state: ++ # pause/resume should work, complete/finalize/dismiss should error out ++ iotests.log('') ++ iotests.log('Pause/resume in RUNNING') ++ test_pause_resume(vm) ++ ++ iotests.log(vm.qmp('job-complete', id='job0')) ++ iotests.log(vm.qmp('job-finalize', id='job0')) ++ iotests.log(vm.qmp('job-dismiss', id='job0')) ++ ++ iotests.log(vm.qmp('block-job-complete', device='job0')) ++ iotests.log(vm.qmp('block-job-finalize', id='job0')) ++ iotests.log(vm.qmp('block-job-dismiss', id='job0')) ++ ++ # Let the job complete (or transition to READY if it supports that) ++ iotests.log(vm.qmp('block-job-set-speed', device='job0', speed=0)) ++ if has_ready: ++ iotests.log('') ++ iotests.log('Waiting for READY state...') ++ vm.event_wait('BLOCK_JOB_READY') ++ iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE'))) ++ iotests.log(vm.qmp('query-jobs')) ++ ++ # READY state: ++ # pause/resume/complete should work, finalize/dismiss should error out ++ iotests.log('') ++ iotests.log('Pause/resume in READY') ++ test_pause_resume(vm) ++ ++ iotests.log(vm.qmp('job-finalize', id='job0')) ++ iotests.log(vm.qmp('job-dismiss', id='job0')) ++ ++ iotests.log(vm.qmp('block-job-finalize', id='job0')) ++ iotests.log(vm.qmp('block-job-dismiss', id='job0')) ++ ++ # Transition to WAITING ++ iotests.log(vm.qmp('job-complete', id='job0')) ++ ++ # Move to WAITING and PENDING state ++ iotests.log('') ++ iotests.log('Waiting for PENDING state...') ++ iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE'))) ++ iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE'))) ++ ++ if not job_args.get('auto-finalize', True): ++ # PENDING state: ++ # finalize should work, pause/complete/dismiss should error out ++ iotests.log(vm.qmp('query-jobs')) ++ ++ iotests.log(vm.qmp('job-pause', id='job0')) ++ iotests.log(vm.qmp('job-complete', id='job0')) ++ iotests.log(vm.qmp('job-dismiss', id='job0')) ++ ++ iotests.log(vm.qmp('block-job-pause', device='job0')) ++ iotests.log(vm.qmp('block-job-complete', device='job0')) ++ iotests.log(vm.qmp('block-job-dismiss', id='job0')) ++ ++ # Transition to CONCLUDED ++ iotests.log(vm.qmp('job-finalize', id='job0')) ++ ++ ++ # Move to CONCLUDED state ++ iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE'))) ++ ++ if not job_args.get('auto-dismiss', True): ++ # CONCLUDED state: ++ # dismiss should work, pause/complete/finalize should error out ++ iotests.log(vm.qmp('query-jobs')) ++ ++ iotests.log(vm.qmp('job-pause', id='job0')) ++ iotests.log(vm.qmp('job-complete', id='job0')) ++ iotests.log(vm.qmp('job-finalize', id='job0')) ++ ++ iotests.log(vm.qmp('block-job-pause', device='job0')) ++ iotests.log(vm.qmp('block-job-complete', device='job0')) ++ iotests.log(vm.qmp('block-job-finalize', id='job0')) ++ ++ # Transition to NULL ++ iotests.log(vm.qmp('job-dismiss', id='job0')) ++ ++ # Move to NULL state ++ iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE'))) ++ iotests.log(vm.qmp('query-jobs')) ++ ++ ++with iotests.FilePath('disk.img') as disk_path, \ ++ iotests.FilePath('copy.img') as copy_path, \ ++ iotests.VM() as vm: ++ ++ img_size = '4M' ++ iotests.qemu_img_create('-f', iotests.imgfmt, disk_path, img_size) ++ iotests.qemu_io('-c', 'write 0 %s' % (img_size), ++ '-f', iotests.imgfmt, disk_path) ++ ++ iotests.log('Launching VM...') ++ vm.add_blockdev(vm.qmp_to_opts({ ++ 'driver': iotests.imgfmt, ++ 'node-name': 'drive0-node', ++ 'file': { ++ 'driver': 'file', ++ 'filename': disk_path, ++ }, ++ })) ++ vm.launch() ++ ++ # In order to keep things deterministic (especially progress in query-job, ++ # but related to this also automatic state transitions like job ++ # completion), but still get pause points often enough to avoid making this ++ # test very slow, it's important to have the right ratio between speed and ++ # buf_size. ++ # ++ # For backup, buf_size is hard-coded to the source image cluster size (64k), ++ # so we'll pick the same for mirror. The slice time, i.e. the granularity ++ # of the rate limiting is 100ms. With a speed of 256k per second, we can ++ # get four pause points per second. This gives us 250ms per iteration, ++ # which should be enough to stay deterministic. ++ ++ test_job_lifecycle(vm, 'drive-mirror', has_ready=True, job_args={ ++ 'device': 'drive0-node', ++ 'target': copy_path, ++ 'sync': 'full', ++ 'speed': 262144, ++ 'buf_size': 65536, ++ }) ++ ++ for auto_finalize in [True, False]: ++ for auto_dismiss in [True, False]: ++ test_job_lifecycle(vm, 'drive-backup', job_args={ ++ 'device': 'drive0-node', ++ 'target': copy_path, ++ 'sync': 'full', ++ 'speed': 262144, ++ 'auto-finalize': auto_finalize, ++ 'auto-dismiss': auto_dismiss, ++ }) ++ ++ vm.shutdown() +diff --git a/tests/qemu-iotests/219.out b/tests/qemu-iotests/219.out +new file mode 100644 +index 0000000..346801b +--- /dev/null ++++ b/tests/qemu-iotests/219.out +@@ -0,0 +1,327 @@ ++Launching VM... ++ ++ ++Starting block job: drive-mirror (auto-finalize: True; auto-dismiss: True) ++{u'return': {}} ++{u'return': [{u'status': u'running', u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'created', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++ ++Pause/resume in RUNNING ++=== Testing block-job-pause/block-job-resume === ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'paused', u'current-progress': 65536, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'running', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} ++=== Testing block-job-pause/job-resume === ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'paused', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'running', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} ++=== Testing job-pause/block-job-resume === ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'paused', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'running', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} ++=== Testing job-pause/job-resume === ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'paused', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'running', u'current-progress': 327680, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} ++{u'return': {}} ++ ++Waiting for READY state... ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'ready', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'ready', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} ++ ++Pause/resume in READY ++=== Testing block-job-pause/block-job-resume === ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'standby', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'standby', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'ready', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'ready', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} ++=== Testing block-job-pause/job-resume === ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'standby', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'standby', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'ready', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'ready', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} ++=== Testing job-pause/block-job-resume === ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'standby', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'standby', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'ready', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'ready', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} ++=== Testing job-pause/job-resume === ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'standby', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'standby', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'ready', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'ready', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'mirror'}]} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'ready' cannot accept command verb 'finalize'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'ready' cannot accept command verb 'dismiss'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'ready' cannot accept command verb 'finalize'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'ready' cannot accept command verb 'dismiss'"}} ++{u'return': {}} ++ ++Waiting for PENDING state... ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'waiting', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'pending', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'concluded', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'null', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': []} ++ ++ ++Starting block job: drive-backup (auto-finalize: True; auto-dismiss: True) ++{u'return': {}} ++{u'return': [{u'status': u'running', u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'created', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++ ++Pause/resume in RUNNING ++=== Testing block-job-pause/block-job-resume === ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'paused', u'current-progress': 65536, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'running', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++=== Testing block-job-pause/job-resume === ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'paused', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'running', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++=== Testing job-pause/block-job-resume === ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'paused', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'running', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++=== Testing job-pause/job-resume === ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'paused', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'running', u'current-progress': 327680, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} ++{u'return': {}} ++ ++Waiting for PENDING state... ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'waiting', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'pending', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'concluded', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'null', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': []} ++ ++ ++Starting block job: drive-backup (auto-finalize: True; auto-dismiss: False) ++{u'return': {}} ++{u'return': [{u'status': u'running', u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'created', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++ ++Pause/resume in RUNNING ++=== Testing block-job-pause/block-job-resume === ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'paused', u'current-progress': 65536, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'running', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++=== Testing block-job-pause/job-resume === ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'paused', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'running', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++=== Testing job-pause/block-job-resume === ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'paused', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'running', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++=== Testing job-pause/job-resume === ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'paused', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'running', u'current-progress': 327680, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} ++{u'return': {}} ++ ++Waiting for PENDING state... ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'waiting', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'pending', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'concluded', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'concluded', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'pause'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'complete'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'finalize'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'pause'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'complete'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'finalize'"}} ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'null', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': []} ++ ++ ++Starting block job: drive-backup (auto-finalize: False; auto-dismiss: True) ++{u'return': {}} ++{u'return': [{u'status': u'running', u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'created', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++ ++Pause/resume in RUNNING ++=== Testing block-job-pause/block-job-resume === ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'paused', u'current-progress': 65536, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'running', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++=== Testing block-job-pause/job-resume === ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'paused', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'running', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++=== Testing job-pause/block-job-resume === ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'paused', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'running', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++=== Testing job-pause/job-resume === ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'paused', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'running', u'current-progress': 327680, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} ++{u'return': {}} ++ ++Waiting for PENDING state... ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'waiting', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'pending', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'pending', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'pause'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'complete'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'dismiss'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'pause'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'complete'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'dismiss'"}} ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'concluded', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'null', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': []} ++ ++ ++Starting block job: drive-backup (auto-finalize: False; auto-dismiss: False) ++{u'return': {}} ++{u'return': [{u'status': u'running', u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'created', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++ ++Pause/resume in RUNNING ++=== Testing block-job-pause/block-job-resume === ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'paused', u'current-progress': 65536, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'running', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++=== Testing block-job-pause/job-resume === ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'paused', u'current-progress': 131072, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'running', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++=== Testing job-pause/block-job-resume === ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'paused', u'current-progress': 196608, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'running', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++=== Testing job-pause/job-resume === ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'paused', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'paused', u'current-progress': 262144, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'running', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'running', u'current-progress': 327680, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'complete'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'finalize'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'running' cannot accept command verb 'dismiss'"}} ++{u'return': {}} ++ ++Waiting for PENDING state... ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'waiting', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'pending', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'pending', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'pause'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'complete'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'dismiss'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'pause'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'complete'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'pending' cannot accept command verb 'dismiss'"}} ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'concluded', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': [{u'status': u'concluded', u'current-progress': 4194304, u'total-progress': 4194304, u'id': u'job0', u'type': u'backup'}]} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'pause'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'complete'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'finalize'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'pause'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'complete'"}} ++{u'error': {u'class': u'GenericError', u'desc': u"Job 'job0' in state 'concluded' cannot accept command verb 'finalize'"}} ++{u'return': {}} ++{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'status': u'null', u'id': u'job0'}, u'event': u'JOB_STATUS_CHANGE'} ++{u'return': []} +diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group +index cd7bc29..5c55adc 100644 +--- a/tests/qemu-iotests/group ++++ b/tests/qemu-iotests/group +@@ -217,3 +217,4 @@ + 216 rw auto quick + 217 rw auto quick + 218 rw auto quick ++219 rw auto +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-iotests-Test-qcow2-not-leaking-clusters-on-writ.patch b/SOURCES/kvm-qemu-iotests-Test-qcow2-not-leaking-clusters-on-writ.patch new file mode 100644 index 0000000..d70e82a --- /dev/null +++ b/SOURCES/kvm-qemu-iotests-Test-qcow2-not-leaking-clusters-on-writ.patch @@ -0,0 +1,95 @@ +From 52970228a0ba4956ed98cb1ae370b16dd740c9e4 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Mon, 2 Jul 2018 15:40:08 +0200 +Subject: [PATCH 55/57] qemu-iotests: Test qcow2 not leaking clusters on write + error + +RH-Author: Kevin Wolf +Message-id: <20180702154008.15533-4-kwolf@redhat.com> +Patchwork-id: 81187 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 3/3] qemu-iotests: Test qcow2 not leaking clusters on write error +Bugzilla: 1528541 +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng +RH-Acked-by: Stefan Hajnoczi + +This adds a test for a temporary write failure, which simulates the +situation after werror=stop/enospc has stopped the VM. We shouldn't +leave leaked clusters behind in such cases. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +(cherry picked from commit ae376c6255d0eee4b3c4d60acc4679aa99c0d2c8) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/026 | 17 +++++++++++++++++ + tests/qemu-iotests/026.out | 8 ++++++++ + tests/qemu-iotests/026.out.nocache | 8 ++++++++ + 3 files changed, 33 insertions(+) + +diff --git a/tests/qemu-iotests/026 b/tests/qemu-iotests/026 +index 7fadfba..582d254 100755 +--- a/tests/qemu-iotests/026 ++++ b/tests/qemu-iotests/026 +@@ -200,6 +200,23 @@ done + done + done + ++echo ++echo === Avoid cluster leaks after temporary failure === ++echo ++ ++cat > "$TEST_DIR/blkdebug.conf" < +Date: Tue, 7 Aug 2018 14:04:01 +0200 +Subject: [PATCH 08/13] qemu-iotests: Test query-blockstats with -drive and + -blockdev + +RH-Author: Kevin Wolf +Message-id: <20180807140401.23995-4-kwolf@redhat.com> +Patchwork-id: 81665 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 3/3] qemu-iotests: Test query-blockstats with -drive and -blockdev +Bugzilla: 1612114 +RH-Acked-by: John Snow +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Markus Armbruster + +Make sure that query-blockstats returns information for every +BlockBackend that is named or attached to a device model (or both). + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +Signed-off-by: Kevin Wolf +(cherry picked from commit 1239ac241fe170bb9fcf0be74bfff04f6f1c2560) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/227 | 101 ++++++++++++++++++++++ + tests/qemu-iotests/227.out | 205 +++++++++++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/group | 1 + + 3 files changed, 307 insertions(+) + create mode 100755 tests/qemu-iotests/227 + create mode 100644 tests/qemu-iotests/227.out + +diff --git a/tests/qemu-iotests/227 b/tests/qemu-iotests/227 +new file mode 100755 +index 0000000..9a5f7f9 +--- /dev/null ++++ b/tests/qemu-iotests/227 +@@ -0,0 +1,101 @@ ++#!/bin/bash ++# ++# Test query-blockstats with different ways to create a BB ++# ++# Copyright (C) 2018 Red Hat, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++ ++# creator ++owner=kwolf@redhat.com ++ ++seq=$(basename $0) ++echo "QA output created by $seq" ++ ++here=$PWD ++status=1 # failure is the default! ++ ++_cleanup() ++{ ++ _cleanup_test_img ++} ++trap "_cleanup; exit \$status" 0 1 2 3 15 ++ ++# get standard environment, filters and checks ++. ./common.rc ++. ./common.filter ++ ++_supported_fmt generic ++_supported_proto file ++_supported_os Linux ++ ++function do_run_qemu() ++{ ++ echo Testing: "$@" ++ $QEMU -nographic -qmp-pretty stdio -serial none "$@" ++ echo ++} ++ ++function run_qemu() ++{ ++ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \ ++ | _filter_qemu | _filter_imgfmt \ ++ | _filter_generated_node_ids ++} ++ ++echo ++echo '=== blockstats with -drive if=virtio ===' ++echo ++ ++run_qemu -drive driver=null-co,if=virtio < +Date: Mon, 2 Jul 2018 15:40:06 +0200 +Subject: [PATCH 53/57] qemu-iotests: Update 026.out.nocache reference output + +RH-Author: Kevin Wolf +Message-id: <20180702154008.15533-2-kwolf@redhat.com> +Patchwork-id: 81186 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 1/3] qemu-iotests: Update 026.out.nocache reference output +Bugzilla: 1528541 +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng +RH-Acked-by: Stefan Hajnoczi + +Commit abf754fe406 updated 026.out, but forgot to also update +026.out.nocache. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +(cherry picked from commit 93a3642efcadf4ad6045ccea38a05ff5297dfe26) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/026.out.nocache | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/tests/qemu-iotests/026.out.nocache b/tests/qemu-iotests/026.out.nocache +index ea2e166..650ccd8 100644 +--- a/tests/qemu-iotests/026.out.nocache ++++ b/tests/qemu-iotests/026.out.nocache +@@ -541,7 +541,7 @@ Failed to flush the L2 table cache: No space left on device + Failed to flush the refcount block cache: No space left on device + write failed: No space left on device + +-11 leaked clusters were found on the image. ++10 leaked clusters were found on the image. + This means waste of disk space, but no harm to data. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + +@@ -569,7 +569,7 @@ Failed to flush the L2 table cache: No space left on device + Failed to flush the refcount block cache: No space left on device + write failed: No space left on device + +-11 leaked clusters were found on the image. ++10 leaked clusters were found on the image. + This means waste of disk space, but no harm to data. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + +@@ -597,7 +597,7 @@ Failed to flush the L2 table cache: No space left on device + Failed to flush the refcount block cache: No space left on device + write failed: No space left on device + +-11 leaked clusters were found on the image. ++10 leaked clusters were found on the image. + This means waste of disk space, but no harm to data. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-iotests-add-202-external-snapshots-IOThread-tes.patch b/SOURCES/kvm-qemu-iotests-add-202-external-snapshots-IOThread-tes.patch deleted file mode 100644 index 3e31fec..0000000 --- a/SOURCES/kvm-qemu-iotests-add-202-external-snapshots-IOThread-tes.patch +++ /dev/null @@ -1,165 +0,0 @@ -From c5ff50d391e5a1afa55d6f2394f404ce27c6ceb5 Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Fri, 22 Dec 2017 11:08:56 +0100 -Subject: [PATCH 38/42] qemu-iotests: add 202 external snapshots IOThread test - -RH-Author: Stefan Hajnoczi -Message-id: <20171222110900.24813-17-stefanha@redhat.com> -Patchwork-id: 78496 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 16/20] qemu-iotests: add 202 external snapshots IOThread test -Bugzilla: 1519721 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -QMP 'transaction' blockdev-snapshot-sync with multiple disks in an -IOThread is an untested code path. Several bugs have been found in -connection with this command. This patch adds a test case to prevent -future regressions. - -Signed-off-by: Stefan Hajnoczi -Reviewed-by: Kevin Wolf -Reviewed-by: Eric Blake -Message-id: 20171206144550.22295-10-stefanha@redhat.com -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit 6dd64919ea36db9fd7e754ed394c25ced45ea39a) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - tests/qemu-iotests/202 | 95 ++++++++++++++++++++++++++++++++++++++++++++++ - tests/qemu-iotests/202.out | 11 ++++++ - tests/qemu-iotests/group | 1 + - 3 files changed, 107 insertions(+) - create mode 100755 tests/qemu-iotests/202 - create mode 100644 tests/qemu-iotests/202.out - -diff --git a/tests/qemu-iotests/202 b/tests/qemu-iotests/202 -new file mode 100755 -index 0000000..581ca34 ---- /dev/null -+++ b/tests/qemu-iotests/202 -@@ -0,0 +1,95 @@ -+#!/usr/bin/env python -+# -+# Copyright (C) 2017 Red Hat, Inc. -+# -+# This program is free software; you can redistribute it and/or modify -+# it under the terms of the GNU General Public License as published by -+# the Free Software Foundation; either version 2 of the License, or -+# (at your option) any later version. -+# -+# This program is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with this program. If not, see . -+# -+# Creator/Owner: Stefan Hajnoczi -+# -+# Check that QMP 'transaction' blockdev-snapshot-sync with multiple drives on a -+# single IOThread completes successfully. This particular command triggered a -+# hang due to recursive AioContext locking and BDRV_POLL_WHILE(). Protect -+# against regressions. -+ -+import iotests -+ -+iotests.verify_image_format(supported_fmts=['qcow2']) -+iotests.verify_platform(['linux']) -+ -+with iotests.FilePath('disk0.img') as disk0_img_path, \ -+ iotests.FilePath('disk1.img') as disk1_img_path, \ -+ iotests.FilePath('disk0-snap.img') as disk0_snap_img_path, \ -+ iotests.FilePath('disk1-snap.img') as disk1_snap_img_path, \ -+ iotests.VM() as vm: -+ -+ img_size = '10M' -+ iotests.qemu_img_pipe('create', '-f', iotests.imgfmt, disk0_img_path, img_size) -+ iotests.qemu_img_pipe('create', '-f', iotests.imgfmt, disk1_img_path, img_size) -+ -+ iotests.log('Launching VM...') -+ vm.launch() -+ -+ iotests.log('Adding IOThread...') -+ iotests.log(vm.qmp('object-add', -+ qom_type='iothread', -+ id='iothread0')) -+ -+ iotests.log('Adding blockdevs...') -+ iotests.log(vm.qmp('blockdev-add', -+ driver=iotests.imgfmt, -+ node_name='disk0', -+ file={ -+ 'driver': 'file', -+ 'filename': disk0_img_path, -+ })) -+ iotests.log(vm.qmp('blockdev-add', -+ driver=iotests.imgfmt, -+ node_name='disk1', -+ file={ -+ 'driver': 'file', -+ 'filename': disk1_img_path, -+ })) -+ -+ iotests.log('Setting iothread...') -+ iotests.log(vm.qmp('x-blockdev-set-iothread', -+ node_name='disk0', -+ iothread='iothread0')) -+ iotests.log(vm.qmp('x-blockdev-set-iothread', -+ node_name='disk1', -+ iothread='iothread0')) -+ -+ iotests.log('Creating external snapshots...') -+ iotests.log(vm.qmp( -+ 'transaction', -+ actions=[ -+ { -+ 'data': { -+ 'node-name': 'disk0', -+ 'snapshot-file': disk0_snap_img_path, -+ 'snapshot-node-name': 'disk0-snap', -+ 'mode': 'absolute-paths', -+ 'format': iotests.imgfmt, -+ }, -+ 'type': 'blockdev-snapshot-sync' -+ }, { -+ 'data': { -+ 'node-name': 'disk1', -+ 'snapshot-file': disk1_snap_img_path, -+ 'snapshot-node-name': 'disk1-snap', -+ 'mode': 'absolute-paths', -+ 'format': iotests.imgfmt -+ }, -+ 'type': 'blockdev-snapshot-sync' -+ } -+ ])) -diff --git a/tests/qemu-iotests/202.out b/tests/qemu-iotests/202.out -new file mode 100644 -index 0000000..d5ea374 ---- /dev/null -+++ b/tests/qemu-iotests/202.out -@@ -0,0 +1,11 @@ -+Launching VM... -+Adding IOThread... -+{u'return': {}} -+Adding blockdevs... -+{u'return': {}} -+{u'return': {}} -+Setting iothread... -+{u'return': {}} -+{u'return': {}} -+Creating external snapshots... -+{u'return': {}} -diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group -index 39b61ce..8d3752c 100644 ---- a/tests/qemu-iotests/group -+++ b/tests/qemu-iotests/group -@@ -191,3 +191,4 @@ - 195 rw auto quick - 198 rw auto - 200 rw auto -+202 rw auto quick --- -1.8.3.1 - diff --git a/SOURCES/kvm-qemu-iotests-add-203-savevm-with-IOThreads-test.patch b/SOURCES/kvm-qemu-iotests-add-203-savevm-with-IOThreads-test.patch deleted file mode 100644 index 4c1a34c..0000000 --- a/SOURCES/kvm-qemu-iotests-add-203-savevm-with-IOThreads-test.patch +++ /dev/null @@ -1,121 +0,0 @@ -From 8c4af840ec684f51a9159ab65550653600ade7e8 Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Fri, 22 Dec 2017 11:09:00 +0100 -Subject: [PATCH 42/42] qemu-iotests: add 203 savevm with IOThreads test - -RH-Author: Stefan Hajnoczi -Message-id: <20171222110900.24813-21-stefanha@redhat.com> -Patchwork-id: 78502 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 20/20] qemu-iotests: add 203 savevm with IOThreads test -Bugzilla: 1519721 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -This test case will prevent future regressions with savevm and -IOThreads. - -Signed-off-by: Stefan Hajnoczi -Reviewed-by: Eric Blake -Message-id: 20171207201320.19284-7-stefanha@redhat.com -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit 7a9dda0d7f9831c2432620dcfefdadbb7ae888dc) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - tests/qemu-iotests/203 | 59 ++++++++++++++++++++++++++++++++++++++++++++++ - tests/qemu-iotests/203.out | 6 +++++ - tests/qemu-iotests/group | 1 + - 3 files changed, 66 insertions(+) - create mode 100755 tests/qemu-iotests/203 - create mode 100644 tests/qemu-iotests/203.out - -diff --git a/tests/qemu-iotests/203 b/tests/qemu-iotests/203 -new file mode 100755 -index 0000000..2c81191 ---- /dev/null -+++ b/tests/qemu-iotests/203 -@@ -0,0 +1,59 @@ -+#!/usr/bin/env python -+# -+# Copyright (C) 2017 Red Hat, Inc. -+# -+# This program is free software; you can redistribute it and/or modify -+# it under the terms of the GNU General Public License as published by -+# the Free Software Foundation; either version 2 of the License, or -+# (at your option) any later version. -+# -+# This program is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with this program. If not, see . -+# -+# Creator/Owner: Stefan Hajnoczi -+# -+# Check that QMP 'migrate' with multiple drives on a single IOThread completes -+# successfully. This particular command triggered a hang in the source QEMU -+# process due to recursive AioContext locking in bdrv_invalidate_all() and -+# BDRV_POLL_WHILE(). -+ -+import iotests -+ -+iotests.verify_image_format(supported_fmts=['qcow2']) -+iotests.verify_platform(['linux']) -+ -+with iotests.FilePath('disk0.img') as disk0_img_path, \ -+ iotests.FilePath('disk1.img') as disk1_img_path, \ -+ iotests.VM() as vm: -+ -+ img_size = '10M' -+ iotests.qemu_img_pipe('create', '-f', iotests.imgfmt, disk0_img_path, img_size) -+ iotests.qemu_img_pipe('create', '-f', iotests.imgfmt, disk1_img_path, img_size) -+ -+ iotests.log('Launching VM...') -+ (vm.add_object('iothread,id=iothread0') -+ .add_drive(disk0_img_path, 'node-name=drive0-node', interface='none') -+ .add_drive(disk1_img_path, 'node-name=drive1-node', interface='none') -+ .launch()) -+ -+ iotests.log('Setting IOThreads...') -+ iotests.log(vm.qmp('x-blockdev-set-iothread', -+ node_name='drive0-node', iothread='iothread0', -+ force=True)) -+ iotests.log(vm.qmp('x-blockdev-set-iothread', -+ node_name='drive1-node', iothread='iothread0', -+ force=True)) -+ -+ iotests.log('Starting migration...') -+ iotests.log(vm.qmp('migrate', uri='exec:cat >/dev/null')) -+ while True: -+ vm.get_qmp_event(wait=60.0) -+ result = vm.qmp('query-migrate') -+ status = result.get('return', {}).get('status', None) -+ if status == 'completed': -+ break -diff --git a/tests/qemu-iotests/203.out b/tests/qemu-iotests/203.out -new file mode 100644 -index 0000000..3f1ff90 ---- /dev/null -+++ b/tests/qemu-iotests/203.out -@@ -0,0 +1,6 @@ -+Launching VM... -+Setting IOThreads... -+{u'return': {}} -+{u'return': {}} -+Starting migration... -+{u'return': {}} -diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group -index 8d3752c..67b197e 100644 ---- a/tests/qemu-iotests/group -+++ b/tests/qemu-iotests/group -@@ -192,3 +192,4 @@ - 198 rw auto - 200 rw auto - 202 rw auto quick -+203 rw auto --- -1.8.3.1 - diff --git a/SOURCES/kvm-qemu-iotests-add-option-in-common.qemu-for-mismatch-.patch b/SOURCES/kvm-qemu-iotests-add-option-in-common.qemu-for-mismatch-.patch deleted file mode 100644 index 2b96a5b..0000000 --- a/SOURCES/kvm-qemu-iotests-add-option-in-common.qemu-for-mismatch-.patch +++ /dev/null @@ -1,65 +0,0 @@ -From ebcc9ff9c53aca4d9fab9a0839ccbaf54fbf9943 Mon Sep 17 00:00:00 2001 -From: Jeffrey Cody -Date: Thu, 30 Nov 2017 22:49:09 +0100 -Subject: [PATCH 05/21] qemu-iotests: add option in common.qemu for mismatch - only - -RH-Author: Jeffrey Cody -Message-id: <050629fe443e53475eed8d77b0d6ed321bd42967.1511985875.git.jcody@redhat.com> -Patchwork-id: 78043 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 05/11] qemu-iotests: add option in common.qemu for mismatch only -Bugzilla: 1506531 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: John Snow - -Add option to echo response to QMP / HMP command only on mismatch. - -Useful for ignore all normal responses, but catching things like -segfaults. - -Signed-off-by: Jeff Cody -Reviewed-by: Stefan Hajnoczi -(cherry picked from commit a2339699c3d35f19253b3b9b51f8a9b8e24f90eb) -Signed-off-by: Jeff Cody -Signed-off-by: Miroslav Rezanina ---- - tests/qemu-iotests/common.qemu | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/tests/qemu-iotests/common.qemu b/tests/qemu-iotests/common.qemu -index 7645f1d..f646d81 100644 ---- a/tests/qemu-iotests/common.qemu -+++ b/tests/qemu-iotests/common.qemu -@@ -49,6 +49,8 @@ _in_fd=4 - # - # If $silent is set to anything but an empty string, then - # response is not echoed out. -+# If $mismatch_only is set, only non-matching responses will -+# be echoed. - function _timed_wait_for() - { - local h=${1} -@@ -57,14 +59,18 @@ function _timed_wait_for() - QEMU_STATUS[$h]=0 - while read -t ${QEMU_COMM_TIMEOUT} resp <&${QEMU_OUT[$h]} - do -- if [ -z "${silent}" ]; then -+ if [ -z "${silent}" ] && [ -z "${mismatch_only}" ]; then - echo "${resp}" | _filter_testdir | _filter_qemu \ - | _filter_qemu_io | _filter_qmp | _filter_hmp - fi - grep -q "${*}" < <(echo ${resp}) - if [ $? -eq 0 ]; then - return -+ elif [ -z "${silent}" ] && [ -n "${mismatch_only}" ]; then -+ echo "${resp}" | _filter_testdir | _filter_qemu \ -+ | _filter_qemu_io | _filter_qmp | _filter_hmp - fi -+ - done - QEMU_STATUS[$h]=-1 - if [ -z "${qemu_error_no_exit}" ]; then --- -1.8.3.1 - diff --git a/SOURCES/kvm-qemu-iotests-improve-nbd-fault-injector.py-startup-p.patch b/SOURCES/kvm-qemu-iotests-improve-nbd-fault-injector.py-startup-p.patch deleted file mode 100644 index b908f2d..0000000 --- a/SOURCES/kvm-qemu-iotests-improve-nbd-fault-injector.py-startup-p.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 2f7ffaddd0a233a233125320b6595a091c19c18f Mon Sep 17 00:00:00 2001 -From: Eric Blake -Date: Fri, 6 Oct 2017 19:24:07 +0200 -Subject: [PATCH 15/34] qemu-iotests: improve nbd-fault-injector.py startup - protocol - -RH-Author: Eric Blake -Message-id: <20171006192409.29915-3-eblake@redhat.com> -Patchwork-id: 76914 -O-Subject: [RHEV-7.5 qemu-kvm-rhev PATCH 2/4] qemu-iotests: improve nbd-fault-injector.py startup protocol -Bugzilla: 1482478 -RH-Acked-by: Max Reitz -RH-Acked-by: Laurent Vivier -RH-Acked-by: Stefan Hajnoczi - -From: Stefan Hajnoczi - -Currently 083 waits for the nbd-fault-injector.py server to start up by -looping until netstat shows the TCP listen socket. - -The startup protocol can be simplified by passing a 0 port number to -nbd-fault-injector.py. The kernel will allocate a port in bind(2) and -the final port number can be printed by nbd-fault-injector.py. - -This should make it slightly nicer and less TCP-specific to wait for -server startup. This patch changes nbd-fault-injector.py, the next one -will rewrite server startup in 083. - -Reviewed-by: Eric Blake -Signed-off-by: Stefan Hajnoczi -Message-Id: <20170829122745.14309-3-stefanha@redhat.com> -Signed-off-by: Eric Blake -(cherry picked from commit 6e592fc92234a58c7156c385840633c17dedd24f) -Signed-off-by: Miroslav Rezanina ---- - tests/qemu-iotests/nbd-fault-injector.py | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/tests/qemu-iotests/nbd-fault-injector.py b/tests/qemu-iotests/nbd-fault-injector.py -index 6c07191..1c10dcb 100755 ---- a/tests/qemu-iotests/nbd-fault-injector.py -+++ b/tests/qemu-iotests/nbd-fault-injector.py -@@ -235,11 +235,15 @@ def open_socket(path): - sock = socket.socket() - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - sock.bind((host, int(port))) -+ -+ # If given port was 0 the final port number is now available -+ path = '%s:%d' % sock.getsockname() - else: - sock = socket.socket(socket.AF_UNIX) - sock.bind(path) - sock.listen(0) - print 'Listening on %s' % path -+ sys.stdout.flush() # another process may be waiting, show message now - return sock - - def usage(args): --- -1.8.3.1 - diff --git a/SOURCES/kvm-qemu-iotests-iotests.py-helper-for-non-file-protocol.patch b/SOURCES/kvm-qemu-iotests-iotests.py-helper-for-non-file-protocol.patch new file mode 100644 index 0000000..5b314cf --- /dev/null +++ b/SOURCES/kvm-qemu-iotests-iotests.py-helper-for-non-file-protocol.patch @@ -0,0 +1,65 @@ +From a50830277403643e090bec4bfe7cf77d693f90e8 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:45 +0200 +Subject: [PATCH 76/89] qemu-iotests: iotests.py helper for non-file protocols + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-63-kwolf@redhat.com> +Patchwork-id: 81081 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 62/73] qemu-iotests: iotests.py helper for non-file protocols +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This adds two helper functions that are useful for test cases that make +use of a non-file protocol (specifically ssh). + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +Reviewed-by: Jeff Cody +(cherry picked from commit 5a259e868b308564de9f2bfaef0606074a4f9028) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/iotests.py | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py +index 390da6b..9f1759d 100644 +--- a/tests/qemu-iotests/iotests.py ++++ b/tests/qemu-iotests/iotests.py +@@ -312,6 +312,13 @@ def file_path(*names): + + return paths[0] if len(paths) == 1 else paths + ++def remote_filename(path): ++ if imgproto == 'file': ++ return path ++ elif imgproto == 'ssh': ++ return "ssh://127.0.0.1%s" % (path) ++ else: ++ raise Exception("Protocol %s not supported" % (imgproto)) + + class VM(qtest.QEMUQtestMachine): + '''A QEMU VM''' +@@ -610,6 +617,16 @@ def verify_image_format(supported_fmts=[], unsupported_fmts=[]): + if not_sup or (imgfmt in unsupported_fmts): + notrun('not suitable for this image format: %s' % imgfmt) + ++def verify_protocol(supported=[], unsupported=[]): ++ assert not (supported and unsupported) ++ ++ if 'generic' in supported: ++ return ++ ++ not_sup = supported and (imgproto not in supported) ++ if not_sup or (imgproto in unsupported): ++ notrun('not suitable for this protocol: %s' % imgproto) ++ + def verify_platform(supported_oses=['linux']): + if True not in [sys.platform.startswith(x) for x in supported_oses]: + notrun('not suitable for this OS: %s' % sys.platform) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-iotests-reduce-chance-of-races-in-185.patch b/SOURCES/kvm-qemu-iotests-reduce-chance-of-races-in-185.patch new file mode 100644 index 0000000..6fec60a --- /dev/null +++ b/SOURCES/kvm-qemu-iotests-reduce-chance-of-races-in-185.patch @@ -0,0 +1,90 @@ +From 03240b36532d828a71fd3c9fee7b1ed6e8faa7a5 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:47:45 +0200 +Subject: [PATCH 16/89] qemu-iotests: reduce chance of races in 185 + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-3-kwolf@redhat.com> +Patchwork-id: 81061 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 02/73] qemu-iotests: reduce chance of races in 185 +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +From: Stefan Hajnoczi + +Commit 8565c3ab537e78f3e69977ec2c609dc9417a806e ("qemu-iotests: fix +185") identified a race condition in a sub-test. + +Similar issues also affect the other sub-tests. If disk I/O completes +quickly, it races with the QMP 'quit' command. This causes spurious +test failures because QMP events are emitted in an unpredictable order. + +This test relies on QEMU internals and there is no QMP API for getting +deterministic behavior needed to make this test 100% reliable. At the +same time, the test is useful and it would be a shame to remove it. + +Add sleep 0.5 to reduce the chance of races. This is not a real fix but +appears to reduce spurious failures in practice. + +Cc: Vladimir Sementsov-Ogievskiy +Signed-off-by: Stefan Hajnoczi +Reviewed-by: Eric Blake +Message-id: 20180508135436.30140-2-stefanha@redhat.com +Reviewed-by: Jeff Cody +Signed-off-by: Jeff Cody +(cherry picked from commit ddf2d98a94c8a98a661a217fb629cfd15f4dcec7) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/185 | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/tests/qemu-iotests/185 b/tests/qemu-iotests/185 +index 298d88d..975404c 100755 +--- a/tests/qemu-iotests/185 ++++ b/tests/qemu-iotests/185 +@@ -118,6 +118,9 @@ _send_qemu_cmd $h \ + 'speed': 65536 } }" \ + "return" + ++# If we don't sleep here 'quit' command races with disk I/O ++sleep 0.5 ++ + _send_qemu_cmd $h "{ 'execute': 'quit' }" "return" + wait=1 _cleanup_qemu + +@@ -137,6 +140,9 @@ _send_qemu_cmd $h \ + 'speed': 65536 } }" \ + "return" + ++# If we don't sleep here 'quit' command races with disk I/O ++sleep 0.5 ++ + _send_qemu_cmd $h "{ 'execute': 'quit' }" "return" + wait=1 _cleanup_qemu + +@@ -183,6 +189,9 @@ _send_qemu_cmd $h \ + 'speed': 65536 } }" \ + "return" + ++# If we don't sleep here 'quit' command races with disk I/O ++sleep 0.5 ++ + _send_qemu_cmd $h "{ 'execute': 'quit' }" "return" + wait=1 _cleanup_qemu + +@@ -201,6 +210,9 @@ _send_qemu_cmd $h \ + 'speed': 65536 } }" \ + "return" + ++# If we don't sleep here 'quit' command races with disk I/O ++sleep 0.5 ++ + _send_qemu_cmd $h "{ 'execute': 'quit' }" "return" + wait=1 _cleanup_qemu + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-iotests-test-NBD-over-UNIX-domain-sockets-in-08.patch b/SOURCES/kvm-qemu-iotests-test-NBD-over-UNIX-domain-sockets-in-08.patch deleted file mode 100644 index 0549bfc..0000000 --- a/SOURCES/kvm-qemu-iotests-test-NBD-over-UNIX-domain-sockets-in-08.patch +++ /dev/null @@ -1,451 +0,0 @@ -From 91394fd12be59351787e34e0f18de8b2ff06441f Mon Sep 17 00:00:00 2001 -From: Eric Blake -Date: Fri, 6 Oct 2017 19:24:08 +0200 -Subject: [PATCH 16/34] qemu-iotests: test NBD over UNIX domain sockets in 083 - -RH-Author: Eric Blake -Message-id: <20171006192409.29915-4-eblake@redhat.com> -Patchwork-id: 76910 -O-Subject: [RHEV-7.5 qemu-kvm-rhev PATCH 3/4] qemu-iotests: test NBD over UNIX domain sockets in 083 -Bugzilla: 1482478 -RH-Acked-by: Max Reitz -RH-Acked-by: Laurent Vivier -RH-Acked-by: Stefan Hajnoczi - -From: Stefan Hajnoczi - -083 only tests TCP. Some failures might be specific to UNIX domain -sockets. - -A few adjustments are necessary: - -1. Generating a port number and waiting for server startup is - TCP-specific. Use the new nbd-fault-injector.py startup protocol to - fetch the address. This is a little more elegant because we don't - need netstat anymore. - -2. The NBD filter does not work for the UNIX domain sockets URIs we - generate and must be extended. - -3. Run all tests twice: once for TCP and once for UNIX domain sockets. - -Reviewed-by: Eric Blake -Signed-off-by: Stefan Hajnoczi -Message-Id: <20170829122745.14309-4-stefanha@redhat.com> -Signed-off-by: Eric Blake -(cherry picked from commit 02d2d860d25e439f0e88658c701668ab684568fb) -Signed-off-by: Miroslav Rezanina ---- - tests/qemu-iotests/083 | 136 ++++++++++++++++++++++-------------- - tests/qemu-iotests/083.out | 145 ++++++++++++++++++++++++++++++++++----- - tests/qemu-iotests/common.filter | 4 +- - 3 files changed, 214 insertions(+), 71 deletions(-) - -diff --git a/tests/qemu-iotests/083 b/tests/qemu-iotests/083 -index bff9360..0306f11 100755 ---- a/tests/qemu-iotests/083 -+++ b/tests/qemu-iotests/083 -@@ -27,6 +27,14 @@ echo "QA output created by $seq" - here=`pwd` - status=1 # failure is the default! - -+_cleanup() -+{ -+ rm -f nbd.sock -+ rm -f nbd-fault-injector.out -+ rm -f nbd-fault-injector.conf -+} -+trap "_cleanup; exit \$status" 0 1 2 3 15 -+ - # get standard environment, filters and checks - . ./common.rc - . ./common.filter -@@ -35,81 +43,105 @@ _supported_fmt generic - _supported_proto nbd - _supported_os Linux - --# Pick a TCP port based on our pid. This way multiple instances of this test --# can run in parallel without conflicting. --choose_tcp_port() { -- echo $((($$ % 31744) + 1024)) # 1024 <= port < 32768 --} -- --wait_for_tcp_port() { -- while ! (netstat --tcp --listening --numeric | \ -- grep "$1.*0\\.0\\.0\\.0:\\*.*LISTEN") >/dev/null 2>&1; do -- sleep 0.1 -+check_disconnect() { -+ local event export_name=foo extra_args nbd_addr nbd_url proto when -+ -+ while true; do -+ case $1 in -+ --classic-negotiation) -+ shift -+ extra_args=--classic-negotiation -+ export_name= -+ ;; -+ --tcp) -+ shift -+ proto=tcp -+ ;; -+ --unix) -+ shift -+ proto=unix -+ ;; -+ *) -+ break -+ ;; -+ esac - done --} - --check_disconnect() { - event=$1 - when=$2 -- negotiation=$3 - echo "=== Check disconnect $when $event ===" - echo - -- port=$(choose_tcp_port) -- - cat > "$TEST_DIR/nbd-fault-injector.conf" <"$TEST_DIR/nbd-fault-injector.out" 2>&1 & -+ -+ # Wait for server to be ready -+ while ! grep -q 'Listening on ' "$TEST_DIR/nbd-fault-injector.out"; do -+ sleep 0.1 -+ done -+ -+ # Extract the final address (port number has now been assigned in tcp case) -+ nbd_addr=$(sed 's/Listening on \(.*\)$/\1/' "$TEST_DIR/nbd-fault-injector.out") -+ -+ if [ "$proto" = "tcp" ]; then -+ nbd_url="nbd+tcp://$nbd_addr/$export_name" -+ else -+ nbd_url="nbd+unix:///$export_name?socket=$nbd_addr" - fi - -- $PYTHON nbd-fault-injector.py $extra_args "127.0.0.1:$port" "$TEST_DIR/nbd-fault-injector.conf" >/dev/null 2>&1 & -- wait_for_tcp_port "127\\.0\\.0\\.1:$port" - $QEMU_IO -c "read 0 512" "$nbd_url" 2>&1 | _filter_qemu_io | _filter_nbd - - echo - } - --for event in neg1 "export" neg2 request reply data; do -- for when in before after; do -- check_disconnect "$event" "$when" -- done -- -- # Also inject short replies from the NBD server -- case "$event" in -- neg1) -- for when in 8 16; do -- check_disconnect "$event" "$when" -- done -- ;; -- "export") -- for when in 4 12 16; do -- check_disconnect "$event" "$when" -+for proto in tcp unix; do -+ for event in neg1 "export" neg2 request reply data; do -+ for when in before after; do -+ check_disconnect "--$proto" "$event" "$when" - done -- ;; -- neg2) -- for when in 8 10; do -- check_disconnect "$event" "$when" -- done -- ;; -- reply) -- for when in 4 8; do -- check_disconnect "$event" "$when" -- done -- ;; -- esac --done - --# Also check classic negotiation without export information --for when in before 8 16 24 28 after; do -- check_disconnect "neg-classic" "$when" --classic-negotiation -+ # Also inject short replies from the NBD server -+ case "$event" in -+ neg1) -+ for when in 8 16; do -+ check_disconnect "--$proto" "$event" "$when" -+ done -+ ;; -+ "export") -+ for when in 4 12 16; do -+ check_disconnect "--$proto" "$event" "$when" -+ done -+ ;; -+ neg2) -+ for when in 8 10; do -+ check_disconnect "--$proto" "$event" "$when" -+ done -+ ;; -+ reply) -+ for when in 4 8; do -+ check_disconnect "--$proto" "$event" "$when" -+ done -+ ;; -+ esac -+ done -+ -+ # Also check classic negotiation without export information -+ for when in before 8 16 24 28 after; do -+ check_disconnect "--$proto" --classic-negotiation "neg-classic" "$when" -+ done - done - - # success, all done -diff --git a/tests/qemu-iotests/083.out b/tests/qemu-iotests/083.out -index a24c6bf..a7fb081 100644 ---- a/tests/qemu-iotests/083.out -+++ b/tests/qemu-iotests/083.out -@@ -1,43 +1,43 @@ - QA output created by 083 - === Check disconnect before neg1 === - --can't open device nbd:127.0.0.1:PORT:exportname=foo -+can't open device nbd+tcp://127.0.0.1:PORT/foo - - === Check disconnect after neg1 === - --can't open device nbd:127.0.0.1:PORT:exportname=foo -+can't open device nbd+tcp://127.0.0.1:PORT/foo - - === Check disconnect 8 neg1 === - --can't open device nbd:127.0.0.1:PORT:exportname=foo -+can't open device nbd+tcp://127.0.0.1:PORT/foo - - === Check disconnect 16 neg1 === - --can't open device nbd:127.0.0.1:PORT:exportname=foo -+can't open device nbd+tcp://127.0.0.1:PORT/foo - - === Check disconnect before export === - --can't open device nbd:127.0.0.1:PORT:exportname=foo -+can't open device nbd+tcp://127.0.0.1:PORT/foo - - === Check disconnect after export === - --can't open device nbd:127.0.0.1:PORT:exportname=foo -+can't open device nbd+tcp://127.0.0.1:PORT/foo - - === Check disconnect 4 export === - --can't open device nbd:127.0.0.1:PORT:exportname=foo -+can't open device nbd+tcp://127.0.0.1:PORT/foo - - === Check disconnect 12 export === - --can't open device nbd:127.0.0.1:PORT:exportname=foo -+can't open device nbd+tcp://127.0.0.1:PORT/foo - - === Check disconnect 16 export === - --can't open device nbd:127.0.0.1:PORT:exportname=foo -+can't open device nbd+tcp://127.0.0.1:PORT/foo - - === Check disconnect before neg2 === - --can't open device nbd:127.0.0.1:PORT:exportname=foo -+can't open device nbd+tcp://127.0.0.1:PORT/foo - - === Check disconnect after neg2 === - -@@ -45,11 +45,11 @@ read failed: Input/output error - - === Check disconnect 8 neg2 === - --can't open device nbd:127.0.0.1:PORT:exportname=foo -+can't open device nbd+tcp://127.0.0.1:PORT/foo - - === Check disconnect 10 neg2 === - --can't open device nbd:127.0.0.1:PORT:exportname=foo -+can't open device nbd+tcp://127.0.0.1:PORT/foo - - === Check disconnect before request === - -@@ -88,23 +88,134 @@ read 512/512 bytes at offset 0 - - === Check disconnect before neg-classic === - --can't open device nbd:127.0.0.1:PORT -+can't open device nbd+tcp://127.0.0.1:PORT/ - - === Check disconnect 8 neg-classic === - --can't open device nbd:127.0.0.1:PORT -+can't open device nbd+tcp://127.0.0.1:PORT/ - - === Check disconnect 16 neg-classic === - --can't open device nbd:127.0.0.1:PORT -+can't open device nbd+tcp://127.0.0.1:PORT/ - - === Check disconnect 24 neg-classic === - --can't open device nbd:127.0.0.1:PORT -+can't open device nbd+tcp://127.0.0.1:PORT/ - - === Check disconnect 28 neg-classic === - --can't open device nbd:127.0.0.1:PORT -+can't open device nbd+tcp://127.0.0.1:PORT/ -+ -+=== Check disconnect after neg-classic === -+ -+read failed: Input/output error -+ -+=== Check disconnect before neg1 === -+ -+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect after neg1 === -+ -+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect 8 neg1 === -+ -+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect 16 neg1 === -+ -+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect before export === -+ -+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect after export === -+ -+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect 4 export === -+ -+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect 12 export === -+ -+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect 16 export === -+ -+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect before neg2 === -+ -+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect after neg2 === -+ -+read failed: Input/output error -+ -+=== Check disconnect 8 neg2 === -+ -+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect 10 neg2 === -+ -+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect before request === -+ -+read failed: Input/output error -+ -+=== Check disconnect after request === -+ -+read failed: Input/output error -+ -+=== Check disconnect before reply === -+ -+read failed: Input/output error -+ -+=== Check disconnect after reply === -+ -+read failed: Input/output error -+ -+=== Check disconnect 4 reply === -+ -+read failed -+read failed: Input/output error -+ -+=== Check disconnect 8 reply === -+ -+read failed -+read failed: Input/output error -+ -+=== Check disconnect before data === -+ -+read failed: Input/output error -+ -+=== Check disconnect after data === -+ -+read 512/512 bytes at offset 0 -+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+=== Check disconnect before neg-classic === -+ -+can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect 8 neg-classic === -+ -+can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect 16 neg-classic === -+ -+can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect 24 neg-classic === -+ -+can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect 28 neg-classic === -+ -+can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock - - === Check disconnect after neg-classic === - -diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter -index 7a58e57..9d5442e 100644 ---- a/tests/qemu-iotests/common.filter -+++ b/tests/qemu-iotests/common.filter -@@ -170,9 +170,9 @@ _filter_nbd() - # - # Filter out the TCP port number since this changes between runs. - sed -e '/nbd\/.*\.c:/d' \ -- -e 's#nbd:\(//\)\?127\.0\.0\.1:[0-9]*#nbd:\1127.0.0.1:PORT#g' \ -+ -e 's#127\.0\.0\.1:[0-9]*#127.0.0.1:PORT#g' \ - -e "s#?socket=$TEST_DIR#?socket=TEST_DIR#g" \ -- -e 's#\(exportname=foo\|PORT\): Failed to .*$#\1#' -+ -e 's#\(foo\|PORT/\?\|.sock\): Failed to .*$#\1#' - } - - # make sure this script returns success --- -1.8.3.1 - diff --git a/SOURCES/kvm-qemu-iothread-IOThread-supports-the-GMainContext-eve.patch b/SOURCES/kvm-qemu-iothread-IOThread-supports-the-GMainContext-eve.patch deleted file mode 100644 index c395845..0000000 --- a/SOURCES/kvm-qemu-iothread-IOThread-supports-the-GMainContext-eve.patch +++ /dev/null @@ -1,134 +0,0 @@ -From 79000a2843af86fcd026ba8eb899dfeb1da0e04d Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Fri, 22 Dec 2017 11:08:43 +0100 -Subject: [PATCH 25/42] qemu-iothread: IOThread supports the GMainContext event - loop - -RH-Author: Stefan Hajnoczi -Message-id: <20171222110900.24813-4-stefanha@redhat.com> -Patchwork-id: 78485 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 03/20] qemu-iothread: IOThread supports the GMainContext event loop -Bugzilla: 1519721 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -From: Wang Yong - -IOThread uses AioContext event loop and does not run a GMainContext. -Therefore,chardev cannot work in IOThread,such as the chardev is -used for colo-compare packets reception. - -This patch makes the IOThread run the GMainContext event loop, -chardev and IOThread can work together. - -Reviewed-by: Fam Zheng -Signed-off-by: Wang Yong -Signed-off-by: Wang Guang -Signed-off-by: Jason Wang -(cherry picked from commit 329163cbe64a615b4edf6c40f2fff8c79dbc8fb4) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - include/sysemu/iothread.h | 4 ++++ - iothread.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 49 insertions(+) - -diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h -index e6da1a4..d2985b3 100644 ---- a/include/sysemu/iothread.h -+++ b/include/sysemu/iothread.h -@@ -24,6 +24,9 @@ typedef struct { - - QemuThread thread; - AioContext *ctx; -+ GMainContext *worker_context; -+ GMainLoop *main_loop; -+ GOnce once; - QemuMutex init_done_lock; - QemuCond init_done_cond; /* is thread initialization done? */ - bool stopping; -@@ -41,5 +44,6 @@ typedef struct { - char *iothread_get_id(IOThread *iothread); - AioContext *iothread_get_aio_context(IOThread *iothread); - void iothread_stop_all(void); -+GMainContext *iothread_get_g_main_context(IOThread *iothread); - - #endif /* IOTHREAD_H */ -diff --git a/iothread.c b/iothread.c -index d67bdd4..59d0850 100644 ---- a/iothread.c -+++ b/iothread.c -@@ -57,6 +57,23 @@ static void *iothread_run(void *opaque) - - while (!atomic_read(&iothread->stopping)) { - aio_poll(iothread->ctx, true); -+ -+ if (atomic_read(&iothread->worker_context)) { -+ GMainLoop *loop; -+ -+ g_main_context_push_thread_default(iothread->worker_context); -+ iothread->main_loop = -+ g_main_loop_new(iothread->worker_context, TRUE); -+ loop = iothread->main_loop; -+ -+ g_main_loop_run(iothread->main_loop); -+ iothread->main_loop = NULL; -+ g_main_loop_unref(loop); -+ -+ g_main_context_pop_thread_default(iothread->worker_context); -+ g_main_context_unref(iothread->worker_context); -+ iothread->worker_context = NULL; -+ } - } - - rcu_unregister_thread(); -@@ -73,6 +90,9 @@ static int iothread_stop(Object *object, void *opaque) - } - iothread->stopping = true; - aio_notify(iothread->ctx); -+ if (atomic_read(&iothread->main_loop)) { -+ g_main_loop_quit(iothread->main_loop); -+ } - qemu_thread_join(&iothread->thread); - return 0; - } -@@ -125,6 +145,7 @@ static void iothread_complete(UserCreatable *obj, Error **errp) - - qemu_mutex_init(&iothread->init_done_lock); - qemu_cond_init(&iothread->init_done_cond); -+ iothread->once = (GOnce) G_ONCE_INIT; - - /* This assumes we are called from a thread with useful CPU affinity for us - * to inherit. -@@ -309,3 +330,27 @@ void iothread_stop_all(void) - - object_child_foreach(container, iothread_stop, NULL); - } -+ -+static gpointer iothread_g_main_context_init(gpointer opaque) -+{ -+ AioContext *ctx; -+ IOThread *iothread = opaque; -+ GSource *source; -+ -+ iothread->worker_context = g_main_context_new(); -+ -+ ctx = iothread_get_aio_context(iothread); -+ source = aio_get_g_source(ctx); -+ g_source_attach(source, iothread->worker_context); -+ g_source_unref(source); -+ -+ aio_notify(iothread->ctx); -+ return NULL; -+} -+ -+GMainContext *iothread_get_g_main_context(IOThread *iothread) -+{ -+ g_once(&iothread->once, iothread_g_main_context_init, iothread); -+ -+ return iothread->worker_context; -+} --- -1.8.3.1 - diff --git a/SOURCES/kvm-qemu-kvm-ma-define-only-pseries-rhel7.5.0-machine-ty.patch b/SOURCES/kvm-qemu-kvm-ma-define-only-pseries-rhel7.5.0-machine-ty.patch deleted file mode 100644 index 3cdd38b..0000000 --- a/SOURCES/kvm-qemu-kvm-ma-define-only-pseries-rhel7.5.0-machine-ty.patch +++ /dev/null @@ -1,67 +0,0 @@ -From d8bf28e9ec1a5d854c3fa6f17001db2e8bc59a7a Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Mon, 9 Oct 2017 14:23:18 +0200 -Subject: [PATCH 08/69] qemu-kvm-ma: define only pseries-rhel7.5.0 machine type - for -ma - -RH-Author: Laurent Vivier -Message-id: <20171009142318.6262-5-lvivier@redhat.com> -Patchwork-id: 77032 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 4/4] qemu-kvm-ma: define only pseries-rhel7.5.0 machine type for -ma -Bugzilla: 1478478 -RH-Acked-by: David Gibson -RH-Acked-by: Thomas Huth -RH-Acked-by: Laszlo Ersek - -qemu-kvm-ma doesn't support pseries-rhel7.2.0, -pseries-rhel7.3.0, pseries-rhel7.4.0 whereas -qemu-kvm-rhev does. And as the sources are shared -we use a configuration switch to disable this part -of the code. - -Signed-off-by: Laurent Vivier -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index cb317f8..3c598fd 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -3734,6 +3734,7 @@ DEFINE_SPAPR_MACHINE(2_8, "2.8", false); - }, - #endif - -+#if defined(CONFIG_RHV) - static void phb_placement_2_7(sPAPRMachineState *spapr, uint32_t index, - uint64_t *buid, hwaddr *pio, - hwaddr *mmio32, hwaddr *mmio64, -@@ -3782,6 +3783,7 @@ static void phb_placement_2_7(sPAPRMachineState *spapr, uint32_t index, - * window into contiguous 32-bit and 64-bit windows - */ - } -+#endif /* CONFIG_RHV */ - - #if 0 /* Disabled for Red Hat Enterprise Linux */ - static void spapr_machine_2_7_instance_options(MachineState *machine) -@@ -3960,6 +3962,8 @@ static void spapr_machine_rhel750_class_options(MachineClass *mc) - - DEFINE_SPAPR_MACHINE(rhel750, "rhel7.5.0", true); - -+#if defined(CONFIG_RHV) -+ - /* - * pseries-rhel7.4.0 - * like SPAPR_COMPAT_2_9 -@@ -4079,6 +4083,7 @@ static void spapr_machine_rhel720_class_options(MachineClass *mc) - } - - DEFINE_SPAPR_MACHINE(rhel720, "rhel7.2.0", false); -+#endif /* CONFIG_RHV */ - - static void spapr_machine_register_types(void) - { --- -1.8.3.1 - diff --git a/SOURCES/kvm-qemu-kvm-rhev-only-allows-pseries-rhel7.5.0-machine-.patch b/SOURCES/kvm-qemu-kvm-rhev-only-allows-pseries-rhel7.5.0-machine-.patch deleted file mode 100644 index 57e3767..0000000 --- a/SOURCES/kvm-qemu-kvm-rhev-only-allows-pseries-rhel7.5.0-machine-.patch +++ /dev/null @@ -1,151 +0,0 @@ -From 8663586f2bc64d4761d4f621bc7aa781a4a450b2 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Fri, 20 Oct 2017 14:02:07 +0200 -Subject: [PATCH 1/9] qemu-kvm-rhev: only allows pseries-rhel7.5.0 machine type - with POWER9 guest - -RH-Author: Laurent Vivier -Message-id: <20171020140207.15190-1-lvivier@redhat.com> -Patchwork-id: 77416 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH v3 3/4] qemu-kvm-rhev: only allows pseries-rhel7.5.0 machine type with POWER9 guest -Bugzilla: 1478469 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Thomas Huth -RH-Acked-by: David Gibson - -We disable all machine types except pseries-rhel7.5.0 for POWER9 -guest. - -qemu-kvm-rhev does't not support POWER9 with former machine types -so disable them dynamically. We allow all machine types on POWER9 -host but with guest in POWER8 CPU mode -(for instance "-M pseries-rhel7.4.0,max-cpu-compat=power8") - -"-M help" display all the machine types, but if the guest is started -with "-cpu POWER9" and with a machine type which is not -"pseries-rhel7.5.0" an error message is displayed and the guest is -stopped. - -We use the ppc_check_compat() to compare current CPU version with ISA -level of POWER9 (CPU_POWERPC_LOGICAL_3_00), but as POWER9 DD1 has some -bugs, POWER9 DD1 does not advertise PCR_COMPAT_3_00 (see -kvmppc_host_cpu_class_init()), and thus this allows to run all the machine -types with POWER9 DD1. - -Signed-off-by: Laurent Vivier -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr.c | 2 ++ - hw/ppc/spapr_cpu_core.c | 13 +++++++++++++ - include/hw/ppc/spapr.h | 1 + - target/ppc/compat.c | 11 +++++++++++ - target/ppc/cpu.h | 1 + - 5 files changed, 28 insertions(+) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 5fe7769..42028ef 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -3592,6 +3592,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) - * in which LMBs are represented and hot-added - */ - mc->numa_mem_align_shift = 28; -+ smc->has_power9_support = true; - } - - static const TypeInfo spapr_machine_info = { -@@ -3993,6 +3994,7 @@ static void spapr_machine_rhel740_class_options(MachineClass *mc) - spapr_machine_rhel750_class_options(mc); - SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_RHEL7_4); - mc->numa_auto_assign_ram = numa_legacy_auto_assign_ram; -+ smc->has_power9_support = false; - smc->pre_2_10_has_unused_icps = true; - smc->resize_hpt_default = SPAPR_RESIZE_HPT_DISABLED; - } -diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c -index 3e731e4..400ab56 100644 ---- a/hw/ppc/spapr_cpu_core.c -+++ b/hw/ppc/spapr_cpu_core.c -@@ -19,6 +19,7 @@ - #include "target/ppc/mmu-hash64.h" - #include "sysemu/numa.h" - #include "qemu/error-report.h" -+#include "cpu-models.h" - - void spapr_cpu_parse_features(sPAPRMachineState *spapr) - { -@@ -111,6 +112,7 @@ static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, - Error **errp) - { - CPUPPCState *env = &cpu->env; -+ sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); - - /* Set time-base frequency to 512 MHz */ - cpu_ppc_tb_init(env, SPAPR_TIMEBASE_FREQ); -@@ -118,6 +120,17 @@ static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, - /* Enable PAPR mode in TCG or KVM */ - cpu_ppc_set_papr(cpu, PPC_VIRTUAL_HYPERVISOR(spapr)); - -+ if (!smc->has_power9_support && -+ (((spapr->max_compat_pvr && -+ ppc_compat_cmp(spapr->max_compat_pvr, -+ CPU_POWERPC_LOGICAL_3_00) >= 0)) || -+ (!spapr->max_compat_pvr && -+ ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00, 0, 0)))) { -+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, -+ "POWER9 CPU is not supported by this machine class"); -+ return; -+ } -+ - qemu_register_reset(spapr_cpu_reset, cpu); - spapr_cpu_reset(cpu); - } -diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h -index 3d0d206..d9e8e5a 100644 ---- a/include/hw/ppc/spapr.h -+++ b/include/hw/ppc/spapr.h -@@ -62,6 +62,7 @@ struct sPAPRMachineClass { - bool use_ohci_by_default; /* use USB-OHCI instead of XHCI */ - const char *tcg_default_cpu; /* which (TCG) CPU to simulate by default */ - bool pre_2_10_has_unused_icps; -+ bool has_power9_support; - void (*phb_placement)(sPAPRMachineState *spapr, uint32_t index, - uint64_t *buid, hwaddr *pio, - hwaddr *mmio32, hwaddr *mmio64, -diff --git a/target/ppc/compat.c b/target/ppc/compat.c -index f8729fe..540b4eb 100644 ---- a/target/ppc/compat.c -+++ b/target/ppc/compat.c -@@ -89,6 +89,17 @@ static const CompatInfo *compat_by_pvr(uint32_t pvr) - return NULL; - } - -+long ppc_compat_cmp(uint32_t pvr1, uint32_t pvr2) -+{ -+ const CompatInfo *compat1 = compat_by_pvr(pvr1); -+ const CompatInfo *compat2 = compat_by_pvr(pvr2); -+ -+ g_assert(compat1); -+ g_assert(compat2); -+ -+ return compat1 - compat2; -+} -+ - bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr, - uint32_t min_compat_pvr, uint32_t max_compat_pvr) - { -diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h -index 46d3dd8..6c770a2 100644 ---- a/target/ppc/cpu.h -+++ b/target/ppc/cpu.h -@@ -1367,6 +1367,7 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch) - - /* Compatibility modes */ - #if defined(TARGET_PPC64) -+long ppc_compat_cmp(uint32_t pvr1, uint32_t pvr2); - bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr, - uint32_t min_compat_pvr, uint32_t max_compat_pvr); - void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp); --- -1.8.3.1 - diff --git a/SOURCES/kvm-qemu-option-Pull-out-Supported-options-print.patch b/SOURCES/kvm-qemu-option-Pull-out-Supported-options-print.patch new file mode 100644 index 0000000..d2de31b --- /dev/null +++ b/SOURCES/kvm-qemu-option-Pull-out-Supported-options-print.patch @@ -0,0 +1,56 @@ +From 1f1faf92011618b0d32dc6a4a7e5b5119c38c2ac Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Mon, 18 Jun 2018 14:59:39 +0200 +Subject: [PATCH 05/89] qemu-option: Pull out "Supported options" print + +RH-Author: Max Reitz +Message-id: <20180618145943.4489-4-mreitz@redhat.com> +Patchwork-id: 80756 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 3/7] qemu-option: Pull out "Supported options" print +Bugzilla: 1537956 +RH-Acked-by: John Snow +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi + +It really is up to the caller to decide what this list of options means. + +Signed-off-by: Max Reitz +Reviewed-by: John Snow +Reviewed-by: Eric Blake +Message-id: 20180509210023.20283-4-mreitz@redhat.com +Signed-off-by: Max Reitz +(cherry picked from commit 7f3fb00136aaec74df8132492d1f48b8e9840258) +Signed-off-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + qemu-img.c | 1 + + util/qemu-option.c | 1 - + 2 files changed, 1 insertion(+), 1 deletion(-) + +diff --git a/qemu-img.c b/qemu-img.c +index e40d6ff..cdeb01b 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -261,6 +261,7 @@ static int print_block_option_help(const char *filename, const char *fmt) + create_opts = qemu_opts_append(create_opts, proto_drv->create_opts); + } + ++ printf("Supported options:\n"); + qemu_opts_print_help(create_opts); + qemu_opts_free(create_opts); + return 0; +diff --git a/util/qemu-option.c b/util/qemu-option.c +index d0756fd..95e6cf4 100644 +--- a/util/qemu-option.c ++++ b/util/qemu-option.c +@@ -218,7 +218,6 @@ void qemu_opts_print_help(QemuOptsList *list) + + assert(list); + desc = list->desc; +- printf("Supported options:\n"); + while (desc && desc->name) { + printf("%-16s %s\n", desc->name, + desc->help ? desc->help : "No description available"); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-options-Add-missing-newline-to-accel-help-text.patch b/SOURCES/kvm-qemu-options-Add-missing-newline-to-accel-help-text.patch new file mode 100644 index 0000000..987a129 --- /dev/null +++ b/SOURCES/kvm-qemu-options-Add-missing-newline-to-accel-help-text.patch @@ -0,0 +1,54 @@ +From 93dbdd330d91333053406b0a2bb9c4404dd210d3 Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Tue, 3 Jul 2018 13:27:24 +0200 +Subject: [PATCH 57/57] qemu-options: Add missing newline to -accel help text + +RH-Author: Eduardo Habkost +Message-id: <20180703132724.21964-2-ehabkost@redhat.com> +Patchwork-id: 81208 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/1] qemu-options: Add missing newline to -accel help text +Bugzilla: 1586313 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Igor Mammedov + +The newline was removed by commit c97d6d2c, and broke -help output: + +Before this patch: + + $ qemu-system-x86_64 -help | grep smp + thread=single|multi (enable multi-threaded TCG)-smp [...] + +After this patch: + + $ qemu-system-x86_64 -help | grep smp + -smp [cpus=]n[,maxcpus=cpus][,cores=cores][,threads=threads][,sockets=sockets] + +Fixes: c97d6d2cdf97edb4aebe832fdba65d701ad7bcb6 +Cc: Sergio Andres Gomez Del Real +Signed-off-by: Eduardo Habkost +Message-Id: <20180611195607.3015-1-ehabkost@redhat.com> +Signed-off-by: Paolo Bonzini +(cherry picked from commit 0b3c5c81bf0a9e32fd08c532acde3caa446b3712) +Signed-off-by: Eduardo Habkost +Signed-off-by: Miroslav Rezanina +--- + qemu-options.hx | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/qemu-options.hx b/qemu-options.hx +index 43f10b1..4271cd3 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -130,7 +130,7 @@ ETEXI + DEF("accel", HAS_ARG, QEMU_OPTION_accel, + "-accel [accel=]accelerator[,thread=single|multi]\n" + " select accelerator (kvm, xen, hax, hvf, whpx or tcg; use 'help' for a list)\n" +- " thread=single|multi (enable multi-threaded TCG)", QEMU_ARCH_ALL) ++ " thread=single|multi (enable multi-threaded TCG)\n", QEMU_ARCH_ALL) + STEXI + @item -accel @var{name}[,prop=@var{value}[,...]] + @findex -accel +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-options-Mention-locking-option-of-file-driver.patch b/SOURCES/kvm-qemu-options-Mention-locking-option-of-file-driver.patch deleted file mode 100644 index aefaf26..0000000 --- a/SOURCES/kvm-qemu-options-Mention-locking-option-of-file-driver.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 47c794c7f8010caf97447badfb059fc8fd6aa89f Mon Sep 17 00:00:00 2001 -From: Fam Zheng -Date: Thu, 30 Nov 2017 09:25:43 +0100 -Subject: [PATCH 06/36] qemu-options: Mention locking option of file driver - -RH-Author: Fam Zheng -Message-id: <20171130092544.19231-5-famz@redhat.com> -Patchwork-id: 78018 -O-Subject: [RHV7.5 qemu-kvm-ma PATCH 4/5] qemu-options: Mention locking option of file driver -Bugzilla: 1494210 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Jeffrey Cody -RH-Acked-by: John Snow - -Signed-off-by: Fam Zheng -Signed-off-by: Kevin Wolf -(cherry picked from commit 1878eaff9bdeece4546d4f9587e6c75ab0b79b8b) -Signed-off-by: Fam Zheng -Signed-off-by: Miroslav Rezanina ---- - qemu-options.hx | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/qemu-options.hx b/qemu-options.hx -index 50ba50e..5878359 100644 ---- a/qemu-options.hx -+++ b/qemu-options.hx -@@ -693,6 +693,10 @@ This is the protocol-level block driver for accessing regular files. - The path to the image file in the local filesystem - @item aio - Specifies the AIO backend (threads/native, default: threads) -+@item locking -+Specifies whether the image file is protected with Linux OFD / POSIX locks. The -+default is to use the Linux Open File Descriptor API if available, otherwise no -+lock is applied. (auto/on/off, default: auto) - @end table - Example: - @example --- -1.8.3.1 - diff --git a/SOURCES/kvm-qemu-pr-helper-miscellaneous-fixes.patch b/SOURCES/kvm-qemu-pr-helper-miscellaneous-fixes.patch deleted file mode 100644 index 7c0fc31..0000000 --- a/SOURCES/kvm-qemu-pr-helper-miscellaneous-fixes.patch +++ /dev/null @@ -1,131 +0,0 @@ -From 35c11f52fe8423b40d133e22150354a595fd109f Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Sat, 2 Dec 2017 12:19:53 +0100 -Subject: [PATCH 27/36] qemu-pr-helper: miscellaneous fixes - -RH-Author: Paolo Bonzini -Message-id: <20171202121953.13317-18-pbonzini@redhat.com> -Patchwork-id: 78090 -O-Subject: [RHEL7.4 qemu-kvm-rhev PATCH 17/17] qemu-pr-helper: miscellaneous fixes -Bugzilla: 1464908 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: John Snow - -1) Return a generic sense if TEST UNIT READY does not provide one; - -2) Fix two mistakes in copying from the spec. - -Reported-by: Dr. David Alan Gilbert -Signed-off-by: Paolo Bonzini -(cherry picked from commit 041a4acfdf4d9b2db60b10805aed94178dbf0463) -Signed-off-by: Miroslav Rezanina ---- - include/scsi/utils.h | 6 +++++- - scsi/qemu-pr-helper.c | 30 ++++++++++++++++++++++++++---- - scsi/utils.c | 10 ++++++++++ - 3 files changed, 41 insertions(+), 5 deletions(-) - -diff --git a/include/scsi/utils.h b/include/scsi/utils.h -index 00a4bdb..eb07e47 100644 ---- a/include/scsi/utils.h -+++ b/include/scsi/utils.h -@@ -76,7 +76,11 @@ extern const struct SCSISense sense_code_LUN_FAILURE; - extern const struct SCSISense sense_code_LUN_COMM_FAILURE; - /* Command aborted, Overlapped Commands Attempted */ - extern const struct SCSISense sense_code_OVERLAPPED_COMMANDS; --/* LUN not ready, Capacity data has changed */ -+/* Medium error, Unrecovered read error */ -+extern const struct SCSISense sense_code_READ_ERROR; -+/* LUN not ready, Cause not reportable */ -+extern const struct SCSISense sense_code_NOT_READY; -+/* Unit attention, Capacity data has changed */ - extern const struct SCSISense sense_code_CAPACITY_CHANGED; - /* Unit attention, SCSI bus reset */ - extern const struct SCSISense sense_code_SCSI_BUS_RESET; -diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c -index 42bc2cf..4c6ca63 100644 ---- a/scsi/qemu-pr-helper.c -+++ b/scsi/qemu-pr-helper.c -@@ -303,6 +303,22 @@ static int is_mpath(int fd) - return !strncmp(tgt->target_type, "multipath", DM_MAX_TYPE_NAME); - } - -+static SCSISense mpath_generic_sense(int r) -+{ -+ switch (r) { -+ case MPATH_PR_SENSE_NOT_READY: -+ return SENSE_CODE(NOT_READY); -+ case MPATH_PR_SENSE_MEDIUM_ERROR: -+ return SENSE_CODE(READ_ERROR); -+ case MPATH_PR_SENSE_HARDWARE_ERROR: -+ return SENSE_CODE(TARGET_FAILURE); -+ case MPATH_PR_SENSE_ABORTED_COMMAND: -+ return SENSE_CODE(IO_ERROR); -+ default: -+ abort(); -+ } -+} -+ - static int mpath_reconstruct_sense(int fd, int r, uint8_t *sense) - { - switch (r) { -@@ -318,7 +334,13 @@ static int mpath_reconstruct_sense(int fd, int r, uint8_t *sense) - */ - uint8_t cdb[6] = { TEST_UNIT_READY }; - int sz = 0; -- return do_sgio(fd, cdb, sense, NULL, &sz, SG_DXFER_NONE); -+ int r = do_sgio(fd, cdb, sense, NULL, &sz, SG_DXFER_NONE); -+ -+ if (r != GOOD) { -+ return r; -+ } -+ scsi_build_sense(sense, mpath_generic_sense(r)); -+ return CHECK_CONDITION; - } - - case MPATH_PR_SENSE_UNIT_ATTENTION: -@@ -438,7 +460,7 @@ static int multipath_pr_out(int fd, const uint8_t *cdb, uint8_t *sense, - memset(¶mp, 0, sizeof(paramp)); - memcpy(¶mp.key, ¶m[0], 8); - memcpy(¶mp.sa_key, ¶m[8], 8); -- paramp.sa_flags = param[10]; -+ paramp.sa_flags = param[20]; - if (sz > PR_OUT_FIXED_PARAM_SIZE) { - size_t transportid_len; - int i, j; -@@ -467,8 +489,8 @@ static int multipath_pr_out(int fd, const uint8_t *cdb, uint8_t *sense, - j += offsetof(struct transportid, n_port_name[8]); - i += 24; - break; -- case 3: -- case 0x43: -+ case 5: -+ case 0x45: - /* iSCSI transport. */ - len = lduw_be_p(¶m[i + 2]); - if (len > 252 || (len & 3) || i + len + 4 > transportid_len) { -diff --git a/scsi/utils.c b/scsi/utils.c -index 5684951..e4182a9 100644 ---- a/scsi/utils.c -+++ b/scsi/utils.c -@@ -211,6 +211,16 @@ const struct SCSISense sense_code_LUN_COMM_FAILURE = { - .key = ABORTED_COMMAND, .asc = 0x08, .ascq = 0x00 - }; - -+/* Medium Error, Unrecovered read error */ -+const struct SCSISense sense_code_READ_ERROR = { -+ .key = MEDIUM_ERROR, .asc = 0x11, .ascq = 0x00 -+}; -+ -+/* Not ready, Cause not reportable */ -+const struct SCSISense sense_code_NOT_READY = { -+ .key = NOT_READY, .asc = 0x04, .ascq = 0x00 -+}; -+ - /* Unit attention, Capacity data has changed */ - const struct SCSISense sense_code_CAPACITY_CHANGED = { - .key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09 --- -1.8.3.1 - diff --git a/SOURCES/kvm-qemu.py-make-VM-a-context-manager.patch b/SOURCES/kvm-qemu.py-make-VM-a-context-manager.patch deleted file mode 100644 index 8ea3252..0000000 --- a/SOURCES/kvm-qemu.py-make-VM-a-context-manager.patch +++ /dev/null @@ -1,74 +0,0 @@ -From da96c55a017fbc750b49550c6e7a523dcdab0dbe Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Fri, 22 Dec 2017 11:08:41 +0100 -Subject: [PATCH 23/42] qemu.py: make VM() a context manager - -RH-Author: Stefan Hajnoczi -Message-id: <20171222110900.24813-2-stefanha@redhat.com> -Patchwork-id: 78483 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 01/20] qemu.py: make VM() a context manager -Bugzilla: 1519721 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -There are a number of ways to ensure that the QEMU process is shut down -when the test ends, including atexit.register(), try: finally:, or -unittest.teardown() methods. All of these require extra code and the -programmer must remember to add vm.shutdown(). - -A nice solution is context managers: - - with VM(binary) as vm: - ... - # vm is guaranteed to be shut down here - -Cc: Eduardo Habkost -Signed-off-by: Stefan Hajnoczi -Reviewed-by: Eduardo Habkost -Message-id: 20170824072202.26818-2-stefanha@redhat.com -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit d792bc3811f22a22a46c7d9a725fd29029f54095) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - scripts/qemu.py | 16 +++++++++++++++- - 1 file changed, 15 insertions(+), 1 deletion(-) - -diff --git a/scripts/qemu.py b/scripts/qemu.py -index 880e3e8..4d8ee10 100644 ---- a/scripts/qemu.py -+++ b/scripts/qemu.py -@@ -21,7 +21,14 @@ import qmp.qmp - - - class QEMUMachine(object): -- '''A QEMU VM''' -+ '''A QEMU VM -+ -+ Use this object as a context manager to ensure the QEMU process terminates:: -+ -+ with VM(binary) as vm: -+ ... -+ # vm is guaranteed to be shut down here -+ ''' - - def __init__(self, binary, args=[], wrapper=[], name=None, test_dir="/var/tmp", - monitor_address=None, socket_scm_helper=None, debug=False): -@@ -40,6 +47,13 @@ class QEMUMachine(object): - self._socket_scm_helper = socket_scm_helper - self._debug = debug - -+ def __enter__(self): -+ return self -+ -+ def __exit__(self, exc_type, exc_val, exc_tb): -+ self.shutdown() -+ return False -+ - # This can be used to add an unused monitor instance. - def add_monitor_telnet(self, ip, port): - args = 'tcp:%s:%d,server,nowait,telnet' % (ip, port) --- -1.8.3.1 - diff --git a/SOURCES/kvm-qmp-transaction-support-for-x-block-dirty-bitmap-ena.patch b/SOURCES/kvm-qmp-transaction-support-for-x-block-dirty-bitmap-ena.patch new file mode 100644 index 0000000..d3aece2 --- /dev/null +++ b/SOURCES/kvm-qmp-transaction-support-for-x-block-dirty-bitmap-ena.patch @@ -0,0 +1,163 @@ +From a2c0037a5871c5982b742f255f6580f30482f1fc Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Wed, 18 Jul 2018 22:54:39 +0200 +Subject: [PATCH 54/89] qmp: transaction support for + x-block-dirty-bitmap-enable/disable + +RH-Author: John Snow +Message-id: <20180718225511.14878-4-jsnow@redhat.com> +Patchwork-id: 81410 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 03/35] qmp: transaction support for x-block-dirty-bitmap-enable/disable +Bugzilla: 1207657 +RH-Acked-by: Eric Blake +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng + +From: Vladimir Sementsov-Ogievskiy + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: John Snow +Reviewed-by: Jeff Cody +Message-id: 20180606182449.1607-4-jsnow@redhat.com +[Added x- prefix. --js] +Signed-off-by: John Snow +(cherry picked from commit c6490447402f574bbe45f45c318e0bdd19121baf) +Signed-off-by: John Snow + +Signed-off-by: Miroslav Rezanina +--- + blockdev.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++- + qapi/transaction.json | 4 +++ + 2 files changed, 84 insertions(+), 1 deletion(-) + +diff --git a/blockdev.c b/blockdev.c +index ca2ffff..a88d792 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -2094,6 +2094,7 @@ typedef struct BlockDirtyBitmapState { + BlockDriverState *bs; + HBitmap *backup; + bool prepared; ++ bool was_enabled; + } BlockDirtyBitmapState; + + static void block_dirty_bitmap_add_prepare(BlkActionState *common, +@@ -2193,6 +2194,74 @@ static void block_dirty_bitmap_clear_commit(BlkActionState *common) + hbitmap_free(state->backup); + } + ++static void block_dirty_bitmap_enable_prepare(BlkActionState *common, ++ Error **errp) ++{ ++ BlockDirtyBitmap *action; ++ BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState, ++ common, common); ++ ++ if (action_check_completion_mode(common, errp) < 0) { ++ return; ++ } ++ ++ action = common->action->u.x_block_dirty_bitmap_enable.data; ++ state->bitmap = block_dirty_bitmap_lookup(action->node, ++ action->name, ++ NULL, ++ errp); ++ if (!state->bitmap) { ++ return; ++ } ++ ++ state->was_enabled = bdrv_dirty_bitmap_enabled(state->bitmap); ++ bdrv_enable_dirty_bitmap(state->bitmap); ++} ++ ++static void block_dirty_bitmap_enable_abort(BlkActionState *common) ++{ ++ BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState, ++ common, common); ++ ++ if (!state->was_enabled) { ++ bdrv_disable_dirty_bitmap(state->bitmap); ++ } ++} ++ ++static void block_dirty_bitmap_disable_prepare(BlkActionState *common, ++ Error **errp) ++{ ++ BlockDirtyBitmap *action; ++ BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState, ++ common, common); ++ ++ if (action_check_completion_mode(common, errp) < 0) { ++ return; ++ } ++ ++ action = common->action->u.x_block_dirty_bitmap_disable.data; ++ state->bitmap = block_dirty_bitmap_lookup(action->node, ++ action->name, ++ NULL, ++ errp); ++ if (!state->bitmap) { ++ return; ++ } ++ ++ state->was_enabled = bdrv_dirty_bitmap_enabled(state->bitmap); ++ bdrv_disable_dirty_bitmap(state->bitmap); ++} ++ ++static void block_dirty_bitmap_disable_abort(BlkActionState *common) ++{ ++ BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState, ++ common, common); ++ ++ if (state->was_enabled) { ++ bdrv_enable_dirty_bitmap(state->bitmap); ++ } ++} ++ + static void abort_prepare(BlkActionState *common, Error **errp) + { + error_setg(errp, "Transaction aborted using Abort action"); +@@ -2253,7 +2322,17 @@ static const BlkActionOps actions[] = { + .prepare = block_dirty_bitmap_clear_prepare, + .commit = block_dirty_bitmap_clear_commit, + .abort = block_dirty_bitmap_clear_abort, +- } ++ }, ++ [TRANSACTION_ACTION_KIND_X_BLOCK_DIRTY_BITMAP_ENABLE] = { ++ .instance_size = sizeof(BlockDirtyBitmapState), ++ .prepare = block_dirty_bitmap_enable_prepare, ++ .abort = block_dirty_bitmap_enable_abort, ++ }, ++ [TRANSACTION_ACTION_KIND_X_BLOCK_DIRTY_BITMAP_DISABLE] = { ++ .instance_size = sizeof(BlockDirtyBitmapState), ++ .prepare = block_dirty_bitmap_disable_prepare, ++ .abort = block_dirty_bitmap_disable_abort, ++ } + }; + + /** +diff --git a/qapi/transaction.json b/qapi/transaction.json +index bd31279..d7e4274 100644 +--- a/qapi/transaction.json ++++ b/qapi/transaction.json +@@ -46,6 +46,8 @@ + # - @abort: since 1.6 + # - @block-dirty-bitmap-add: since 2.5 + # - @block-dirty-bitmap-clear: since 2.5 ++# - @x-block-dirty-bitmap-enable: since 3.0 ++# - @x-block-dirty-bitmap-disable: since 3.0 + # - @blockdev-backup: since 2.3 + # - @blockdev-snapshot: since 2.5 + # - @blockdev-snapshot-internal-sync: since 1.7 +@@ -59,6 +61,8 @@ + 'abort': 'Abort', + 'block-dirty-bitmap-add': 'BlockDirtyBitmapAdd', + 'block-dirty-bitmap-clear': 'BlockDirtyBitmap', ++ 'x-block-dirty-bitmap-enable': 'BlockDirtyBitmap', ++ 'x-block-dirty-bitmap-disable': 'BlockDirtyBitmap', + 'blockdev-backup': 'BlockdevBackup', + 'blockdev-snapshot': 'BlockdevSnapshot', + 'blockdev-snapshot-internal-sync': 'BlockdevSnapshotInternal', +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qobject-Ensure-base-is-at-offset-0.patch b/SOURCES/kvm-qobject-Ensure-base-is-at-offset-0.patch new file mode 100644 index 0000000..74f05aa --- /dev/null +++ b/SOURCES/kvm-qobject-Ensure-base-is-at-offset-0.patch @@ -0,0 +1,76 @@ +From 94cd049b8c81e2b58113db7cc289218f8925d27d Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Mon, 18 Jun 2018 08:43:09 +0200 +Subject: [PATCH 02/54] qobject: Ensure base is at offset 0 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20180618084330.30009-3-armbru@redhat.com> +Patchwork-id: 80724 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 02/23] qobject: Ensure base is at offset 0 +Bugzilla: 1557995 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +From: Marc-André Lureau + +All QObject types have the base QObject as their first field. This +allows the simplification of qobject_to(). + +Signed-off-by: Marc-André Lureau +Reviewed-by: Eric Blake +Message-Id: <20180419150145.24795-2-marcandre.lureau@redhat.com> +Reviewed-by: Markus Armbruster +[Commit message paragraph on type casts dropped, to avoid giving the +impression type casting would be okay] +Signed-off-by: Markus Armbruster +(cherry picked from commit 7ee9edfdb117da47c86c9764d90f0be11a648666) + +Signed-off-by: Miroslav Rezanina +--- + include/qapi/qmp/qobject.h | 5 ++--- + qobject/qobject.c | 9 +++++++++ + 2 files changed, 11 insertions(+), 3 deletions(-) + +diff --git a/include/qapi/qmp/qobject.h b/include/qapi/qmp/qobject.h +index e022707..5206ff9 100644 +--- a/include/qapi/qmp/qobject.h ++++ b/include/qapi/qmp/qobject.h +@@ -61,9 +61,8 @@ struct QObject { + QEMU_BUILD_BUG_MSG(QTYPE__MAX != 7, + "The QTYPE_CAST_TO_* list needs to be extended"); + +-#define qobject_to(type, obj) ({ \ +- QObject *_tmp = qobject_check_type(obj, glue(QTYPE_CAST_TO_, type)); \ +- _tmp ? container_of(_tmp, type, base) : (type *)NULL; }) ++#define qobject_to(type, obj) \ ++ ((type *)qobject_check_type(obj, glue(QTYPE_CAST_TO_, type))) + + /* Initialize an object to default values */ + static inline void qobject_init(QObject *obj, QType type) +diff --git a/qobject/qobject.c b/qobject/qobject.c +index 23600aa..87649c5 100644 +--- a/qobject/qobject.c ++++ b/qobject/qobject.c +@@ -16,6 +16,15 @@ + #include "qapi/qmp/qlist.h" + #include "qapi/qmp/qstring.h" + ++QEMU_BUILD_BUG_MSG( ++ offsetof(QNull, base) != 0 || ++ offsetof(QNum, base) != 0 || ++ offsetof(QString, base) != 0 || ++ offsetof(QDict, base) != 0 || ++ offsetof(QList, base) != 0 || ++ offsetof(QBool, base) != 0, ++ "base qobject must be at offset 0"); ++ + static void (*qdestroy[QTYPE__MAX])(QObject *) = { + [QTYPE_NONE] = NULL, /* No such object exists */ + [QTYPE_QNULL] = NULL, /* qnull_ is indestructible */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qobject-Modify-qobject_ref-to-return-obj.patch b/SOURCES/kvm-qobject-Modify-qobject_ref-to-return-obj.patch new file mode 100644 index 0000000..e24382b --- /dev/null +++ b/SOURCES/kvm-qobject-Modify-qobject_ref-to-return-obj.patch @@ -0,0 +1,437 @@ +From 2b24bd311f6a7a416432078f9e76f772759c7ea2 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Mon, 18 Jun 2018 08:43:12 +0200 +Subject: [PATCH 05/54] qobject: Modify qobject_ref() to return obj +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20180618084330.30009-6-armbru@redhat.com> +Patchwork-id: 80738 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 05/23] qobject: Modify qobject_ref() to return obj +Bugzilla: 1557995 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +From: Marc-André Lureau + +For convenience and clarity, make it possible to call qobject_ref() at +the time when the reference is associated with a variable, or +argument, by making qobject_ref() return the same pointer as given. +Use that to simplify the callers. + +Signed-off-by: Marc-André Lureau +Reviewed-by: Eric Blake +Message-Id: <20180419150145.24795-5-marcandre.lureau@redhat.com> +Reviewed-by: Markus Armbruster +[Useless change to qobject_ref_impl() dropped, commit message improved +slightly] +Signed-off-by: Markus Armbruster +(cherry picked from commit f5a74a5a50387c6f980b2e2f94f062487a1826da) + +Signed-off-by: Miroslav Rezanina +--- + block.c | 8 ++++---- + block/blkdebug.c | 7 +++---- + block/blkverify.c | 8 ++++---- + block/null.c | 3 +-- + block/nvme.c | 3 +-- + block/quorum.c | 4 ++-- + include/qapi/qmp/qnull.h | 3 +-- + include/qapi/qmp/qobject.h | 9 ++++++++- + monitor.c | 20 +++++++------------- + qapi/qobject-input-visitor.c | 6 ++---- + qapi/qobject-output-visitor.c | 7 +++---- + qobject/qdict.c | 33 +++++++++++---------------------- + 12 files changed, 47 insertions(+), 64 deletions(-) + +diff --git a/block.c b/block.c +index 55a7984..676e57f 100644 +--- a/block.c ++++ b/block.c +@@ -5134,8 +5134,8 @@ static bool append_open_options(QDict *d, BlockDriverState *bs) + continue; + } + +- qobject_ref(qdict_entry_value(entry)); +- qdict_put_obj(d, qdict_entry_key(entry), qdict_entry_value(entry)); ++ qdict_put_obj(d, qdict_entry_key(entry), ++ qobject_ref(qdict_entry_value(entry))); + found_any = true; + } + +@@ -5207,8 +5207,8 @@ void bdrv_refresh_filename(BlockDriverState *bs) + * suffices without querying the (exact_)filename of this BDS. */ + if (bs->file->bs->full_open_options) { + qdict_put_str(opts, "driver", drv->format_name); +- qobject_ref(bs->file->bs->full_open_options); +- qdict_put(opts, "file", bs->file->bs->full_open_options); ++ qdict_put(opts, "file", ++ qobject_ref(bs->file->bs->full_open_options)); + + bs->full_open_options = opts; + } else { +diff --git a/block/blkdebug.c b/block/blkdebug.c +index 689703d..053372c 100644 +--- a/block/blkdebug.c ++++ b/block/blkdebug.c +@@ -845,13 +845,12 @@ static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options) + opts = qdict_new(); + qdict_put_str(opts, "driver", "blkdebug"); + +- qobject_ref(bs->file->bs->full_open_options); +- qdict_put(opts, "image", bs->file->bs->full_open_options); ++ qdict_put(opts, "image", qobject_ref(bs->file->bs->full_open_options)); + + for (e = qdict_first(options); e; e = qdict_next(options, e)) { + if (strcmp(qdict_entry_key(e), "x-image")) { +- qobject_ref(qdict_entry_value(e)); +- qdict_put_obj(opts, qdict_entry_key(e), qdict_entry_value(e)); ++ qdict_put_obj(opts, qdict_entry_key(e), ++ qobject_ref(qdict_entry_value(e))); + } + } + +diff --git a/block/blkverify.c b/block/blkverify.c +index 3cffcb1..754cc9e 100644 +--- a/block/blkverify.c ++++ b/block/blkverify.c +@@ -291,10 +291,10 @@ static void blkverify_refresh_filename(BlockDriverState *bs, QDict *options) + QDict *opts = qdict_new(); + qdict_put_str(opts, "driver", "blkverify"); + +- qobject_ref(bs->file->bs->full_open_options); +- qdict_put(opts, "raw", bs->file->bs->full_open_options); +- qobject_ref(s->test_file->bs->full_open_options); +- qdict_put(opts, "test", s->test_file->bs->full_open_options); ++ qdict_put(opts, "raw", ++ qobject_ref(bs->file->bs->full_open_options)); ++ qdict_put(opts, "test", ++ qobject_ref(s->test_file->bs->full_open_options)); + + bs->full_open_options = opts; + } +diff --git a/block/null.c b/block/null.c +index 700a2d0..3944550 100644 +--- a/block/null.c ++++ b/block/null.c +@@ -244,7 +244,6 @@ static int coroutine_fn null_co_block_status(BlockDriverState *bs, + + static void null_refresh_filename(BlockDriverState *bs, QDict *opts) + { +- qobject_ref(opts); + qdict_del(opts, "filename"); + + if (!qdict_size(opts)) { +@@ -253,7 +252,7 @@ static void null_refresh_filename(BlockDriverState *bs, QDict *opts) + } + + qdict_put_str(opts, "driver", bs->drv->format_name); +- bs->full_open_options = opts; ++ bs->full_open_options = qobject_ref(opts); + } + + static BlockDriver bdrv_null_co = { +diff --git a/block/nvme.c b/block/nvme.c +index e192da9..6f71122 100644 +--- a/block/nvme.c ++++ b/block/nvme.c +@@ -1073,7 +1073,6 @@ static int nvme_reopen_prepare(BDRVReopenState *reopen_state, + + static void nvme_refresh_filename(BlockDriverState *bs, QDict *opts) + { +- qobject_ref(opts); + qdict_del(opts, "filename"); + + if (!qdict_size(opts)) { +@@ -1082,7 +1081,7 @@ static void nvme_refresh_filename(BlockDriverState *bs, QDict *opts) + } + + qdict_put_str(opts, "driver", bs->drv->format_name); +- bs->full_open_options = opts; ++ bs->full_open_options = qobject_ref(opts); + } + + static void nvme_refresh_limits(BlockDriverState *bs, Error **errp) +diff --git a/block/quorum.c b/block/quorum.c +index 862cea3..a5051da 100644 +--- a/block/quorum.c ++++ b/block/quorum.c +@@ -1082,8 +1082,8 @@ static void quorum_refresh_filename(BlockDriverState *bs, QDict *options) + + children = qlist_new(); + for (i = 0; i < s->num_children; i++) { +- qobject_ref(s->children[i]->bs->full_open_options); +- qlist_append(children, s->children[i]->bs->full_open_options); ++ qlist_append(children, ++ qobject_ref(s->children[i]->bs->full_open_options)); + } + + opts = qdict_new(); +diff --git a/include/qapi/qmp/qnull.h b/include/qapi/qmp/qnull.h +index 75b29c6..c142688 100644 +--- a/include/qapi/qmp/qnull.h ++++ b/include/qapi/qmp/qnull.h +@@ -23,8 +23,7 @@ extern QNull qnull_; + + static inline QNull *qnull(void) + { +- qobject_ref(&qnull_); +- return &qnull_; ++ return qobject_ref(&qnull_); + } + + bool qnull_is_equal(const QObject *x, const QObject *y); +diff --git a/include/qapi/qmp/qobject.h b/include/qapi/qmp/qobject.h +index e20006f..fcfd549 100644 +--- a/include/qapi/qmp/qobject.h ++++ b/include/qapi/qmp/qobject.h +@@ -103,8 +103,15 @@ static inline void qobject_unref_impl(QObject *obj) + + /** + * qobject_ref(): Increment QObject's reference count ++ * ++ * Returns: the same @obj. The type of @obj will be propagated to the ++ * return type. + */ +-#define qobject_ref(obj) qobject_ref_impl(QOBJECT(obj)) ++#define qobject_ref(obj) ({ \ ++ typeof(obj) _o = (obj); \ ++ qobject_ref_impl(QOBJECT(_o)); \ ++ _o; \ ++}) + + /** + * qobject_unref(): Decrement QObject's reference count, deallocate +diff --git a/monitor.c b/monitor.c +index 32f72f2..d948dbd 100644 +--- a/monitor.c ++++ b/monitor.c +@@ -494,9 +494,8 @@ static void monitor_json_emitter(Monitor *mon, QObject *data) + * caller won't free the data (which will be finally freed in + * responder thread). + */ +- qobject_ref(data); + qemu_mutex_lock(&mon->qmp.qmp_queue_lock); +- g_queue_push_tail(mon->qmp.qmp_responses, data); ++ g_queue_push_tail(mon->qmp.qmp_responses, qobject_ref(data)); + qemu_mutex_unlock(&mon->qmp.qmp_queue_lock); + qemu_bh_schedule(mon_global.qmp_respond_bh); + } else { +@@ -614,8 +613,7 @@ monitor_qapi_event_queue(QAPIEvent event, QDict *qdict, Error **errp) + * replacing a prior stored event if any. + */ + qobject_unref(evstate->qdict); +- evstate->qdict = qdict; +- qobject_ref(evstate->qdict); ++ evstate->qdict = qobject_ref(qdict); + } else { + /* + * Last send was (at least) evconf->rate ns ago. +@@ -629,8 +627,7 @@ monitor_qapi_event_queue(QAPIEvent event, QDict *qdict, Error **errp) + + evstate = g_new(MonitorQAPIEventState, 1); + evstate->event = event; +- evstate->data = data; +- qobject_ref(evstate->data); ++ evstate->data = qobject_ref(data); + evstate->qdict = NULL; + evstate->timer = timer_new_ns(event_clock_type, + monitor_qapi_event_handler, +@@ -4066,9 +4063,7 @@ static void monitor_qmp_respond(Monitor *mon, QObject *rsp, + + if (rsp) { + if (id) { +- /* This is for the qdict below. */ +- qobject_ref(id); +- qdict_put_obj(qobject_to(QDict, rsp), "id", id); ++ qdict_put_obj(qobject_to(QDict, rsp), "id", qobject_ref(id)); + } + + monitor_json_emitter(mon, rsp); +@@ -4208,15 +4203,14 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens) + goto err; + } + +- qobject_ref(id); +- qdict_del(qdict, "id"); +- + req_obj = g_new0(QMPRequest, 1); + req_obj->mon = mon; +- req_obj->id = id; ++ req_obj->id = qobject_ref(id); + req_obj->req = req; + req_obj->need_resume = false; + ++ qdict_del(qdict, "id"); ++ + if (qmp_is_oob(qdict)) { + /* Out-Of-Band (OOB) requests are executed directly in parser. */ + trace_monitor_qmp_cmd_out_of_band(qobject_get_try_str(req_obj->id) +diff --git a/qapi/qobject-input-visitor.c b/qapi/qobject-input-visitor.c +index 7a290c4..da57f4c 100644 +--- a/qapi/qobject-input-visitor.c ++++ b/qapi/qobject-input-visitor.c +@@ -588,8 +588,7 @@ static void qobject_input_type_any(Visitor *v, const char *name, QObject **obj, + return; + } + +- qobject_ref(qobj); +- *obj = qobj; ++ *obj = qobject_ref(qobj); + } + + static void qobject_input_type_null(Visitor *v, const char *name, +@@ -677,8 +676,7 @@ static QObjectInputVisitor *qobject_input_visitor_base_new(QObject *obj) + v->visitor.optional = qobject_input_optional; + v->visitor.free = qobject_input_free; + +- v->root = obj; +- qobject_ref(obj); ++ v->root = qobject_ref(obj); + + return v; + } +diff --git a/qapi/qobject-output-visitor.c b/qapi/qobject-output-visitor.c +index 3a933b4..89ffd8a 100644 +--- a/qapi/qobject-output-visitor.c ++++ b/qapi/qobject-output-visitor.c +@@ -188,8 +188,8 @@ static void qobject_output_type_any(Visitor *v, const char *name, + QObject **obj, Error **errp) + { + QObjectOutputVisitor *qov = to_qov(v); +- qobject_ref(*obj); +- qobject_output_add_obj(qov, name, *obj); ++ ++ qobject_output_add_obj(qov, name, qobject_ref(*obj)); + } + + static void qobject_output_type_null(Visitor *v, const char *name, +@@ -210,8 +210,7 @@ static void qobject_output_complete(Visitor *v, void *opaque) + assert(qov->root && QSLIST_EMPTY(&qov->stack)); + assert(opaque == qov->result); + +- qobject_ref(qov->root); +- *qov->result = qov->root; ++ *qov->result = qobject_ref(qov->root); + qov->result = NULL; + } + +diff --git a/qobject/qdict.c b/qobject/qdict.c +index 2e9bd53..22800ee 100644 +--- a/qobject/qdict.c ++++ b/qobject/qdict.c +@@ -373,8 +373,7 @@ QDict *qdict_clone_shallow(const QDict *src) + + for (i = 0; i < QDICT_BUCKET_MAX; i++) { + QLIST_FOREACH(entry, &src->table[i], next) { +- qobject_ref(entry->value); +- qdict_put_obj(dest, entry->key, entry->value); ++ qdict_put_obj(dest, entry->key, qobject_ref(entry->value)); + } + } + +@@ -480,8 +479,7 @@ void qdict_copy_default(QDict *dst, QDict *src, const char *key) + + val = qdict_get(src, key); + if (val) { +- qobject_ref(val); +- qdict_put_obj(dst, key, val); ++ qdict_put_obj(dst, key, qobject_ref(val)); + } + } + +@@ -526,8 +524,7 @@ static void qdict_flatten_qlist(QList *qlist, QDict *target, const char *prefix) + qdict_flatten_qlist(qobject_to(QList, value), target, new_key); + } else { + /* All other types are moved to the target unchanged. */ +- qobject_ref(value); +- qdict_put_obj(target, new_key, value); ++ qdict_put_obj(target, new_key, qobject_ref(value)); + } + + g_free(new_key); +@@ -566,8 +563,7 @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix) + delete = true; + } else if (prefix) { + /* All other objects are moved to the target unchanged. */ +- qobject_ref(value); +- qdict_put_obj(target, new_key, value); ++ qdict_put_obj(target, new_key, qobject_ref(value)); + delete = true; + } + +@@ -610,8 +606,7 @@ void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start) + while (entry != NULL) { + next = qdict_next(src, entry); + if (strstart(entry->key, start, &p)) { +- qobject_ref(entry->value); +- qdict_put_obj(*dst, p, entry->value); ++ qdict_put_obj(*dst, p, qobject_ref(entry->value)); + qdict_del(src, entry->key); + } + entry = next; +@@ -894,16 +889,14 @@ QObject *qdict_crumple(const QDict *src, Error **errp) + qdict_put_obj(two_level, prefix, QOBJECT(child_dict)); + } + +- qobject_ref(ent->value); +- qdict_put_obj(child_dict, suffix, ent->value); ++ qdict_put_obj(child_dict, suffix, qobject_ref(ent->value)); + } else { + if (child) { + error_setg(errp, "Key %s prefix is already set as a dict", + prefix); + goto error; + } +- qobject_ref(ent->value); +- qdict_put_obj(two_level, prefix, ent->value); ++ qdict_put_obj(two_level, prefix, qobject_ref(ent->value)); + } + + g_free(prefix); +@@ -924,8 +917,7 @@ QObject *qdict_crumple(const QDict *src, Error **errp) + + qdict_put_obj(multi_level, ent->key, child); + } else { +- qobject_ref(ent->value); +- qdict_put_obj(multi_level, ent->key, ent->value); ++ qdict_put_obj(multi_level, ent->key, qobject_ref(ent->value)); + } + } + qobject_unref(two_level); +@@ -951,8 +943,7 @@ QObject *qdict_crumple(const QDict *src, Error **errp) + goto error; + } + +- qobject_ref(child); +- qlist_append_obj(qobject_to(QList, dst), child); ++ qlist_append_obj(qobject_to(QList, dst), qobject_ref(child)); + } + qobject_unref(multi_level); + multi_level = NULL; +@@ -1055,8 +1046,7 @@ void qdict_join(QDict *dest, QDict *src, bool overwrite) + next = qdict_next(src, entry); + + if (overwrite || !qdict_haskey(dest, entry->key)) { +- qobject_ref(entry->value); +- qdict_put_obj(dest, entry->key, entry->value); ++ qdict_put_obj(dest, entry->key, qobject_ref(entry->value)); + qdict_del(src, entry->key); + } + +@@ -1088,8 +1078,7 @@ bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp) + } + + qobj = qdict_get(qdict, renames->from); +- qobject_ref(qobj); +- qdict_put_obj(qdict, renames->to, qobj); ++ qdict_put_obj(qdict, renames->to, qobject_ref(qobj)); + qdict_del(qdict, renames->from); + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qobject-Move-block-specific-qdict-code-to-block-qdic.patch b/SOURCES/kvm-qobject-Move-block-specific-qdict-code-to-block-qdic.patch new file mode 100644 index 0000000..4f0255a --- /dev/null +++ b/SOURCES/kvm-qobject-Move-block-specific-qdict-code-to-block-qdic.patch @@ -0,0 +1,2728 @@ +From 4b3bbc27a6554471969347a1f0ddd70cd80e2b0b Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Mon, 18 Jun 2018 08:43:16 +0200 +Subject: [PATCH 09/54] qobject: Move block-specific qdict code to + block-qdict.c + +RH-Author: Markus Armbruster +Message-id: <20180618084330.30009-10-armbru@redhat.com> +Patchwork-id: 80722 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 09/23] qobject: Move block-specific qdict code to block-qdict.c +Bugzilla: 1557995 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Pure code motion, except for two brace placements and a comment +tweaked to appease checkpatch. + +Signed-off-by: Markus Armbruster +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit 0bcc8e5bd8d6fd6e5cb6462054f7cfa45b282f9a) +Signed-off-by: Miroslav Rezanina +--- + MAINTAINERS | 2 + + qobject/Makefile.objs | 1 + + qobject/block-qdict.c | 640 ++++++++++++++++++++++++++++++++++++++++++++ + qobject/qdict.c | 629 -------------------------------------------- + tests/Makefile.include | 4 + + tests/check-block-qdict.c | 655 ++++++++++++++++++++++++++++++++++++++++++++++ + tests/check-qdict.c | 642 --------------------------------------------- + 7 files changed, 1302 insertions(+), 1271 deletions(-) + create mode 100644 qobject/block-qdict.c + create mode 100644 tests/check-block-qdict.c + +diff --git a/MAINTAINERS b/MAINTAINERS +index 24b7016..ad5edc8 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -1339,6 +1339,8 @@ F: qemu-img* + F: qemu-io* + F: tests/qemu-iotests/ + F: util/qemu-progress.c ++F: qobject/block-qdict.c ++F: test/check-block-qdict.c + T: git git://repo.or.cz/qemu/kevin.git block + + Block I/O path +diff --git a/qobject/Makefile.objs b/qobject/Makefile.objs +index 002d258..7b12c9c 100644 +--- a/qobject/Makefile.objs ++++ b/qobject/Makefile.objs +@@ -1,2 +1,3 @@ + util-obj-y = qnull.o qnum.o qstring.o qdict.o qlist.o qbool.o qlit.o + util-obj-y += qjson.o qobject.o json-lexer.o json-streamer.o json-parser.o ++util-obj-y += block-qdict.o +diff --git a/qobject/block-qdict.c b/qobject/block-qdict.c +new file mode 100644 +index 0000000..fb92010 +--- /dev/null ++++ b/qobject/block-qdict.c +@@ -0,0 +1,640 @@ ++/* ++ * Special QDict functions used by the block layer ++ * ++ * Copyright (c) 2013-2018 Red Hat, Inc. ++ * ++ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. ++ * See the COPYING.LIB file in the top-level directory. ++ */ ++ ++#include "qemu/osdep.h" ++#include "block/qdict.h" ++#include "qapi/qmp/qlist.h" ++#include "qemu/cutils.h" ++#include "qapi/error.h" ++ ++/** ++ * qdict_copy_default(): If no entry mapped by 'key' exists in 'dst' yet, the ++ * value of 'key' in 'src' is copied there (and the refcount increased ++ * accordingly). ++ */ ++void qdict_copy_default(QDict *dst, QDict *src, const char *key) ++{ ++ QObject *val; ++ ++ if (qdict_haskey(dst, key)) { ++ return; ++ } ++ ++ val = qdict_get(src, key); ++ if (val) { ++ qdict_put_obj(dst, key, qobject_ref(val)); ++ } ++} ++ ++/** ++ * qdict_set_default_str(): If no entry mapped by 'key' exists in 'dst' yet, a ++ * new QString initialised by 'val' is put there. ++ */ ++void qdict_set_default_str(QDict *dst, const char *key, const char *val) ++{ ++ if (qdict_haskey(dst, key)) { ++ return; ++ } ++ ++ qdict_put_str(dst, key, val); ++} ++ ++static void qdict_flatten_qdict(QDict *qdict, QDict *target, ++ const char *prefix); ++ ++static void qdict_flatten_qlist(QList *qlist, QDict *target, const char *prefix) ++{ ++ QObject *value; ++ const QListEntry *entry; ++ char *new_key; ++ int i; ++ ++ /* This function is never called with prefix == NULL, i.e., it is always ++ * called from within qdict_flatten_q(list|dict)(). Therefore, it does not ++ * need to remove list entries during the iteration (the whole list will be ++ * deleted eventually anyway from qdict_flatten_qdict()). */ ++ assert(prefix); ++ ++ entry = qlist_first(qlist); ++ ++ for (i = 0; entry; entry = qlist_next(entry), i++) { ++ value = qlist_entry_obj(entry); ++ new_key = g_strdup_printf("%s.%i", prefix, i); ++ ++ if (qobject_type(value) == QTYPE_QDICT) { ++ qdict_flatten_qdict(qobject_to(QDict, value), target, new_key); ++ } else if (qobject_type(value) == QTYPE_QLIST) { ++ qdict_flatten_qlist(qobject_to(QList, value), target, new_key); ++ } else { ++ /* All other types are moved to the target unchanged. */ ++ qdict_put_obj(target, new_key, qobject_ref(value)); ++ } ++ ++ g_free(new_key); ++ } ++} ++ ++static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix) ++{ ++ QObject *value; ++ const QDictEntry *entry, *next; ++ char *new_key; ++ bool delete; ++ ++ entry = qdict_first(qdict); ++ ++ while (entry != NULL) { ++ ++ next = qdict_next(qdict, entry); ++ value = qdict_entry_value(entry); ++ new_key = NULL; ++ delete = false; ++ ++ if (prefix) { ++ new_key = g_strdup_printf("%s.%s", prefix, entry->key); ++ } ++ ++ if (qobject_type(value) == QTYPE_QDICT) { ++ /* Entries of QDicts are processed recursively, the QDict object ++ * itself disappears. */ ++ qdict_flatten_qdict(qobject_to(QDict, value), target, ++ new_key ? new_key : entry->key); ++ delete = true; ++ } else if (qobject_type(value) == QTYPE_QLIST) { ++ qdict_flatten_qlist(qobject_to(QList, value), target, ++ new_key ? new_key : entry->key); ++ delete = true; ++ } else if (prefix) { ++ /* All other objects are moved to the target unchanged. */ ++ qdict_put_obj(target, new_key, qobject_ref(value)); ++ delete = true; ++ } ++ ++ g_free(new_key); ++ ++ if (delete) { ++ qdict_del(qdict, entry->key); ++ ++ /* Restart loop after modifying the iterated QDict */ ++ entry = qdict_first(qdict); ++ continue; ++ } ++ ++ entry = next; ++ } ++} ++ ++/** ++ * qdict_flatten(): For each nested QDict with key x, all fields with key y ++ * are moved to this QDict and their key is renamed to "x.y". For each nested ++ * QList with key x, the field at index y is moved to this QDict with the key ++ * "x.y" (i.e., the reverse of what qdict_array_split() does). ++ * This operation is applied recursively for nested QDicts and QLists. ++ */ ++void qdict_flatten(QDict *qdict) ++{ ++ qdict_flatten_qdict(qdict, qdict, NULL); ++} ++ ++/* extract all the src QDict entries starting by start into dst */ ++void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start) ++ ++{ ++ const QDictEntry *entry, *next; ++ const char *p; ++ ++ *dst = qdict_new(); ++ entry = qdict_first(src); ++ ++ while (entry != NULL) { ++ next = qdict_next(src, entry); ++ if (strstart(entry->key, start, &p)) { ++ qdict_put_obj(*dst, p, qobject_ref(entry->value)); ++ qdict_del(src, entry->key); ++ } ++ entry = next; ++ } ++} ++ ++static int qdict_count_prefixed_entries(const QDict *src, const char *start) ++{ ++ const QDictEntry *entry; ++ int count = 0; ++ ++ for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) { ++ if (strstart(entry->key, start, NULL)) { ++ if (count == INT_MAX) { ++ return -ERANGE; ++ } ++ count++; ++ } ++ } ++ ++ return count; ++} ++ ++/** ++ * qdict_array_split(): This function moves array-like elements of a QDict into ++ * a new QList. Every entry in the original QDict with a key "%u" or one ++ * prefixed "%u.", where %u designates an unsigned integer starting at 0 and ++ * incrementally counting up, will be moved to a new QDict at index %u in the ++ * output QList with the key prefix removed, if that prefix is "%u.". If the ++ * whole key is just "%u", the whole QObject will be moved unchanged without ++ * creating a new QDict. The function terminates when there is no entry in the ++ * QDict with a prefix directly (incrementally) following the last one; it also ++ * returns if there are both entries with "%u" and "%u." for the same index %u. ++ * Example: {"0.a": 42, "0.b": 23, "1.x": 0, "4.y": 1, "o.o": 7, "2": 66} ++ * (or {"1.x": 0, "4.y": 1, "0.a": 42, "o.o": 7, "0.b": 23, "2": 66}) ++ * => [{"a": 42, "b": 23}, {"x": 0}, 66] ++ * and {"4.y": 1, "o.o": 7} (remainder of the old QDict) ++ */ ++void qdict_array_split(QDict *src, QList **dst) ++{ ++ unsigned i; ++ ++ *dst = qlist_new(); ++ ++ for (i = 0; i < UINT_MAX; i++) { ++ QObject *subqobj; ++ bool is_subqdict; ++ QDict *subqdict; ++ char indexstr[32], prefix[32]; ++ size_t snprintf_ret; ++ ++ snprintf_ret = snprintf(indexstr, 32, "%u", i); ++ assert(snprintf_ret < 32); ++ ++ subqobj = qdict_get(src, indexstr); ++ ++ snprintf_ret = snprintf(prefix, 32, "%u.", i); ++ assert(snprintf_ret < 32); ++ ++ /* Overflow is the same as positive non-zero results */ ++ is_subqdict = qdict_count_prefixed_entries(src, prefix); ++ ++ /* ++ * There may be either a single subordinate object (named ++ * "%u") or multiple objects (each with a key prefixed "%u."), ++ * but not both. ++ */ ++ if (!subqobj == !is_subqdict) { ++ break; ++ } ++ ++ if (is_subqdict) { ++ qdict_extract_subqdict(src, &subqdict, prefix); ++ assert(qdict_size(subqdict) > 0); ++ } else { ++ qobject_ref(subqobj); ++ qdict_del(src, indexstr); ++ } ++ ++ qlist_append_obj(*dst, subqobj ?: QOBJECT(subqdict)); ++ } ++} ++ ++/** ++ * qdict_split_flat_key: ++ * @key: the key string to split ++ * @prefix: non-NULL pointer to hold extracted prefix ++ * @suffix: non-NULL pointer to remaining suffix ++ * ++ * Given a flattened key such as 'foo.0.bar', split it into two parts ++ * at the first '.' separator. Allows double dot ('..') to escape the ++ * normal separator. ++ * ++ * e.g. ++ * 'foo.0.bar' -> prefix='foo' and suffix='0.bar' ++ * 'foo..0.bar' -> prefix='foo.0' and suffix='bar' ++ * ++ * The '..' sequence will be unescaped in the returned 'prefix' ++ * string. The 'suffix' string will be left in escaped format, so it ++ * can be fed back into the qdict_split_flat_key() key as the input ++ * later. ++ * ++ * The caller is responsible for freeing the string returned in @prefix ++ * using g_free(). ++ */ ++static void qdict_split_flat_key(const char *key, char **prefix, ++ const char **suffix) ++{ ++ const char *separator; ++ size_t i, j; ++ ++ /* Find first '.' separator, but if there is a pair '..' ++ * that acts as an escape, so skip over '..' */ ++ separator = NULL; ++ do { ++ if (separator) { ++ separator += 2; ++ } else { ++ separator = key; ++ } ++ separator = strchr(separator, '.'); ++ } while (separator && separator[1] == '.'); ++ ++ if (separator) { ++ *prefix = g_strndup(key, separator - key); ++ *suffix = separator + 1; ++ } else { ++ *prefix = g_strdup(key); ++ *suffix = NULL; ++ } ++ ++ /* Unescape the '..' sequence into '.' */ ++ for (i = 0, j = 0; (*prefix)[i] != '\0'; i++, j++) { ++ if ((*prefix)[i] == '.') { ++ assert((*prefix)[i + 1] == '.'); ++ i++; ++ } ++ (*prefix)[j] = (*prefix)[i]; ++ } ++ (*prefix)[j] = '\0'; ++} ++ ++/** ++ * qdict_is_list: ++ * @maybe_list: dict to check if keys represent list elements. ++ * ++ * Determine whether all keys in @maybe_list are valid list elements. ++ * If @maybe_list is non-zero in length and all the keys look like ++ * valid list indexes, this will return 1. If @maybe_list is zero ++ * length or all keys are non-numeric then it will return 0 to indicate ++ * it is a normal qdict. If there is a mix of numeric and non-numeric ++ * keys, or the list indexes are non-contiguous, an error is reported. ++ * ++ * Returns: 1 if a valid list, 0 if a dict, -1 on error ++ */ ++static int qdict_is_list(QDict *maybe_list, Error **errp) ++{ ++ const QDictEntry *ent; ++ ssize_t len = 0; ++ ssize_t max = -1; ++ int is_list = -1; ++ int64_t val; ++ ++ for (ent = qdict_first(maybe_list); ent != NULL; ++ ent = qdict_next(maybe_list, ent)) { ++ ++ if (qemu_strtoi64(ent->key, NULL, 10, &val) == 0) { ++ if (is_list == -1) { ++ is_list = 1; ++ } else if (!is_list) { ++ error_setg(errp, ++ "Cannot mix list and non-list keys"); ++ return -1; ++ } ++ len++; ++ if (val > max) { ++ max = val; ++ } ++ } else { ++ if (is_list == -1) { ++ is_list = 0; ++ } else if (is_list) { ++ error_setg(errp, ++ "Cannot mix list and non-list keys"); ++ return -1; ++ } ++ } ++ } ++ ++ if (is_list == -1) { ++ assert(!qdict_size(maybe_list)); ++ is_list = 0; ++ } ++ ++ /* NB this isn't a perfect check - e.g. it won't catch ++ * a list containing '1', '+1', '01', '3', but that ++ * does not matter - we've still proved that the ++ * input is a list. It is up the caller to do a ++ * stricter check if desired */ ++ if (len != (max + 1)) { ++ error_setg(errp, "List indices are not contiguous, " ++ "saw %zd elements but %zd largest index", ++ len, max); ++ return -1; ++ } ++ ++ return is_list; ++} ++ ++/** ++ * qdict_crumple: ++ * @src: the original flat dictionary (only scalar values) to crumple ++ * ++ * Takes a flat dictionary whose keys use '.' separator to indicate ++ * nesting, and values are scalars, and crumples it into a nested ++ * structure. ++ * ++ * To include a literal '.' in a key name, it must be escaped as '..' ++ * ++ * For example, an input of: ++ * ++ * { 'foo.0.bar': 'one', 'foo.0.wizz': '1', ++ * 'foo.1.bar': 'two', 'foo.1.wizz': '2' } ++ * ++ * will result in an output of: ++ * ++ * { ++ * 'foo': [ ++ * { 'bar': 'one', 'wizz': '1' }, ++ * { 'bar': 'two', 'wizz': '2' } ++ * ], ++ * } ++ * ++ * The following scenarios in the input dict will result in an ++ * error being returned: ++ * ++ * - Any values in @src are non-scalar types ++ * - If keys in @src imply that a particular level is both a ++ * list and a dict. e.g., "foo.0.bar" and "foo.eek.bar". ++ * - If keys in @src imply that a particular level is a list, ++ * but the indices are non-contiguous. e.g. "foo.0.bar" and ++ * "foo.2.bar" without any "foo.1.bar" present. ++ * - If keys in @src represent list indexes, but are not in ++ * the "%zu" format. e.g. "foo.+0.bar" ++ * ++ * Returns: either a QDict or QList for the nested data structure, or NULL ++ * on error ++ */ ++QObject *qdict_crumple(const QDict *src, Error **errp) ++{ ++ const QDictEntry *ent; ++ QDict *two_level, *multi_level = NULL; ++ QObject *dst = NULL, *child; ++ size_t i; ++ char *prefix = NULL; ++ const char *suffix = NULL; ++ int is_list; ++ ++ two_level = qdict_new(); ++ ++ /* Step 1: split our totally flat dict into a two level dict */ ++ for (ent = qdict_first(src); ent != NULL; ent = qdict_next(src, ent)) { ++ if (qobject_type(ent->value) == QTYPE_QDICT || ++ qobject_type(ent->value) == QTYPE_QLIST) { ++ error_setg(errp, "Value %s is not a scalar", ++ ent->key); ++ goto error; ++ } ++ ++ qdict_split_flat_key(ent->key, &prefix, &suffix); ++ ++ child = qdict_get(two_level, prefix); ++ if (suffix) { ++ QDict *child_dict = qobject_to(QDict, child); ++ if (!child_dict) { ++ if (child) { ++ error_setg(errp, "Key %s prefix is already set as a scalar", ++ prefix); ++ goto error; ++ } ++ ++ child_dict = qdict_new(); ++ qdict_put_obj(two_level, prefix, QOBJECT(child_dict)); ++ } ++ ++ qdict_put_obj(child_dict, suffix, qobject_ref(ent->value)); ++ } else { ++ if (child) { ++ error_setg(errp, "Key %s prefix is already set as a dict", ++ prefix); ++ goto error; ++ } ++ qdict_put_obj(two_level, prefix, qobject_ref(ent->value)); ++ } ++ ++ g_free(prefix); ++ prefix = NULL; ++ } ++ ++ /* Step 2: optionally process the two level dict recursively ++ * into a multi-level dict */ ++ multi_level = qdict_new(); ++ for (ent = qdict_first(two_level); ent != NULL; ++ ent = qdict_next(two_level, ent)) { ++ QDict *dict = qobject_to(QDict, ent->value); ++ if (dict) { ++ child = qdict_crumple(dict, errp); ++ if (!child) { ++ goto error; ++ } ++ ++ qdict_put_obj(multi_level, ent->key, child); ++ } else { ++ qdict_put_obj(multi_level, ent->key, qobject_ref(ent->value)); ++ } ++ } ++ qobject_unref(two_level); ++ two_level = NULL; ++ ++ /* Step 3: detect if we need to turn our dict into list */ ++ is_list = qdict_is_list(multi_level, errp); ++ if (is_list < 0) { ++ goto error; ++ } ++ ++ if (is_list) { ++ dst = QOBJECT(qlist_new()); ++ ++ for (i = 0; i < qdict_size(multi_level); i++) { ++ char *key = g_strdup_printf("%zu", i); ++ ++ child = qdict_get(multi_level, key); ++ g_free(key); ++ ++ if (!child) { ++ error_setg(errp, "Missing list index %zu", i); ++ goto error; ++ } ++ ++ qlist_append_obj(qobject_to(QList, dst), qobject_ref(child)); ++ } ++ qobject_unref(multi_level); ++ multi_level = NULL; ++ } else { ++ dst = QOBJECT(multi_level); ++ } ++ ++ return dst; ++ ++ error: ++ g_free(prefix); ++ qobject_unref(multi_level); ++ qobject_unref(two_level); ++ qobject_unref(dst); ++ return NULL; ++} ++ ++/** ++ * qdict_array_entries(): Returns the number of direct array entries if the ++ * sub-QDict of src specified by the prefix in subqdict (or src itself for ++ * prefix == "") is valid as an array, i.e. the length of the created list if ++ * the sub-QDict would become empty after calling qdict_array_split() on it. If ++ * the array is not valid, -EINVAL is returned. ++ */ ++int qdict_array_entries(QDict *src, const char *subqdict) ++{ ++ const QDictEntry *entry; ++ unsigned i; ++ unsigned entries = 0; ++ size_t subqdict_len = strlen(subqdict); ++ ++ assert(!subqdict_len || subqdict[subqdict_len - 1] == '.'); ++ ++ /* qdict_array_split() loops until UINT_MAX, but as we want to return ++ * negative errors, we only have a signed return value here. Any additional ++ * entries will lead to -EINVAL. */ ++ for (i = 0; i < INT_MAX; i++) { ++ QObject *subqobj; ++ int subqdict_entries; ++ char *prefix = g_strdup_printf("%s%u.", subqdict, i); ++ ++ subqdict_entries = qdict_count_prefixed_entries(src, prefix); ++ ++ /* Remove ending "." */ ++ prefix[strlen(prefix) - 1] = 0; ++ subqobj = qdict_get(src, prefix); ++ ++ g_free(prefix); ++ ++ if (subqdict_entries < 0) { ++ return subqdict_entries; ++ } ++ ++ /* There may be either a single subordinate object (named "%u") or ++ * multiple objects (each with a key prefixed "%u."), but not both. */ ++ if (subqobj && subqdict_entries) { ++ return -EINVAL; ++ } else if (!subqobj && !subqdict_entries) { ++ break; ++ } ++ ++ entries += subqdict_entries ? subqdict_entries : 1; ++ } ++ ++ /* Consider everything handled that isn't part of the given sub-QDict */ ++ for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) { ++ if (!strstart(qdict_entry_key(entry), subqdict, NULL)) { ++ entries++; ++ } ++ } ++ ++ /* Anything left in the sub-QDict that wasn't handled? */ ++ if (qdict_size(src) != entries) { ++ return -EINVAL; ++ } ++ ++ return i; ++} ++ ++/** ++ * qdict_join(): Absorb the src QDict into the dest QDict, that is, move all ++ * elements from src to dest. ++ * ++ * If an element from src has a key already present in dest, it will not be ++ * moved unless overwrite is true. ++ * ++ * If overwrite is true, the conflicting values in dest will be discarded and ++ * replaced by the corresponding values from src. ++ * ++ * Therefore, with overwrite being true, the src QDict will always be empty when ++ * this function returns. If overwrite is false, the src QDict will be empty ++ * iff there were no conflicts. ++ */ ++void qdict_join(QDict *dest, QDict *src, bool overwrite) ++{ ++ const QDictEntry *entry, *next; ++ ++ entry = qdict_first(src); ++ while (entry) { ++ next = qdict_next(src, entry); ++ ++ if (overwrite || !qdict_haskey(dest, entry->key)) { ++ qdict_put_obj(dest, entry->key, qobject_ref(entry->value)); ++ qdict_del(src, entry->key); ++ } ++ ++ entry = next; ++ } ++} ++ ++/** ++ * qdict_rename_keys(): Rename keys in qdict according to the replacements ++ * specified in the array renames. The array must be terminated by an entry ++ * with from = NULL. ++ * ++ * The renames are performed individually in the order of the array, so entries ++ * may be renamed multiple times and may or may not conflict depending on the ++ * order of the renames array. ++ * ++ * Returns true for success, false in error cases. ++ */ ++bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp) ++{ ++ QObject *qobj; ++ ++ while (renames->from) { ++ if (qdict_haskey(qdict, renames->from)) { ++ if (qdict_haskey(qdict, renames->to)) { ++ error_setg(errp, "'%s' and its alias '%s' can't be used at the " ++ "same time", renames->to, renames->from); ++ return false; ++ } ++ ++ qobj = qdict_get(qdict, renames->from); ++ qdict_put_obj(qdict, renames->to, qobject_ref(qobj)); ++ qdict_del(qdict, renames->from); ++ } ++ ++ renames++; ++ } ++ return true; ++} +diff --git a/qobject/qdict.c b/qobject/qdict.c +index 0554c64..3d8c2f7 100644 +--- a/qobject/qdict.c ++++ b/qobject/qdict.c +@@ -11,17 +11,11 @@ + */ + + #include "qemu/osdep.h" +-#include "block/qdict.h" + #include "qapi/qmp/qnum.h" + #include "qapi/qmp/qdict.h" + #include "qapi/qmp/qbool.h" +-#include "qapi/qmp/qlist.h" + #include "qapi/qmp/qnull.h" + #include "qapi/qmp/qstring.h" +-#include "qapi/error.h" +-#include "qemu/queue.h" +-#include "qemu-common.h" +-#include "qemu/cutils.h" + + /** + * qdict_new(): Create a new QDict +@@ -464,626 +458,3 @@ void qdict_destroy_obj(QObject *obj) + + g_free(qdict); + } +- +-/** +- * qdict_copy_default(): If no entry mapped by 'key' exists in 'dst' yet, the +- * value of 'key' in 'src' is copied there (and the refcount increased +- * accordingly). +- */ +-void qdict_copy_default(QDict *dst, QDict *src, const char *key) +-{ +- QObject *val; +- +- if (qdict_haskey(dst, key)) { +- return; +- } +- +- val = qdict_get(src, key); +- if (val) { +- qdict_put_obj(dst, key, qobject_ref(val)); +- } +-} +- +-/** +- * qdict_set_default_str(): If no entry mapped by 'key' exists in 'dst' yet, a +- * new QString initialised by 'val' is put there. +- */ +-void qdict_set_default_str(QDict *dst, const char *key, const char *val) +-{ +- if (qdict_haskey(dst, key)) { +- return; +- } +- +- qdict_put_str(dst, key, val); +-} +- +-static void qdict_flatten_qdict(QDict *qdict, QDict *target, +- const char *prefix); +- +-static void qdict_flatten_qlist(QList *qlist, QDict *target, const char *prefix) +-{ +- QObject *value; +- const QListEntry *entry; +- char *new_key; +- int i; +- +- /* This function is never called with prefix == NULL, i.e., it is always +- * called from within qdict_flatten_q(list|dict)(). Therefore, it does not +- * need to remove list entries during the iteration (the whole list will be +- * deleted eventually anyway from qdict_flatten_qdict()). */ +- assert(prefix); +- +- entry = qlist_first(qlist); +- +- for (i = 0; entry; entry = qlist_next(entry), i++) { +- value = qlist_entry_obj(entry); +- new_key = g_strdup_printf("%s.%i", prefix, i); +- +- if (qobject_type(value) == QTYPE_QDICT) { +- qdict_flatten_qdict(qobject_to(QDict, value), target, new_key); +- } else if (qobject_type(value) == QTYPE_QLIST) { +- qdict_flatten_qlist(qobject_to(QList, value), target, new_key); +- } else { +- /* All other types are moved to the target unchanged. */ +- qdict_put_obj(target, new_key, qobject_ref(value)); +- } +- +- g_free(new_key); +- } +-} +- +-static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix) +-{ +- QObject *value; +- const QDictEntry *entry, *next; +- char *new_key; +- bool delete; +- +- entry = qdict_first(qdict); +- +- while (entry != NULL) { +- +- next = qdict_next(qdict, entry); +- value = qdict_entry_value(entry); +- new_key = NULL; +- delete = false; +- +- if (prefix) { +- new_key = g_strdup_printf("%s.%s", prefix, entry->key); +- } +- +- if (qobject_type(value) == QTYPE_QDICT) { +- /* Entries of QDicts are processed recursively, the QDict object +- * itself disappears. */ +- qdict_flatten_qdict(qobject_to(QDict, value), target, +- new_key ? new_key : entry->key); +- delete = true; +- } else if (qobject_type(value) == QTYPE_QLIST) { +- qdict_flatten_qlist(qobject_to(QList, value), target, +- new_key ? new_key : entry->key); +- delete = true; +- } else if (prefix) { +- /* All other objects are moved to the target unchanged. */ +- qdict_put_obj(target, new_key, qobject_ref(value)); +- delete = true; +- } +- +- g_free(new_key); +- +- if (delete) { +- qdict_del(qdict, entry->key); +- +- /* Restart loop after modifying the iterated QDict */ +- entry = qdict_first(qdict); +- continue; +- } +- +- entry = next; +- } +-} +- +-/** +- * qdict_flatten(): For each nested QDict with key x, all fields with key y +- * are moved to this QDict and their key is renamed to "x.y". For each nested +- * QList with key x, the field at index y is moved to this QDict with the key +- * "x.y" (i.e., the reverse of what qdict_array_split() does). +- * This operation is applied recursively for nested QDicts and QLists. +- */ +-void qdict_flatten(QDict *qdict) +-{ +- qdict_flatten_qdict(qdict, qdict, NULL); +-} +- +-/* extract all the src QDict entries starting by start into dst */ +-void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start) +- +-{ +- const QDictEntry *entry, *next; +- const char *p; +- +- *dst = qdict_new(); +- entry = qdict_first(src); +- +- while (entry != NULL) { +- next = qdict_next(src, entry); +- if (strstart(entry->key, start, &p)) { +- qdict_put_obj(*dst, p, qobject_ref(entry->value)); +- qdict_del(src, entry->key); +- } +- entry = next; +- } +-} +- +-static int qdict_count_prefixed_entries(const QDict *src, const char *start) +-{ +- const QDictEntry *entry; +- int count = 0; +- +- for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) { +- if (strstart(entry->key, start, NULL)) { +- if (count == INT_MAX) { +- return -ERANGE; +- } +- count++; +- } +- } +- +- return count; +-} +- +-/** +- * qdict_array_split(): This function moves array-like elements of a QDict into +- * a new QList. Every entry in the original QDict with a key "%u" or one +- * prefixed "%u.", where %u designates an unsigned integer starting at 0 and +- * incrementally counting up, will be moved to a new QDict at index %u in the +- * output QList with the key prefix removed, if that prefix is "%u.". If the +- * whole key is just "%u", the whole QObject will be moved unchanged without +- * creating a new QDict. The function terminates when there is no entry in the +- * QDict with a prefix directly (incrementally) following the last one; it also +- * returns if there are both entries with "%u" and "%u." for the same index %u. +- * Example: {"0.a": 42, "0.b": 23, "1.x": 0, "4.y": 1, "o.o": 7, "2": 66} +- * (or {"1.x": 0, "4.y": 1, "0.a": 42, "o.o": 7, "0.b": 23, "2": 66}) +- * => [{"a": 42, "b": 23}, {"x": 0}, 66] +- * and {"4.y": 1, "o.o": 7} (remainder of the old QDict) +- */ +-void qdict_array_split(QDict *src, QList **dst) +-{ +- unsigned i; +- +- *dst = qlist_new(); +- +- for (i = 0; i < UINT_MAX; i++) { +- QObject *subqobj; +- bool is_subqdict; +- QDict *subqdict; +- char indexstr[32], prefix[32]; +- size_t snprintf_ret; +- +- snprintf_ret = snprintf(indexstr, 32, "%u", i); +- assert(snprintf_ret < 32); +- +- subqobj = qdict_get(src, indexstr); +- +- snprintf_ret = snprintf(prefix, 32, "%u.", i); +- assert(snprintf_ret < 32); +- +- /* Overflow is the same as positive non-zero results */ +- is_subqdict = qdict_count_prefixed_entries(src, prefix); +- +- // There may be either a single subordinate object (named "%u") or +- // multiple objects (each with a key prefixed "%u."), but not both. +- if (!subqobj == !is_subqdict) { +- break; +- } +- +- if (is_subqdict) { +- qdict_extract_subqdict(src, &subqdict, prefix); +- assert(qdict_size(subqdict) > 0); +- } else { +- qobject_ref(subqobj); +- qdict_del(src, indexstr); +- } +- +- qlist_append_obj(*dst, subqobj ?: QOBJECT(subqdict)); +- } +-} +- +-/** +- * qdict_split_flat_key: +- * @key: the key string to split +- * @prefix: non-NULL pointer to hold extracted prefix +- * @suffix: non-NULL pointer to remaining suffix +- * +- * Given a flattened key such as 'foo.0.bar', split it into two parts +- * at the first '.' separator. Allows double dot ('..') to escape the +- * normal separator. +- * +- * e.g. +- * 'foo.0.bar' -> prefix='foo' and suffix='0.bar' +- * 'foo..0.bar' -> prefix='foo.0' and suffix='bar' +- * +- * The '..' sequence will be unescaped in the returned 'prefix' +- * string. The 'suffix' string will be left in escaped format, so it +- * can be fed back into the qdict_split_flat_key() key as the input +- * later. +- * +- * The caller is responsible for freeing the string returned in @prefix +- * using g_free(). +- */ +-static void qdict_split_flat_key(const char *key, char **prefix, +- const char **suffix) +-{ +- const char *separator; +- size_t i, j; +- +- /* Find first '.' separator, but if there is a pair '..' +- * that acts as an escape, so skip over '..' */ +- separator = NULL; +- do { +- if (separator) { +- separator += 2; +- } else { +- separator = key; +- } +- separator = strchr(separator, '.'); +- } while (separator && separator[1] == '.'); +- +- if (separator) { +- *prefix = g_strndup(key, separator - key); +- *suffix = separator + 1; +- } else { +- *prefix = g_strdup(key); +- *suffix = NULL; +- } +- +- /* Unescape the '..' sequence into '.' */ +- for (i = 0, j = 0; (*prefix)[i] != '\0'; i++, j++) { +- if ((*prefix)[i] == '.') { +- assert((*prefix)[i + 1] == '.'); +- i++; +- } +- (*prefix)[j] = (*prefix)[i]; +- } +- (*prefix)[j] = '\0'; +-} +- +-/** +- * qdict_is_list: +- * @maybe_list: dict to check if keys represent list elements. +- * +- * Determine whether all keys in @maybe_list are valid list elements. +- * If @maybe_list is non-zero in length and all the keys look like +- * valid list indexes, this will return 1. If @maybe_list is zero +- * length or all keys are non-numeric then it will return 0 to indicate +- * it is a normal qdict. If there is a mix of numeric and non-numeric +- * keys, or the list indexes are non-contiguous, an error is reported. +- * +- * Returns: 1 if a valid list, 0 if a dict, -1 on error +- */ +-static int qdict_is_list(QDict *maybe_list, Error **errp) +-{ +- const QDictEntry *ent; +- ssize_t len = 0; +- ssize_t max = -1; +- int is_list = -1; +- int64_t val; +- +- for (ent = qdict_first(maybe_list); ent != NULL; +- ent = qdict_next(maybe_list, ent)) { +- +- if (qemu_strtoi64(ent->key, NULL, 10, &val) == 0) { +- if (is_list == -1) { +- is_list = 1; +- } else if (!is_list) { +- error_setg(errp, +- "Cannot mix list and non-list keys"); +- return -1; +- } +- len++; +- if (val > max) { +- max = val; +- } +- } else { +- if (is_list == -1) { +- is_list = 0; +- } else if (is_list) { +- error_setg(errp, +- "Cannot mix list and non-list keys"); +- return -1; +- } +- } +- } +- +- if (is_list == -1) { +- assert(!qdict_size(maybe_list)); +- is_list = 0; +- } +- +- /* NB this isn't a perfect check - e.g. it won't catch +- * a list containing '1', '+1', '01', '3', but that +- * does not matter - we've still proved that the +- * input is a list. It is up the caller to do a +- * stricter check if desired */ +- if (len != (max + 1)) { +- error_setg(errp, "List indices are not contiguous, " +- "saw %zd elements but %zd largest index", +- len, max); +- return -1; +- } +- +- return is_list; +-} +- +-/** +- * qdict_crumple: +- * @src: the original flat dictionary (only scalar values) to crumple +- * +- * Takes a flat dictionary whose keys use '.' separator to indicate +- * nesting, and values are scalars, and crumples it into a nested +- * structure. +- * +- * To include a literal '.' in a key name, it must be escaped as '..' +- * +- * For example, an input of: +- * +- * { 'foo.0.bar': 'one', 'foo.0.wizz': '1', +- * 'foo.1.bar': 'two', 'foo.1.wizz': '2' } +- * +- * will result in an output of: +- * +- * { +- * 'foo': [ +- * { 'bar': 'one', 'wizz': '1' }, +- * { 'bar': 'two', 'wizz': '2' } +- * ], +- * } +- * +- * The following scenarios in the input dict will result in an +- * error being returned: +- * +- * - Any values in @src are non-scalar types +- * - If keys in @src imply that a particular level is both a +- * list and a dict. e.g., "foo.0.bar" and "foo.eek.bar". +- * - If keys in @src imply that a particular level is a list, +- * but the indices are non-contiguous. e.g. "foo.0.bar" and +- * "foo.2.bar" without any "foo.1.bar" present. +- * - If keys in @src represent list indexes, but are not in +- * the "%zu" format. e.g. "foo.+0.bar" +- * +- * Returns: either a QDict or QList for the nested data structure, or NULL +- * on error +- */ +-QObject *qdict_crumple(const QDict *src, Error **errp) +-{ +- const QDictEntry *ent; +- QDict *two_level, *multi_level = NULL; +- QObject *dst = NULL, *child; +- size_t i; +- char *prefix = NULL; +- const char *suffix = NULL; +- int is_list; +- +- two_level = qdict_new(); +- +- /* Step 1: split our totally flat dict into a two level dict */ +- for (ent = qdict_first(src); ent != NULL; ent = qdict_next(src, ent)) { +- if (qobject_type(ent->value) == QTYPE_QDICT || +- qobject_type(ent->value) == QTYPE_QLIST) { +- error_setg(errp, "Value %s is not a scalar", +- ent->key); +- goto error; +- } +- +- qdict_split_flat_key(ent->key, &prefix, &suffix); +- +- child = qdict_get(two_level, prefix); +- if (suffix) { +- QDict *child_dict = qobject_to(QDict, child); +- if (!child_dict) { +- if (child) { +- error_setg(errp, "Key %s prefix is already set as a scalar", +- prefix); +- goto error; +- } +- +- child_dict = qdict_new(); +- qdict_put_obj(two_level, prefix, QOBJECT(child_dict)); +- } +- +- qdict_put_obj(child_dict, suffix, qobject_ref(ent->value)); +- } else { +- if (child) { +- error_setg(errp, "Key %s prefix is already set as a dict", +- prefix); +- goto error; +- } +- qdict_put_obj(two_level, prefix, qobject_ref(ent->value)); +- } +- +- g_free(prefix); +- prefix = NULL; +- } +- +- /* Step 2: optionally process the two level dict recursively +- * into a multi-level dict */ +- multi_level = qdict_new(); +- for (ent = qdict_first(two_level); ent != NULL; +- ent = qdict_next(two_level, ent)) { +- QDict *dict = qobject_to(QDict, ent->value); +- if (dict) { +- child = qdict_crumple(dict, errp); +- if (!child) { +- goto error; +- } +- +- qdict_put_obj(multi_level, ent->key, child); +- } else { +- qdict_put_obj(multi_level, ent->key, qobject_ref(ent->value)); +- } +- } +- qobject_unref(two_level); +- two_level = NULL; +- +- /* Step 3: detect if we need to turn our dict into list */ +- is_list = qdict_is_list(multi_level, errp); +- if (is_list < 0) { +- goto error; +- } +- +- if (is_list) { +- dst = QOBJECT(qlist_new()); +- +- for (i = 0; i < qdict_size(multi_level); i++) { +- char *key = g_strdup_printf("%zu", i); +- +- child = qdict_get(multi_level, key); +- g_free(key); +- +- if (!child) { +- error_setg(errp, "Missing list index %zu", i); +- goto error; +- } +- +- qlist_append_obj(qobject_to(QList, dst), qobject_ref(child)); +- } +- qobject_unref(multi_level); +- multi_level = NULL; +- } else { +- dst = QOBJECT(multi_level); +- } +- +- return dst; +- +- error: +- g_free(prefix); +- qobject_unref(multi_level); +- qobject_unref(two_level); +- qobject_unref(dst); +- return NULL; +-} +- +-/** +- * qdict_array_entries(): Returns the number of direct array entries if the +- * sub-QDict of src specified by the prefix in subqdict (or src itself for +- * prefix == "") is valid as an array, i.e. the length of the created list if +- * the sub-QDict would become empty after calling qdict_array_split() on it. If +- * the array is not valid, -EINVAL is returned. +- */ +-int qdict_array_entries(QDict *src, const char *subqdict) +-{ +- const QDictEntry *entry; +- unsigned i; +- unsigned entries = 0; +- size_t subqdict_len = strlen(subqdict); +- +- assert(!subqdict_len || subqdict[subqdict_len - 1] == '.'); +- +- /* qdict_array_split() loops until UINT_MAX, but as we want to return +- * negative errors, we only have a signed return value here. Any additional +- * entries will lead to -EINVAL. */ +- for (i = 0; i < INT_MAX; i++) { +- QObject *subqobj; +- int subqdict_entries; +- char *prefix = g_strdup_printf("%s%u.", subqdict, i); +- +- subqdict_entries = qdict_count_prefixed_entries(src, prefix); +- +- /* Remove ending "." */ +- prefix[strlen(prefix) - 1] = 0; +- subqobj = qdict_get(src, prefix); +- +- g_free(prefix); +- +- if (subqdict_entries < 0) { +- return subqdict_entries; +- } +- +- /* There may be either a single subordinate object (named "%u") or +- * multiple objects (each with a key prefixed "%u."), but not both. */ +- if (subqobj && subqdict_entries) { +- return -EINVAL; +- } else if (!subqobj && !subqdict_entries) { +- break; +- } +- +- entries += subqdict_entries ? subqdict_entries : 1; +- } +- +- /* Consider everything handled that isn't part of the given sub-QDict */ +- for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) { +- if (!strstart(qdict_entry_key(entry), subqdict, NULL)) { +- entries++; +- } +- } +- +- /* Anything left in the sub-QDict that wasn't handled? */ +- if (qdict_size(src) != entries) { +- return -EINVAL; +- } +- +- return i; +-} +- +-/** +- * qdict_join(): Absorb the src QDict into the dest QDict, that is, move all +- * elements from src to dest. +- * +- * If an element from src has a key already present in dest, it will not be +- * moved unless overwrite is true. +- * +- * If overwrite is true, the conflicting values in dest will be discarded and +- * replaced by the corresponding values from src. +- * +- * Therefore, with overwrite being true, the src QDict will always be empty when +- * this function returns. If overwrite is false, the src QDict will be empty +- * iff there were no conflicts. +- */ +-void qdict_join(QDict *dest, QDict *src, bool overwrite) +-{ +- const QDictEntry *entry, *next; +- +- entry = qdict_first(src); +- while (entry) { +- next = qdict_next(src, entry); +- +- if (overwrite || !qdict_haskey(dest, entry->key)) { +- qdict_put_obj(dest, entry->key, qobject_ref(entry->value)); +- qdict_del(src, entry->key); +- } +- +- entry = next; +- } +-} +- +-/** +- * qdict_rename_keys(): Rename keys in qdict according to the replacements +- * specified in the array renames. The array must be terminated by an entry +- * with from = NULL. +- * +- * The renames are performed individually in the order of the array, so entries +- * may be renamed multiple times and may or may not conflict depending on the +- * order of the renames array. +- * +- * Returns true for success, false in error cases. +- */ +-bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp) +-{ +- QObject *qobj; +- +- while (renames->from) { +- if (qdict_haskey(qdict, renames->from)) { +- if (qdict_haskey(qdict, renames->to)) { +- error_setg(errp, "'%s' and its alias '%s' can't be used at the " +- "same time", renames->to, renames->from); +- return false; +- } +- +- qobj = qdict_get(qdict, renames->from); +- qdict_put_obj(qdict, renames->to, qobject_ref(qobj)); +- qdict_del(qdict, renames->from); +- } +- +- renames++; +- } +- return true; +-} +diff --git a/tests/Makefile.include b/tests/Makefile.include +index 5cb1902..9dd63e5 100644 +--- a/tests/Makefile.include ++++ b/tests/Makefile.include +@@ -40,6 +40,8 @@ SYSEMU_TARGET_LIST := $(subst -softmmu.mak,,$(notdir \ + + check-unit-y = tests/check-qdict$(EXESUF) + gcov-files-check-qdict-y = qobject/qdict.c ++check-unit-y = tests/check-block-qdict$(EXESUF) ++gcov-files-check-block-qdict-y = qobject/block-qdict.c + check-unit-y += tests/test-char$(EXESUF) + gcov-files-check-qdict-y = chardev/char.c + check-unit-y += tests/check-qnum$(EXESUF) +@@ -559,6 +561,7 @@ GENERATED_FILES += tests/test-qapi-types.h tests/test-qapi-visit.h \ + test-obj-y = tests/check-qnum.o tests/check-qstring.o tests/check-qdict.o \ + tests/check-qlist.o tests/check-qnull.o tests/check-qobject.o \ + tests/check-qjson.o tests/check-qlit.o \ ++ tests/check-block-qtest.o \ + tests/test-coroutine.o tests/test-string-output-visitor.o \ + tests/test-string-input-visitor.o tests/test-qobject-output-visitor.o \ + tests/test-clone-visitor.o \ +@@ -589,6 +592,7 @@ test-block-obj-y = $(block-obj-y) $(test-io-obj-y) tests/iothread.o + tests/check-qnum$(EXESUF): tests/check-qnum.o $(test-util-obj-y) + tests/check-qstring$(EXESUF): tests/check-qstring.o $(test-util-obj-y) + tests/check-qdict$(EXESUF): tests/check-qdict.o $(test-util-obj-y) ++tests/check-block-qdict$(EXESUF): tests/check-block-qdict.o $(test-util-obj-y) + tests/check-qlist$(EXESUF): tests/check-qlist.o $(test-util-obj-y) + tests/check-qnull$(EXESUF): tests/check-qnull.o $(test-util-obj-y) + tests/check-qobject$(EXESUF): tests/check-qobject.o $(test-util-obj-y) +diff --git a/tests/check-block-qdict.c b/tests/check-block-qdict.c +new file mode 100644 +index 0000000..5b9f4d5 +--- /dev/null ++++ b/tests/check-block-qdict.c +@@ -0,0 +1,655 @@ ++/* ++ * Unit-tests for Block layer QDict extras ++ * ++ * Copyright (c) 2013-2018 Red Hat, Inc. ++ * ++ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. ++ * See the COPYING.LIB file in the top-level directory. ++ */ ++ ++#include "qemu/osdep.h" ++#include "block/qdict.h" ++#include "qapi/qmp/qlist.h" ++#include "qapi/qmp/qnum.h" ++#include "qapi/error.h" ++ ++static void qdict_defaults_test(void) ++{ ++ QDict *dict, *copy; ++ ++ dict = qdict_new(); ++ copy = qdict_new(); ++ ++ qdict_set_default_str(dict, "foo", "abc"); ++ qdict_set_default_str(dict, "foo", "def"); ++ g_assert_cmpstr(qdict_get_str(dict, "foo"), ==, "abc"); ++ qdict_set_default_str(dict, "bar", "ghi"); ++ ++ qdict_copy_default(copy, dict, "foo"); ++ g_assert_cmpstr(qdict_get_str(copy, "foo"), ==, "abc"); ++ qdict_set_default_str(copy, "bar", "xyz"); ++ qdict_copy_default(copy, dict, "bar"); ++ g_assert_cmpstr(qdict_get_str(copy, "bar"), ==, "xyz"); ++ ++ qobject_unref(copy); ++ qobject_unref(dict); ++} ++ ++static void qdict_flatten_test(void) ++{ ++ QList *list1 = qlist_new(); ++ QList *list2 = qlist_new(); ++ QDict *dict1 = qdict_new(); ++ QDict *dict2 = qdict_new(); ++ QDict *dict3 = qdict_new(); ++ ++ /* ++ * Test the flattening of ++ * ++ * { ++ * "e": [ ++ * 42, ++ * [ ++ * 23, ++ * 66, ++ * { ++ * "a": 0, ++ * "b": 1 ++ * } ++ * ] ++ * ], ++ * "f": { ++ * "c": 2, ++ * "d": 3, ++ * }, ++ * "g": 4 ++ * } ++ * ++ * to ++ * ++ * { ++ * "e.0": 42, ++ * "e.1.0": 23, ++ * "e.1.1": 66, ++ * "e.1.2.a": 0, ++ * "e.1.2.b": 1, ++ * "f.c": 2, ++ * "f.d": 3, ++ * "g": 4 ++ * } ++ */ ++ ++ qdict_put_int(dict1, "a", 0); ++ qdict_put_int(dict1, "b", 1); ++ ++ qlist_append_int(list1, 23); ++ qlist_append_int(list1, 66); ++ qlist_append(list1, dict1); ++ qlist_append_int(list2, 42); ++ qlist_append(list2, list1); ++ ++ qdict_put_int(dict2, "c", 2); ++ qdict_put_int(dict2, "d", 3); ++ qdict_put(dict3, "e", list2); ++ qdict_put(dict3, "f", dict2); ++ qdict_put_int(dict3, "g", 4); ++ ++ qdict_flatten(dict3); ++ ++ g_assert(qdict_get_int(dict3, "e.0") == 42); ++ g_assert(qdict_get_int(dict3, "e.1.0") == 23); ++ g_assert(qdict_get_int(dict3, "e.1.1") == 66); ++ g_assert(qdict_get_int(dict3, "e.1.2.a") == 0); ++ g_assert(qdict_get_int(dict3, "e.1.2.b") == 1); ++ g_assert(qdict_get_int(dict3, "f.c") == 2); ++ g_assert(qdict_get_int(dict3, "f.d") == 3); ++ g_assert(qdict_get_int(dict3, "g") == 4); ++ ++ g_assert(qdict_size(dict3) == 8); ++ ++ qobject_unref(dict3); ++} ++ ++static void qdict_array_split_test(void) ++{ ++ QDict *test_dict = qdict_new(); ++ QDict *dict1, *dict2; ++ QNum *int1; ++ QList *test_list; ++ ++ /* ++ * Test the split of ++ * ++ * { ++ * "1.x": 0, ++ * "4.y": 1, ++ * "0.a": 42, ++ * "o.o": 7, ++ * "0.b": 23, ++ * "2": 66 ++ * } ++ * ++ * to ++ * ++ * [ ++ * { ++ * "a": 42, ++ * "b": 23 ++ * }, ++ * { ++ * "x": 0 ++ * }, ++ * 66 ++ * ] ++ * ++ * and ++ * ++ * { ++ * "4.y": 1, ++ * "o.o": 7 ++ * } ++ * ++ * (remaining in the old QDict) ++ * ++ * This example is given in the comment of qdict_array_split(). ++ */ ++ ++ qdict_put_int(test_dict, "1.x", 0); ++ qdict_put_int(test_dict, "4.y", 1); ++ qdict_put_int(test_dict, "0.a", 42); ++ qdict_put_int(test_dict, "o.o", 7); ++ qdict_put_int(test_dict, "0.b", 23); ++ qdict_put_int(test_dict, "2", 66); ++ ++ qdict_array_split(test_dict, &test_list); ++ ++ dict1 = qobject_to(QDict, qlist_pop(test_list)); ++ dict2 = qobject_to(QDict, qlist_pop(test_list)); ++ int1 = qobject_to(QNum, qlist_pop(test_list)); ++ ++ g_assert(dict1); ++ g_assert(dict2); ++ g_assert(int1); ++ g_assert(qlist_empty(test_list)); ++ ++ qobject_unref(test_list); ++ ++ g_assert(qdict_get_int(dict1, "a") == 42); ++ g_assert(qdict_get_int(dict1, "b") == 23); ++ ++ g_assert(qdict_size(dict1) == 2); ++ ++ qobject_unref(dict1); ++ ++ g_assert(qdict_get_int(dict2, "x") == 0); ++ ++ g_assert(qdict_size(dict2) == 1); ++ ++ qobject_unref(dict2); ++ ++ g_assert_cmpint(qnum_get_int(int1), ==, 66); ++ ++ qobject_unref(int1); ++ ++ g_assert(qdict_get_int(test_dict, "4.y") == 1); ++ g_assert(qdict_get_int(test_dict, "o.o") == 7); ++ ++ g_assert(qdict_size(test_dict) == 2); ++ ++ qobject_unref(test_dict); ++ ++ /* ++ * Test the split of ++ * ++ * { ++ * "0": 42, ++ * "1": 23, ++ * "1.x": 84 ++ * } ++ * ++ * to ++ * ++ * [ ++ * 42 ++ * ] ++ * ++ * and ++ * ++ * { ++ * "1": 23, ++ * "1.x": 84 ++ * } ++ * ++ * That is, test whether splitting stops if there is both an entry with key ++ * of "%u" and other entries with keys prefixed "%u." for the same index. ++ */ ++ ++ test_dict = qdict_new(); ++ ++ qdict_put_int(test_dict, "0", 42); ++ qdict_put_int(test_dict, "1", 23); ++ qdict_put_int(test_dict, "1.x", 84); ++ ++ qdict_array_split(test_dict, &test_list); ++ ++ int1 = qobject_to(QNum, qlist_pop(test_list)); ++ ++ g_assert(int1); ++ g_assert(qlist_empty(test_list)); ++ ++ qobject_unref(test_list); ++ ++ g_assert_cmpint(qnum_get_int(int1), ==, 42); ++ ++ qobject_unref(int1); ++ ++ g_assert(qdict_get_int(test_dict, "1") == 23); ++ g_assert(qdict_get_int(test_dict, "1.x") == 84); ++ ++ g_assert(qdict_size(test_dict) == 2); ++ ++ qobject_unref(test_dict); ++} ++ ++static void qdict_array_entries_test(void) ++{ ++ QDict *dict = qdict_new(); ++ ++ g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 0); ++ ++ qdict_put_int(dict, "bar", 0); ++ qdict_put_int(dict, "baz.0", 0); ++ g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 0); ++ ++ qdict_put_int(dict, "foo.1", 0); ++ g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, -EINVAL); ++ qdict_put_int(dict, "foo.0", 0); ++ g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 2); ++ qdict_put_int(dict, "foo.bar", 0); ++ g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, -EINVAL); ++ qdict_del(dict, "foo.bar"); ++ ++ qdict_put_int(dict, "foo.2.a", 0); ++ qdict_put_int(dict, "foo.2.b", 0); ++ qdict_put_int(dict, "foo.2.c", 0); ++ g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 3); ++ g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL); ++ ++ qobject_unref(dict); ++ ++ dict = qdict_new(); ++ qdict_put_int(dict, "1", 0); ++ g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL); ++ qdict_put_int(dict, "0", 0); ++ g_assert_cmpint(qdict_array_entries(dict, ""), ==, 2); ++ qdict_put_int(dict, "bar", 0); ++ g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL); ++ qdict_del(dict, "bar"); ++ ++ qdict_put_int(dict, "2.a", 0); ++ qdict_put_int(dict, "2.b", 0); ++ qdict_put_int(dict, "2.c", 0); ++ g_assert_cmpint(qdict_array_entries(dict, ""), ==, 3); ++ ++ qobject_unref(dict); ++} ++ ++static void qdict_join_test(void) ++{ ++ QDict *dict1, *dict2; ++ bool overwrite = false; ++ int i; ++ ++ dict1 = qdict_new(); ++ dict2 = qdict_new(); ++ ++ /* Test everything once without overwrite and once with */ ++ do { ++ /* Test empty dicts */ ++ qdict_join(dict1, dict2, overwrite); ++ ++ g_assert(qdict_size(dict1) == 0); ++ g_assert(qdict_size(dict2) == 0); ++ ++ /* First iteration: Test movement */ ++ /* Second iteration: Test empty source and non-empty destination */ ++ qdict_put_int(dict2, "foo", 42); ++ ++ for (i = 0; i < 2; i++) { ++ qdict_join(dict1, dict2, overwrite); ++ ++ g_assert(qdict_size(dict1) == 1); ++ g_assert(qdict_size(dict2) == 0); ++ ++ g_assert(qdict_get_int(dict1, "foo") == 42); ++ } ++ ++ /* Test non-empty source and destination without conflict */ ++ qdict_put_int(dict2, "bar", 23); ++ ++ qdict_join(dict1, dict2, overwrite); ++ ++ g_assert(qdict_size(dict1) == 2); ++ g_assert(qdict_size(dict2) == 0); ++ ++ g_assert(qdict_get_int(dict1, "foo") == 42); ++ g_assert(qdict_get_int(dict1, "bar") == 23); ++ ++ /* Test conflict */ ++ qdict_put_int(dict2, "foo", 84); ++ ++ qdict_join(dict1, dict2, overwrite); ++ ++ g_assert(qdict_size(dict1) == 2); ++ g_assert(qdict_size(dict2) == !overwrite); ++ ++ g_assert(qdict_get_int(dict1, "foo") == (overwrite ? 84 : 42)); ++ g_assert(qdict_get_int(dict1, "bar") == 23); ++ ++ if (!overwrite) { ++ g_assert(qdict_get_int(dict2, "foo") == 84); ++ } ++ ++ /* Check the references */ ++ g_assert(qdict_get(dict1, "foo")->base.refcnt == 1); ++ g_assert(qdict_get(dict1, "bar")->base.refcnt == 1); ++ ++ if (!overwrite) { ++ g_assert(qdict_get(dict2, "foo")->base.refcnt == 1); ++ } ++ ++ /* Clean up */ ++ qdict_del(dict1, "foo"); ++ qdict_del(dict1, "bar"); ++ ++ if (!overwrite) { ++ qdict_del(dict2, "foo"); ++ } ++ } while (overwrite ^= true); ++ ++ qobject_unref(dict1); ++ qobject_unref(dict2); ++} ++ ++static void qdict_crumple_test_recursive(void) ++{ ++ QDict *src, *dst, *rule, *vnc, *acl, *listen; ++ QList *rules; ++ ++ src = qdict_new(); ++ qdict_put_str(src, "vnc.listen.addr", "127.0.0.1"); ++ qdict_put_str(src, "vnc.listen.port", "5901"); ++ qdict_put_str(src, "vnc.acl.rules.0.match", "fred"); ++ qdict_put_str(src, "vnc.acl.rules.0.policy", "allow"); ++ qdict_put_str(src, "vnc.acl.rules.1.match", "bob"); ++ qdict_put_str(src, "vnc.acl.rules.1.policy", "deny"); ++ qdict_put_str(src, "vnc.acl.default", "deny"); ++ qdict_put_str(src, "vnc.acl..name", "acl0"); ++ qdict_put_str(src, "vnc.acl.rule..name", "acl0"); ++ ++ dst = qobject_to(QDict, qdict_crumple(src, &error_abort)); ++ g_assert(dst); ++ g_assert_cmpint(qdict_size(dst), ==, 1); ++ ++ vnc = qdict_get_qdict(dst, "vnc"); ++ g_assert(vnc); ++ g_assert_cmpint(qdict_size(vnc), ==, 3); ++ ++ listen = qdict_get_qdict(vnc, "listen"); ++ g_assert(listen); ++ g_assert_cmpint(qdict_size(listen), ==, 2); ++ g_assert_cmpstr("127.0.0.1", ==, qdict_get_str(listen, "addr")); ++ g_assert_cmpstr("5901", ==, qdict_get_str(listen, "port")); ++ ++ acl = qdict_get_qdict(vnc, "acl"); ++ g_assert(acl); ++ g_assert_cmpint(qdict_size(acl), ==, 3); ++ ++ rules = qdict_get_qlist(acl, "rules"); ++ g_assert(rules); ++ g_assert_cmpint(qlist_size(rules), ==, 2); ++ ++ rule = qobject_to(QDict, qlist_pop(rules)); ++ g_assert(rule); ++ g_assert_cmpint(qdict_size(rule), ==, 2); ++ g_assert_cmpstr("fred", ==, qdict_get_str(rule, "match")); ++ g_assert_cmpstr("allow", ==, qdict_get_str(rule, "policy")); ++ qobject_unref(rule); ++ ++ rule = qobject_to(QDict, qlist_pop(rules)); ++ g_assert(rule); ++ g_assert_cmpint(qdict_size(rule), ==, 2); ++ g_assert_cmpstr("bob", ==, qdict_get_str(rule, "match")); ++ g_assert_cmpstr("deny", ==, qdict_get_str(rule, "policy")); ++ qobject_unref(rule); ++ ++ /* With recursive crumpling, we should see all names unescaped */ ++ g_assert_cmpstr("acl0", ==, qdict_get_str(vnc, "acl.name")); ++ g_assert_cmpstr("acl0", ==, qdict_get_str(acl, "rule.name")); ++ ++ qobject_unref(src); ++ qobject_unref(dst); ++} ++ ++static void qdict_crumple_test_empty(void) ++{ ++ QDict *src, *dst; ++ ++ src = qdict_new(); ++ ++ dst = qobject_to(QDict, qdict_crumple(src, &error_abort)); ++ ++ g_assert_cmpint(qdict_size(dst), ==, 0); ++ ++ qobject_unref(src); ++ qobject_unref(dst); ++} ++ ++static int qdict_count_entries(QDict *dict) ++{ ++ const QDictEntry *e; ++ int count = 0; ++ ++ for (e = qdict_first(dict); e; e = qdict_next(dict, e)) { ++ count++; ++ } ++ ++ return count; ++} ++ ++static void qdict_rename_keys_test(void) ++{ ++ QDict *dict = qdict_new(); ++ QDict *copy; ++ QDictRenames *renames; ++ Error *local_err = NULL; ++ ++ qdict_put_str(dict, "abc", "foo"); ++ qdict_put_str(dict, "abcdef", "bar"); ++ qdict_put_int(dict, "number", 42); ++ qdict_put_bool(dict, "flag", true); ++ qdict_put_null(dict, "nothing"); ++ ++ /* Empty rename list */ ++ renames = (QDictRenames[]) { ++ { NULL, "this can be anything" } ++ }; ++ copy = qdict_clone_shallow(dict); ++ qdict_rename_keys(copy, renames, &error_abort); ++ ++ g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "foo"); ++ g_assert_cmpstr(qdict_get_str(copy, "abcdef"), ==, "bar"); ++ g_assert_cmpint(qdict_get_int(copy, "number"), ==, 42); ++ g_assert_cmpint(qdict_get_bool(copy, "flag"), ==, true); ++ g_assert(qobject_type(qdict_get(copy, "nothing")) == QTYPE_QNULL); ++ g_assert_cmpint(qdict_count_entries(copy), ==, 5); ++ ++ qobject_unref(copy); ++ ++ /* Simple rename of all entries */ ++ renames = (QDictRenames[]) { ++ { "abc", "str1" }, ++ { "abcdef", "str2" }, ++ { "number", "int" }, ++ { "flag", "bool" }, ++ { "nothing", "null" }, ++ { NULL , NULL } ++ }; ++ copy = qdict_clone_shallow(dict); ++ qdict_rename_keys(copy, renames, &error_abort); ++ ++ g_assert(!qdict_haskey(copy, "abc")); ++ g_assert(!qdict_haskey(copy, "abcdef")); ++ g_assert(!qdict_haskey(copy, "number")); ++ g_assert(!qdict_haskey(copy, "flag")); ++ g_assert(!qdict_haskey(copy, "nothing")); ++ ++ g_assert_cmpstr(qdict_get_str(copy, "str1"), ==, "foo"); ++ g_assert_cmpstr(qdict_get_str(copy, "str2"), ==, "bar"); ++ g_assert_cmpint(qdict_get_int(copy, "int"), ==, 42); ++ g_assert_cmpint(qdict_get_bool(copy, "bool"), ==, true); ++ g_assert(qobject_type(qdict_get(copy, "null")) == QTYPE_QNULL); ++ g_assert_cmpint(qdict_count_entries(copy), ==, 5); ++ ++ qobject_unref(copy); ++ ++ /* Renames are processed top to bottom */ ++ renames = (QDictRenames[]) { ++ { "abc", "tmp" }, ++ { "abcdef", "abc" }, ++ { "number", "abcdef" }, ++ { "flag", "number" }, ++ { "nothing", "flag" }, ++ { "tmp", "nothing" }, ++ { NULL , NULL } ++ }; ++ copy = qdict_clone_shallow(dict); ++ qdict_rename_keys(copy, renames, &error_abort); ++ ++ g_assert_cmpstr(qdict_get_str(copy, "nothing"), ==, "foo"); ++ g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "bar"); ++ g_assert_cmpint(qdict_get_int(copy, "abcdef"), ==, 42); ++ g_assert_cmpint(qdict_get_bool(copy, "number"), ==, true); ++ g_assert(qobject_type(qdict_get(copy, "flag")) == QTYPE_QNULL); ++ g_assert(!qdict_haskey(copy, "tmp")); ++ g_assert_cmpint(qdict_count_entries(copy), ==, 5); ++ ++ qobject_unref(copy); ++ ++ /* Conflicting rename */ ++ renames = (QDictRenames[]) { ++ { "abcdef", "abc" }, ++ { NULL , NULL } ++ }; ++ copy = qdict_clone_shallow(dict); ++ qdict_rename_keys(copy, renames, &local_err); ++ ++ g_assert(local_err != NULL); ++ error_free(local_err); ++ local_err = NULL; ++ ++ g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "foo"); ++ g_assert_cmpstr(qdict_get_str(copy, "abcdef"), ==, "bar"); ++ g_assert_cmpint(qdict_get_int(copy, "number"), ==, 42); ++ g_assert_cmpint(qdict_get_bool(copy, "flag"), ==, true); ++ g_assert(qobject_type(qdict_get(copy, "nothing")) == QTYPE_QNULL); ++ g_assert_cmpint(qdict_count_entries(copy), ==, 5); ++ ++ qobject_unref(copy); ++ ++ /* Renames in an empty dict */ ++ renames = (QDictRenames[]) { ++ { "abcdef", "abc" }, ++ { NULL , NULL } ++ }; ++ ++ qobject_unref(dict); ++ dict = qdict_new(); ++ ++ qdict_rename_keys(dict, renames, &error_abort); ++ g_assert(qdict_first(dict) == NULL); ++ ++ qobject_unref(dict); ++} ++ ++static void qdict_crumple_test_bad_inputs(void) ++{ ++ QDict *src; ++ Error *error = NULL; ++ ++ src = qdict_new(); ++ /* rule.0 can't be both a string and a dict */ ++ qdict_put_str(src, "rule.0", "fred"); ++ qdict_put_str(src, "rule.0.policy", "allow"); ++ ++ g_assert(qdict_crumple(src, &error) == NULL); ++ g_assert(error != NULL); ++ error_free(error); ++ error = NULL; ++ qobject_unref(src); ++ ++ src = qdict_new(); ++ /* rule can't be both a list and a dict */ ++ qdict_put_str(src, "rule.0", "fred"); ++ qdict_put_str(src, "rule.a", "allow"); ++ ++ g_assert(qdict_crumple(src, &error) == NULL); ++ g_assert(error != NULL); ++ error_free(error); ++ error = NULL; ++ qobject_unref(src); ++ ++ src = qdict_new(); ++ /* The input should be flat, ie no dicts or lists */ ++ qdict_put(src, "rule.a", qdict_new()); ++ qdict_put_str(src, "rule.b", "allow"); ++ ++ g_assert(qdict_crumple(src, &error) == NULL); ++ g_assert(error != NULL); ++ error_free(error); ++ error = NULL; ++ qobject_unref(src); ++ ++ src = qdict_new(); ++ /* List indexes must not have gaps */ ++ qdict_put_str(src, "rule.0", "deny"); ++ qdict_put_str(src, "rule.3", "allow"); ++ ++ g_assert(qdict_crumple(src, &error) == NULL); ++ g_assert(error != NULL); ++ error_free(error); ++ error = NULL; ++ qobject_unref(src); ++ ++ src = qdict_new(); ++ /* List indexes must be in %zu format */ ++ qdict_put_str(src, "rule.0", "deny"); ++ qdict_put_str(src, "rule.+1", "allow"); ++ ++ g_assert(qdict_crumple(src, &error) == NULL); ++ g_assert(error != NULL); ++ error_free(error); ++ error = NULL; ++ qobject_unref(src); ++} ++ ++int main(int argc, char **argv) ++{ ++ g_test_init(&argc, &argv, NULL); ++ ++ g_test_add_func("/public/defaults", qdict_defaults_test); ++ g_test_add_func("/public/flatten", qdict_flatten_test); ++ g_test_add_func("/public/array_split", qdict_array_split_test); ++ g_test_add_func("/public/array_entries", qdict_array_entries_test); ++ g_test_add_func("/public/join", qdict_join_test); ++ g_test_add_func("/public/crumple/recursive", ++ qdict_crumple_test_recursive); ++ g_test_add_func("/public/crumple/empty", ++ qdict_crumple_test_empty); ++ g_test_add_func("/public/crumple/bad_inputs", ++ qdict_crumple_test_bad_inputs); ++ ++ g_test_add_func("/public/rename_keys", qdict_rename_keys_test); ++ ++ return g_test_run(); ++} +diff --git a/tests/check-qdict.c b/tests/check-qdict.c +index 93e2112..86e9fe7 100644 +--- a/tests/check-qdict.c ++++ b/tests/check-qdict.c +@@ -11,13 +11,7 @@ + */ + + #include "qemu/osdep.h" +-#include "block/qdict.h" + #include "qapi/qmp/qdict.h" +-#include "qapi/qmp/qlist.h" +-#include "qapi/qmp/qnum.h" +-#include "qapi/qmp/qstring.h" +-#include "qapi/error.h" +-#include "qemu-common.h" + + /* + * Public Interface test-cases +@@ -157,28 +151,6 @@ static void qdict_get_try_str_test(void) + qobject_unref(tests_dict); + } + +-static void qdict_defaults_test(void) +-{ +- QDict *dict, *copy; +- +- dict = qdict_new(); +- copy = qdict_new(); +- +- qdict_set_default_str(dict, "foo", "abc"); +- qdict_set_default_str(dict, "foo", "def"); +- g_assert_cmpstr(qdict_get_str(dict, "foo"), ==, "abc"); +- qdict_set_default_str(dict, "bar", "ghi"); +- +- qdict_copy_default(copy, dict, "foo"); +- g_assert_cmpstr(qdict_get_str(copy, "foo"), ==, "abc"); +- qdict_set_default_str(copy, "bar", "xyz"); +- qdict_copy_default(copy, dict, "bar"); +- g_assert_cmpstr(qdict_get_str(copy, "bar"), ==, "xyz"); +- +- qobject_unref(copy); +- qobject_unref(dict); +-} +- + static void qdict_haskey_not_test(void) + { + QDict *tests_dict = qdict_new(); +@@ -254,606 +226,6 @@ static void qdict_iterapi_test(void) + qobject_unref(tests_dict); + } + +-static void qdict_flatten_test(void) +-{ +- QList *list1 = qlist_new(); +- QList *list2 = qlist_new(); +- QDict *dict1 = qdict_new(); +- QDict *dict2 = qdict_new(); +- QDict *dict3 = qdict_new(); +- +- /* +- * Test the flattening of +- * +- * { +- * "e": [ +- * 42, +- * [ +- * 23, +- * 66, +- * { +- * "a": 0, +- * "b": 1 +- * } +- * ] +- * ], +- * "f": { +- * "c": 2, +- * "d": 3, +- * }, +- * "g": 4 +- * } +- * +- * to +- * +- * { +- * "e.0": 42, +- * "e.1.0": 23, +- * "e.1.1": 66, +- * "e.1.2.a": 0, +- * "e.1.2.b": 1, +- * "f.c": 2, +- * "f.d": 3, +- * "g": 4 +- * } +- */ +- +- qdict_put_int(dict1, "a", 0); +- qdict_put_int(dict1, "b", 1); +- +- qlist_append_int(list1, 23); +- qlist_append_int(list1, 66); +- qlist_append(list1, dict1); +- qlist_append_int(list2, 42); +- qlist_append(list2, list1); +- +- qdict_put_int(dict2, "c", 2); +- qdict_put_int(dict2, "d", 3); +- qdict_put(dict3, "e", list2); +- qdict_put(dict3, "f", dict2); +- qdict_put_int(dict3, "g", 4); +- +- qdict_flatten(dict3); +- +- g_assert(qdict_get_int(dict3, "e.0") == 42); +- g_assert(qdict_get_int(dict3, "e.1.0") == 23); +- g_assert(qdict_get_int(dict3, "e.1.1") == 66); +- g_assert(qdict_get_int(dict3, "e.1.2.a") == 0); +- g_assert(qdict_get_int(dict3, "e.1.2.b") == 1); +- g_assert(qdict_get_int(dict3, "f.c") == 2); +- g_assert(qdict_get_int(dict3, "f.d") == 3); +- g_assert(qdict_get_int(dict3, "g") == 4); +- +- g_assert(qdict_size(dict3) == 8); +- +- qobject_unref(dict3); +-} +- +-static void qdict_array_split_test(void) +-{ +- QDict *test_dict = qdict_new(); +- QDict *dict1, *dict2; +- QNum *int1; +- QList *test_list; +- +- /* +- * Test the split of +- * +- * { +- * "1.x": 0, +- * "4.y": 1, +- * "0.a": 42, +- * "o.o": 7, +- * "0.b": 23, +- * "2": 66 +- * } +- * +- * to +- * +- * [ +- * { +- * "a": 42, +- * "b": 23 +- * }, +- * { +- * "x": 0 +- * }, +- * 66 +- * ] +- * +- * and +- * +- * { +- * "4.y": 1, +- * "o.o": 7 +- * } +- * +- * (remaining in the old QDict) +- * +- * This example is given in the comment of qdict_array_split(). +- */ +- +- qdict_put_int(test_dict, "1.x", 0); +- qdict_put_int(test_dict, "4.y", 1); +- qdict_put_int(test_dict, "0.a", 42); +- qdict_put_int(test_dict, "o.o", 7); +- qdict_put_int(test_dict, "0.b", 23); +- qdict_put_int(test_dict, "2", 66); +- +- qdict_array_split(test_dict, &test_list); +- +- dict1 = qobject_to(QDict, qlist_pop(test_list)); +- dict2 = qobject_to(QDict, qlist_pop(test_list)); +- int1 = qobject_to(QNum, qlist_pop(test_list)); +- +- g_assert(dict1); +- g_assert(dict2); +- g_assert(int1); +- g_assert(qlist_empty(test_list)); +- +- qobject_unref(test_list); +- +- g_assert(qdict_get_int(dict1, "a") == 42); +- g_assert(qdict_get_int(dict1, "b") == 23); +- +- g_assert(qdict_size(dict1) == 2); +- +- qobject_unref(dict1); +- +- g_assert(qdict_get_int(dict2, "x") == 0); +- +- g_assert(qdict_size(dict2) == 1); +- +- qobject_unref(dict2); +- +- g_assert_cmpint(qnum_get_int(int1), ==, 66); +- +- qobject_unref(int1); +- +- g_assert(qdict_get_int(test_dict, "4.y") == 1); +- g_assert(qdict_get_int(test_dict, "o.o") == 7); +- +- g_assert(qdict_size(test_dict) == 2); +- +- qobject_unref(test_dict); +- +- /* +- * Test the split of +- * +- * { +- * "0": 42, +- * "1": 23, +- * "1.x": 84 +- * } +- * +- * to +- * +- * [ +- * 42 +- * ] +- * +- * and +- * +- * { +- * "1": 23, +- * "1.x": 84 +- * } +- * +- * That is, test whether splitting stops if there is both an entry with key +- * of "%u" and other entries with keys prefixed "%u." for the same index. +- */ +- +- test_dict = qdict_new(); +- +- qdict_put_int(test_dict, "0", 42); +- qdict_put_int(test_dict, "1", 23); +- qdict_put_int(test_dict, "1.x", 84); +- +- qdict_array_split(test_dict, &test_list); +- +- int1 = qobject_to(QNum, qlist_pop(test_list)); +- +- g_assert(int1); +- g_assert(qlist_empty(test_list)); +- +- qobject_unref(test_list); +- +- g_assert_cmpint(qnum_get_int(int1), ==, 42); +- +- qobject_unref(int1); +- +- g_assert(qdict_get_int(test_dict, "1") == 23); +- g_assert(qdict_get_int(test_dict, "1.x") == 84); +- +- g_assert(qdict_size(test_dict) == 2); +- +- qobject_unref(test_dict); +-} +- +-static void qdict_array_entries_test(void) +-{ +- QDict *dict = qdict_new(); +- +- g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 0); +- +- qdict_put_int(dict, "bar", 0); +- qdict_put_int(dict, "baz.0", 0); +- g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 0); +- +- qdict_put_int(dict, "foo.1", 0); +- g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, -EINVAL); +- qdict_put_int(dict, "foo.0", 0); +- g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 2); +- qdict_put_int(dict, "foo.bar", 0); +- g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, -EINVAL); +- qdict_del(dict, "foo.bar"); +- +- qdict_put_int(dict, "foo.2.a", 0); +- qdict_put_int(dict, "foo.2.b", 0); +- qdict_put_int(dict, "foo.2.c", 0); +- g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 3); +- g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL); +- +- qobject_unref(dict); +- +- dict = qdict_new(); +- qdict_put_int(dict, "1", 0); +- g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL); +- qdict_put_int(dict, "0", 0); +- g_assert_cmpint(qdict_array_entries(dict, ""), ==, 2); +- qdict_put_int(dict, "bar", 0); +- g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL); +- qdict_del(dict, "bar"); +- +- qdict_put_int(dict, "2.a", 0); +- qdict_put_int(dict, "2.b", 0); +- qdict_put_int(dict, "2.c", 0); +- g_assert_cmpint(qdict_array_entries(dict, ""), ==, 3); +- +- qobject_unref(dict); +-} +- +-static void qdict_join_test(void) +-{ +- QDict *dict1, *dict2; +- bool overwrite = false; +- int i; +- +- dict1 = qdict_new(); +- dict2 = qdict_new(); +- +- /* Test everything once without overwrite and once with */ +- do +- { +- /* Test empty dicts */ +- qdict_join(dict1, dict2, overwrite); +- +- g_assert(qdict_size(dict1) == 0); +- g_assert(qdict_size(dict2) == 0); +- +- /* First iteration: Test movement */ +- /* Second iteration: Test empty source and non-empty destination */ +- qdict_put_int(dict2, "foo", 42); +- +- for (i = 0; i < 2; i++) { +- qdict_join(dict1, dict2, overwrite); +- +- g_assert(qdict_size(dict1) == 1); +- g_assert(qdict_size(dict2) == 0); +- +- g_assert(qdict_get_int(dict1, "foo") == 42); +- } +- +- /* Test non-empty source and destination without conflict */ +- qdict_put_int(dict2, "bar", 23); +- +- qdict_join(dict1, dict2, overwrite); +- +- g_assert(qdict_size(dict1) == 2); +- g_assert(qdict_size(dict2) == 0); +- +- g_assert(qdict_get_int(dict1, "foo") == 42); +- g_assert(qdict_get_int(dict1, "bar") == 23); +- +- /* Test conflict */ +- qdict_put_int(dict2, "foo", 84); +- +- qdict_join(dict1, dict2, overwrite); +- +- g_assert(qdict_size(dict1) == 2); +- g_assert(qdict_size(dict2) == !overwrite); +- +- g_assert(qdict_get_int(dict1, "foo") == (overwrite ? 84 : 42)); +- g_assert(qdict_get_int(dict1, "bar") == 23); +- +- if (!overwrite) { +- g_assert(qdict_get_int(dict2, "foo") == 84); +- } +- +- /* Check the references */ +- g_assert(qdict_get(dict1, "foo")->base.refcnt == 1); +- g_assert(qdict_get(dict1, "bar")->base.refcnt == 1); +- +- if (!overwrite) { +- g_assert(qdict_get(dict2, "foo")->base.refcnt == 1); +- } +- +- /* Clean up */ +- qdict_del(dict1, "foo"); +- qdict_del(dict1, "bar"); +- +- if (!overwrite) { +- qdict_del(dict2, "foo"); +- } +- } +- while (overwrite ^= true); +- +- qobject_unref(dict1); +- qobject_unref(dict2); +-} +- +-static void qdict_crumple_test_recursive(void) +-{ +- QDict *src, *dst, *rule, *vnc, *acl, *listen; +- QList *rules; +- +- src = qdict_new(); +- qdict_put_str(src, "vnc.listen.addr", "127.0.0.1"); +- qdict_put_str(src, "vnc.listen.port", "5901"); +- qdict_put_str(src, "vnc.acl.rules.0.match", "fred"); +- qdict_put_str(src, "vnc.acl.rules.0.policy", "allow"); +- qdict_put_str(src, "vnc.acl.rules.1.match", "bob"); +- qdict_put_str(src, "vnc.acl.rules.1.policy", "deny"); +- qdict_put_str(src, "vnc.acl.default", "deny"); +- qdict_put_str(src, "vnc.acl..name", "acl0"); +- qdict_put_str(src, "vnc.acl.rule..name", "acl0"); +- +- dst = qobject_to(QDict, qdict_crumple(src, &error_abort)); +- g_assert(dst); +- g_assert_cmpint(qdict_size(dst), ==, 1); +- +- vnc = qdict_get_qdict(dst, "vnc"); +- g_assert(vnc); +- g_assert_cmpint(qdict_size(vnc), ==, 3); +- +- listen = qdict_get_qdict(vnc, "listen"); +- g_assert(listen); +- g_assert_cmpint(qdict_size(listen), ==, 2); +- g_assert_cmpstr("127.0.0.1", ==, qdict_get_str(listen, "addr")); +- g_assert_cmpstr("5901", ==, qdict_get_str(listen, "port")); +- +- acl = qdict_get_qdict(vnc, "acl"); +- g_assert(acl); +- g_assert_cmpint(qdict_size(acl), ==, 3); +- +- rules = qdict_get_qlist(acl, "rules"); +- g_assert(rules); +- g_assert_cmpint(qlist_size(rules), ==, 2); +- +- rule = qobject_to(QDict, qlist_pop(rules)); +- g_assert(rule); +- g_assert_cmpint(qdict_size(rule), ==, 2); +- g_assert_cmpstr("fred", ==, qdict_get_str(rule, "match")); +- g_assert_cmpstr("allow", ==, qdict_get_str(rule, "policy")); +- qobject_unref(rule); +- +- rule = qobject_to(QDict, qlist_pop(rules)); +- g_assert(rule); +- g_assert_cmpint(qdict_size(rule), ==, 2); +- g_assert_cmpstr("bob", ==, qdict_get_str(rule, "match")); +- g_assert_cmpstr("deny", ==, qdict_get_str(rule, "policy")); +- qobject_unref(rule); +- +- /* With recursive crumpling, we should see all names unescaped */ +- g_assert_cmpstr("acl0", ==, qdict_get_str(vnc, "acl.name")); +- g_assert_cmpstr("acl0", ==, qdict_get_str(acl, "rule.name")); +- +- qobject_unref(src); +- qobject_unref(dst); +-} +- +-static void qdict_crumple_test_empty(void) +-{ +- QDict *src, *dst; +- +- src = qdict_new(); +- +- dst = qobject_to(QDict, qdict_crumple(src, &error_abort)); +- +- g_assert_cmpint(qdict_size(dst), ==, 0); +- +- qobject_unref(src); +- qobject_unref(dst); +-} +- +-static int qdict_count_entries(QDict *dict) +-{ +- const QDictEntry *e; +- int count = 0; +- +- for (e = qdict_first(dict); e; e = qdict_next(dict, e)) { +- count++; +- } +- +- return count; +-} +- +-static void qdict_rename_keys_test(void) +-{ +- QDict *dict = qdict_new(); +- QDict *copy; +- QDictRenames *renames; +- Error *local_err = NULL; +- +- qdict_put_str(dict, "abc", "foo"); +- qdict_put_str(dict, "abcdef", "bar"); +- qdict_put_int(dict, "number", 42); +- qdict_put_bool(dict, "flag", true); +- qdict_put_null(dict, "nothing"); +- +- /* Empty rename list */ +- renames = (QDictRenames[]) { +- { NULL, "this can be anything" } +- }; +- copy = qdict_clone_shallow(dict); +- qdict_rename_keys(copy, renames, &error_abort); +- +- g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "foo"); +- g_assert_cmpstr(qdict_get_str(copy, "abcdef"), ==, "bar"); +- g_assert_cmpint(qdict_get_int(copy, "number"), ==, 42); +- g_assert_cmpint(qdict_get_bool(copy, "flag"), ==, true); +- g_assert(qobject_type(qdict_get(copy, "nothing")) == QTYPE_QNULL); +- g_assert_cmpint(qdict_count_entries(copy), ==, 5); +- +- qobject_unref(copy); +- +- /* Simple rename of all entries */ +- renames = (QDictRenames[]) { +- { "abc", "str1" }, +- { "abcdef", "str2" }, +- { "number", "int" }, +- { "flag", "bool" }, +- { "nothing", "null" }, +- { NULL , NULL } +- }; +- copy = qdict_clone_shallow(dict); +- qdict_rename_keys(copy, renames, &error_abort); +- +- g_assert(!qdict_haskey(copy, "abc")); +- g_assert(!qdict_haskey(copy, "abcdef")); +- g_assert(!qdict_haskey(copy, "number")); +- g_assert(!qdict_haskey(copy, "flag")); +- g_assert(!qdict_haskey(copy, "nothing")); +- +- g_assert_cmpstr(qdict_get_str(copy, "str1"), ==, "foo"); +- g_assert_cmpstr(qdict_get_str(copy, "str2"), ==, "bar"); +- g_assert_cmpint(qdict_get_int(copy, "int"), ==, 42); +- g_assert_cmpint(qdict_get_bool(copy, "bool"), ==, true); +- g_assert(qobject_type(qdict_get(copy, "null")) == QTYPE_QNULL); +- g_assert_cmpint(qdict_count_entries(copy), ==, 5); +- +- qobject_unref(copy); +- +- /* Renames are processed top to bottom */ +- renames = (QDictRenames[]) { +- { "abc", "tmp" }, +- { "abcdef", "abc" }, +- { "number", "abcdef" }, +- { "flag", "number" }, +- { "nothing", "flag" }, +- { "tmp", "nothing" }, +- { NULL , NULL } +- }; +- copy = qdict_clone_shallow(dict); +- qdict_rename_keys(copy, renames, &error_abort); +- +- g_assert_cmpstr(qdict_get_str(copy, "nothing"), ==, "foo"); +- g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "bar"); +- g_assert_cmpint(qdict_get_int(copy, "abcdef"), ==, 42); +- g_assert_cmpint(qdict_get_bool(copy, "number"), ==, true); +- g_assert(qobject_type(qdict_get(copy, "flag")) == QTYPE_QNULL); +- g_assert(!qdict_haskey(copy, "tmp")); +- g_assert_cmpint(qdict_count_entries(copy), ==, 5); +- +- qobject_unref(copy); +- +- /* Conflicting rename */ +- renames = (QDictRenames[]) { +- { "abcdef", "abc" }, +- { NULL , NULL } +- }; +- copy = qdict_clone_shallow(dict); +- qdict_rename_keys(copy, renames, &local_err); +- +- g_assert(local_err != NULL); +- error_free(local_err); +- local_err = NULL; +- +- g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "foo"); +- g_assert_cmpstr(qdict_get_str(copy, "abcdef"), ==, "bar"); +- g_assert_cmpint(qdict_get_int(copy, "number"), ==, 42); +- g_assert_cmpint(qdict_get_bool(copy, "flag"), ==, true); +- g_assert(qobject_type(qdict_get(copy, "nothing")) == QTYPE_QNULL); +- g_assert_cmpint(qdict_count_entries(copy), ==, 5); +- +- qobject_unref(copy); +- +- /* Renames in an empty dict */ +- renames = (QDictRenames[]) { +- { "abcdef", "abc" }, +- { NULL , NULL } +- }; +- +- qobject_unref(dict); +- dict = qdict_new(); +- +- qdict_rename_keys(dict, renames, &error_abort); +- g_assert(qdict_first(dict) == NULL); +- +- qobject_unref(dict); +-} +- +-static void qdict_crumple_test_bad_inputs(void) +-{ +- QDict *src; +- Error *error = NULL; +- +- src = qdict_new(); +- /* rule.0 can't be both a string and a dict */ +- qdict_put_str(src, "rule.0", "fred"); +- qdict_put_str(src, "rule.0.policy", "allow"); +- +- g_assert(qdict_crumple(src, &error) == NULL); +- g_assert(error != NULL); +- error_free(error); +- error = NULL; +- qobject_unref(src); +- +- src = qdict_new(); +- /* rule can't be both a list and a dict */ +- qdict_put_str(src, "rule.0", "fred"); +- qdict_put_str(src, "rule.a", "allow"); +- +- g_assert(qdict_crumple(src, &error) == NULL); +- g_assert(error != NULL); +- error_free(error); +- error = NULL; +- qobject_unref(src); +- +- src = qdict_new(); +- /* The input should be flat, ie no dicts or lists */ +- qdict_put(src, "rule.a", qdict_new()); +- qdict_put_str(src, "rule.b", "allow"); +- +- g_assert(qdict_crumple(src, &error) == NULL); +- g_assert(error != NULL); +- error_free(error); +- error = NULL; +- qobject_unref(src); +- +- src = qdict_new(); +- /* List indexes must not have gaps */ +- qdict_put_str(src, "rule.0", "deny"); +- qdict_put_str(src, "rule.3", "allow"); +- +- g_assert(qdict_crumple(src, &error) == NULL); +- g_assert(error != NULL); +- error_free(error); +- error = NULL; +- qobject_unref(src); +- +- src = qdict_new(); +- /* List indexes must be in %zu format */ +- qdict_put_str(src, "rule.0", "deny"); +- qdict_put_str(src, "rule.+1", "allow"); +- +- g_assert(qdict_crumple(src, &error) == NULL); +- g_assert(error != NULL); +- error_free(error); +- error = NULL; +- qobject_unref(src); +-} +- + /* + * Errors test-cases + */ +@@ -987,29 +359,15 @@ int main(int argc, char **argv) + g_test_add_func("/public/get_try_int", qdict_get_try_int_test); + g_test_add_func("/public/get_str", qdict_get_str_test); + g_test_add_func("/public/get_try_str", qdict_get_try_str_test); +- g_test_add_func("/public/defaults", qdict_defaults_test); + g_test_add_func("/public/haskey_not", qdict_haskey_not_test); + g_test_add_func("/public/haskey", qdict_haskey_test); + g_test_add_func("/public/del", qdict_del_test); + g_test_add_func("/public/to_qdict", qobject_to_qdict_test); + g_test_add_func("/public/iterapi", qdict_iterapi_test); +- g_test_add_func("/public/flatten", qdict_flatten_test); +- g_test_add_func("/public/array_split", qdict_array_split_test); +- g_test_add_func("/public/array_entries", qdict_array_entries_test); +- g_test_add_func("/public/join", qdict_join_test); + + g_test_add_func("/errors/put_exists", qdict_put_exists_test); + g_test_add_func("/errors/get_not_exists", qdict_get_not_exists_test); + +- g_test_add_func("/public/crumple/recursive", +- qdict_crumple_test_recursive); +- g_test_add_func("/public/crumple/empty", +- qdict_crumple_test_empty); +- g_test_add_func("/public/crumple/bad_inputs", +- qdict_crumple_test_bad_inputs); +- +- g_test_add_func("/public/rename_keys", qdict_rename_keys_test); +- + /* The Big one */ + if (g_test_slow()) { + g_test_add_func("/stress/test", qdict_stress_test); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qobject-Replace-qobject_incref-QINCREF-qobject_decre.patch b/SOURCES/kvm-qobject-Replace-qobject_incref-QINCREF-qobject_decre.patch new file mode 100644 index 0000000..fe406c4 --- /dev/null +++ b/SOURCES/kvm-qobject-Replace-qobject_incref-QINCREF-qobject_decre.patch @@ -0,0 +1,5252 @@ +From 7760613392819cfcfca3f2569909fb2fa794204f Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Mon, 18 Jun 2018 08:43:11 +0200 +Subject: [PATCH 04/54] qobject: Replace qobject_incref/QINCREF + qobject_decref/QDECREF +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20180618084330.30009-5-armbru@redhat.com> +Patchwork-id: 80739 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 04/23] qobject: Replace qobject_incref/QINCREF qobject_decref/QDECREF +Bugzilla: 1557995 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +From: Marc-André Lureau + +Now that we can safely call QOBJECT() on QObject * as well as its +subtypes, we can have macros qobject_ref() / qobject_unref() that work +everywhere instead of having to use QINCREF() / QDECREF() for QObject +and qobject_incref() / qobject_decref() for its subtypes. + +The replacement is mechanical, except I broke a long line, and added a +cast in monitor_qmp_cleanup_req_queue_locked(). Unlike +qobject_decref(), qobject_unref() doesn't accept void *. + +Note that the new macros evaluate their argument exactly once, thus no +need to shout them. + +Signed-off-by: Marc-André Lureau +Reviewed-by: Eric Blake +Message-Id: <20180419150145.24795-4-marcandre.lureau@redhat.com> +Reviewed-by: Markus Armbruster +[Rebased, semantic conflict resolved, commit message improved] +Signed-off-by: Markus Armbruster +(cherry picked from commit cb3e7f08aeaab0ab13e629ce8496dca150a449ba) +[Trivial conflict in tests/migration-test.c resolved] + +Signed-off-by: Miroslav Rezanina +--- + block.c | 78 ++++++++++++++-------------- + block/blkdebug.c | 4 +- + block/blkverify.c | 4 +- + block/crypto.c | 4 +- + block/gluster.c | 4 +- + block/iscsi.c | 2 +- + block/nbd.c | 4 +- + block/nfs.c | 4 +- + block/null.c | 2 +- + block/nvme.c | 2 +- + block/parallels.c | 4 +- + block/qapi.c | 2 +- + block/qcow.c | 8 +-- + block/qcow2.c | 8 +-- + block/qed.c | 4 +- + block/quorum.c | 2 +- + block/rbd.c | 14 ++--- + block/sheepdog.c | 12 ++--- + block/snapshot.c | 4 +- + block/ssh.c | 4 +- + block/vdi.c | 2 +- + block/vhdx.c | 4 +- + block/vpc.c | 4 +- + block/vvfat.c | 2 +- + block/vxhs.c | 2 +- + blockdev.c | 16 +++--- + docs/devel/qapi-code-gen.txt | 2 +- + hw/i386/acpi-build.c | 12 ++--- + hw/ppc/spapr_drc.c | 2 +- + hw/usb/xen-usb.c | 4 +- + include/qapi/qmp/qnull.h | 2 +- + include/qapi/qmp/qobject.h | 40 +++++++-------- + migration/migration.c | 4 +- + migration/qjson.c | 2 +- + monitor.c | 50 +++++++++--------- + qapi/qapi-dealloc-visitor.c | 4 +- + qapi/qmp-dispatch.c | 6 +-- + qapi/qobject-input-visitor.c | 8 +-- + qapi/qobject-output-visitor.c | 8 +-- + qemu-img.c | 18 +++---- + qemu-io.c | 6 +-- + qga/main.c | 12 ++--- + qmp.c | 4 +- + qobject/json-parser.c | 10 ++-- + qobject/qdict.c | 38 +++++++------- + qobject/qjson.c | 2 +- + qobject/qlist.c | 4 +- + qom/object.c | 16 +++--- + qom/object_interfaces.c | 2 +- + scripts/coccinelle/qobject.cocci | 8 +-- + scripts/qapi/events.py | 2 +- + target/ppc/translate_init.c | 2 +- + target/s390x/cpu_models.c | 2 +- + tests/ahci-test.c | 6 +-- + tests/check-qdict.c | 100 ++++++++++++++++++------------------ + tests/check-qjson.c | 84 +++++++++++++++--------------- + tests/check-qlist.c | 8 +-- + tests/check-qlit.c | 10 ++-- + tests/check-qnull.c | 10 ++-- + tests/check-qnum.c | 28 +++++----- + tests/check-qobject.c | 2 +- + tests/check-qstring.c | 10 ++-- + tests/cpu-plug-test.c | 4 +- + tests/device-introspect-test.c | 24 ++++----- + tests/drive_del-test.c | 4 +- + tests/libqos/libqos.c | 8 +-- + tests/libqos/pci-pc.c | 2 +- + tests/libqtest.c | 24 ++++----- + tests/machine-none-test.c | 2 +- + tests/migration-test.c | 24 ++++----- + tests/numa-test.c | 16 +++--- + tests/pvpanic-test.c | 2 +- + tests/q35-test.c | 2 +- + tests/qmp-test.c | 38 +++++++------- + tests/qom-test.c | 8 +-- + tests/tco-test.c | 12 ++--- + tests/test-char.c | 2 +- + tests/test-keyval.c | 82 ++++++++++++++--------------- + tests/test-netfilter.c | 26 +++++----- + tests/test-qemu-opts.c | 14 ++--- + tests/test-qga.c | 76 +++++++++++++-------------- + tests/test-qmp-cmds.c | 24 ++++----- + tests/test-qmp-event.c | 2 +- + tests/test-qobject-input-visitor.c | 10 ++-- + tests/test-qobject-output-visitor.c | 18 +++---- + tests/test-visitor-serialization.c | 6 +-- + tests/test-x86-cpuid-compat.c | 14 ++--- + tests/tmp105-test.c | 4 +- + tests/vhost-user-test.c | 6 +-- + tests/virtio-net-test.c | 6 +-- + tests/vmgenid-test.c | 2 +- + tests/wdt_ib700-test.c | 14 ++--- + util/keyval.c | 12 ++--- + util/qemu-config.c | 4 +- + 94 files changed, 608 insertions(+), 612 deletions(-) + +diff --git a/block.c b/block.c +index a2caadf..55a7984 100644 +--- a/block.c ++++ b/block.c +@@ -1227,9 +1227,9 @@ BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name, + + ret = bdrv_open_driver(bs, drv, node_name, bs->options, flags, errp); + if (ret < 0) { +- QDECREF(bs->explicit_options); ++ qobject_unref(bs->explicit_options); + bs->explicit_options = NULL; +- QDECREF(bs->options); ++ qobject_unref(bs->options); + bs->options = NULL; + bdrv_unref(bs); + return NULL; +@@ -1460,7 +1460,7 @@ static QDict *parse_json_filename(const char *filename, Error **errp) + + options = qobject_to(QDict, options_obj); + if (!options) { +- qobject_decref(options_obj); ++ qobject_unref(options_obj); + error_setg(errp, "Invalid JSON object given"); + return NULL; + } +@@ -1490,7 +1490,7 @@ static void parse_json_protocol(QDict *options, const char **pfilename, + /* Options given in the filename have lower priority than options + * specified directly */ + qdict_join(options, json_options, false); +- QDECREF(json_options); ++ qobject_unref(json_options); + *pfilename = NULL; + } + +@@ -2273,7 +2273,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options, + if (reference || qdict_haskey(options, "file.filename")) { + backing_filename[0] = '\0'; + } else if (bs->backing_file[0] == '\0' && qdict_size(options) == 0) { +- QDECREF(options); ++ qobject_unref(options); + goto free_exit; + } else { + bdrv_get_full_backing_filename(bs, backing_filename, PATH_MAX, +@@ -2281,7 +2281,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options, + if (local_err) { + ret = -EINVAL; + error_propagate(errp, local_err); +- QDECREF(options); ++ qobject_unref(options); + goto free_exit; + } + } +@@ -2289,7 +2289,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options, + if (!bs->drv || !bs->drv->supports_backing) { + ret = -EINVAL; + error_setg(errp, "Driver doesn't support backing files"); +- QDECREF(options); ++ qobject_unref(options); + goto free_exit; + } + +@@ -2323,7 +2323,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options, + + free_exit: + g_free(backing_filename); +- QDECREF(tmp_parent_options); ++ qobject_unref(tmp_parent_options); + return ret; + } + +@@ -2356,7 +2356,7 @@ bdrv_open_child_bs(const char *filename, QDict *options, const char *bdref_key, + error_setg(errp, "A block device must be specified for \"%s\"", + bdref_key); + } +- QDECREF(image_options); ++ qobject_unref(image_options); + goto done; + } + +@@ -2449,7 +2449,7 @@ BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp) + obj = NULL; + + fail: +- qobject_decref(obj); ++ qobject_unref(obj); + visit_free(v); + return bs; + } +@@ -2519,7 +2519,7 @@ static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs, + } + + out: +- QDECREF(snapshot_options); ++ qobject_unref(snapshot_options); + g_free(tmp_filename); + return bs_snapshot; + } +@@ -2530,7 +2530,7 @@ out: + * options is a QDict of options to pass to the block drivers, or NULL for an + * empty set of options. The reference to the QDict belongs to the block layer + * after the call (even on failure), so if the caller intends to reuse the +- * dictionary, it needs to use QINCREF() before calling bdrv_open. ++ * dictionary, it needs to use qobject_ref() before calling bdrv_open. + * + * If *pbs is NULL, a new BDS will be created with a pointer to it stored there. + * If it is not NULL, the referenced BDS will be reused. +@@ -2561,7 +2561,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, + + if (reference) { + bool options_non_empty = options ? qdict_size(options) : false; +- QDECREF(options); ++ qobject_unref(options); + + if (filename || options_non_empty) { + error_setg(errp, "Cannot reference an existing block device with " +@@ -2752,7 +2752,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, + + bdrv_parent_cb_change_media(bs, true); + +- QDECREF(options); ++ qobject_unref(options); + + /* For snapshot=on, create a temporary qcow2 overlay. bs points to the + * temporary snapshot afterwards. */ +@@ -2776,10 +2776,10 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, + + fail: + blk_unref(file); +- QDECREF(snapshot_options); +- QDECREF(bs->explicit_options); +- QDECREF(bs->options); +- QDECREF(options); ++ qobject_unref(snapshot_options); ++ qobject_unref(bs->explicit_options); ++ qobject_unref(bs->options); ++ qobject_unref(options); + bs->options = NULL; + bs->explicit_options = NULL; + bdrv_unref(bs); +@@ -2788,8 +2788,8 @@ fail: + + close_and_fail: + bdrv_unref(bs); +- QDECREF(snapshot_options); +- QDECREF(options); ++ qobject_unref(snapshot_options); ++ qobject_unref(options); + error_propagate(errp, local_err); + return NULL; + } +@@ -2884,7 +2884,7 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, + old_options = qdict_clone_shallow(bs->explicit_options); + } + bdrv_join_options(bs, options, old_options); +- QDECREF(old_options); ++ qobject_unref(old_options); + + explicit_options = qdict_clone_shallow(options); + +@@ -2899,13 +2899,13 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, + qemu_opts_absorb_qdict(opts, options_copy, NULL); + update_flags_from_options(&flags, opts); + qemu_opts_del(opts); +- QDECREF(options_copy); ++ qobject_unref(options_copy); + } + + /* Old values are used for options that aren't set yet */ + old_options = qdict_clone_shallow(bs->options); + bdrv_join_options(bs, options, old_options); +- QDECREF(old_options); ++ qobject_unref(old_options); + + /* bdrv_open_inherit() sets and clears some additional flags internally */ + flags &= ~BDRV_O_PROTOCOL; +@@ -2917,8 +2917,8 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, + bs_entry = g_new0(BlockReopenQueueEntry, 1); + QSIMPLEQ_INSERT_TAIL(bs_queue, bs_entry, entry); + } else { +- QDECREF(bs_entry->state.options); +- QDECREF(bs_entry->state.explicit_options); ++ qobject_unref(bs_entry->state.options); ++ qobject_unref(bs_entry->state.explicit_options); + } + + bs_entry->state.bs = bs; +@@ -3008,9 +3008,9 @@ cleanup: + if (ret && bs_entry->prepared) { + bdrv_reopen_abort(&bs_entry->state); + } else if (ret) { +- QDECREF(bs_entry->state.explicit_options); ++ qobject_unref(bs_entry->state.explicit_options); + } +- QDECREF(bs_entry->state.options); ++ qobject_unref(bs_entry->state.options); + g_free(bs_entry); + } + g_free(bs_queue); +@@ -3253,7 +3253,7 @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state) + } + + /* set BDS specific flags now */ +- QDECREF(bs->explicit_options); ++ qobject_unref(bs->explicit_options); + + bs->explicit_options = reopen_state->explicit_options; + bs->open_flags = reopen_state->flags; +@@ -3296,7 +3296,7 @@ void bdrv_reopen_abort(BDRVReopenState *reopen_state) + drv->bdrv_reopen_abort(reopen_state); + } + +- QDECREF(reopen_state->explicit_options); ++ qobject_unref(reopen_state->explicit_options); + + bdrv_abort_perm_update(reopen_state->bs); + } +@@ -3343,11 +3343,11 @@ static void bdrv_close(BlockDriverState *bs) + bs->total_sectors = 0; + bs->encrypted = false; + bs->sg = false; +- QDECREF(bs->options); +- QDECREF(bs->explicit_options); ++ qobject_unref(bs->options); ++ qobject_unref(bs->explicit_options); + bs->options = NULL; + bs->explicit_options = NULL; +- QDECREF(bs->full_open_options); ++ qobject_unref(bs->full_open_options); + bs->full_open_options = NULL; + + bdrv_release_named_dirty_bitmaps(bs); +@@ -5134,7 +5134,7 @@ static bool append_open_options(QDict *d, BlockDriverState *bs) + continue; + } + +- qobject_incref(qdict_entry_value(entry)); ++ qobject_ref(qdict_entry_value(entry)); + qdict_put_obj(d, qdict_entry_key(entry), qdict_entry_value(entry)); + found_any = true; + } +@@ -5174,21 +5174,21 @@ void bdrv_refresh_filename(BlockDriverState *bs) + * information before refreshing it */ + bs->exact_filename[0] = '\0'; + if (bs->full_open_options) { +- QDECREF(bs->full_open_options); ++ qobject_unref(bs->full_open_options); + bs->full_open_options = NULL; + } + + opts = qdict_new(); + append_open_options(opts, bs); + drv->bdrv_refresh_filename(bs, opts); +- QDECREF(opts); ++ qobject_unref(opts); + } else if (bs->file) { + /* Try to reconstruct valid information from the underlying file */ + bool has_open_options; + + bs->exact_filename[0] = '\0'; + if (bs->full_open_options) { +- QDECREF(bs->full_open_options); ++ qobject_unref(bs->full_open_options); + bs->full_open_options = NULL; + } + +@@ -5207,12 +5207,12 @@ void bdrv_refresh_filename(BlockDriverState *bs) + * suffices without querying the (exact_)filename of this BDS. */ + if (bs->file->bs->full_open_options) { + qdict_put_str(opts, "driver", drv->format_name); +- QINCREF(bs->file->bs->full_open_options); ++ qobject_ref(bs->file->bs->full_open_options); + qdict_put(opts, "file", bs->file->bs->full_open_options); + + bs->full_open_options = opts; + } else { +- QDECREF(opts); ++ qobject_unref(opts); + } + } else if (!bs->full_open_options && qdict_size(bs->options)) { + /* There is no underlying file BDS (at least referenced by BDS.file), +@@ -5246,7 +5246,7 @@ void bdrv_refresh_filename(BlockDriverState *bs) + QString *json = qobject_to_json(QOBJECT(bs->full_open_options)); + snprintf(bs->filename, sizeof(bs->filename), "json:%s", + qstring_get_str(json)); +- QDECREF(json); ++ qobject_unref(json); + } + } + +diff --git a/block/blkdebug.c b/block/blkdebug.c +index 5897124..689703d 100644 +--- a/block/blkdebug.c ++++ b/block/blkdebug.c +@@ -845,12 +845,12 @@ static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options) + opts = qdict_new(); + qdict_put_str(opts, "driver", "blkdebug"); + +- QINCREF(bs->file->bs->full_open_options); ++ qobject_ref(bs->file->bs->full_open_options); + qdict_put(opts, "image", bs->file->bs->full_open_options); + + for (e = qdict_first(options); e; e = qdict_next(options, e)) { + if (strcmp(qdict_entry_key(e), "x-image")) { +- qobject_incref(qdict_entry_value(e)); ++ qobject_ref(qdict_entry_value(e)); + qdict_put_obj(opts, qdict_entry_key(e), qdict_entry_value(e)); + } + } +diff --git a/block/blkverify.c b/block/blkverify.c +index 331365b..3cffcb1 100644 +--- a/block/blkverify.c ++++ b/block/blkverify.c +@@ -291,9 +291,9 @@ static void blkverify_refresh_filename(BlockDriverState *bs, QDict *options) + QDict *opts = qdict_new(); + qdict_put_str(opts, "driver", "blkverify"); + +- QINCREF(bs->file->bs->full_open_options); ++ qobject_ref(bs->file->bs->full_open_options); + qdict_put(opts, "raw", bs->file->bs->full_open_options); +- QINCREF(s->test_file->bs->full_open_options); ++ qobject_ref(s->test_file->bs->full_open_options); + qdict_put(opts, "test", s->test_file->bs->full_open_options); + + bs->full_open_options = opts; +diff --git a/block/crypto.c b/block/crypto.c +index bc6c7e3..7e7ad2d 100644 +--- a/block/crypto.c ++++ b/block/crypto.c +@@ -305,7 +305,7 @@ static int block_crypto_open_generic(QCryptoBlockFormat format, + + ret = 0; + cleanup: +- QDECREF(cryptoopts); ++ qobject_unref(cryptoopts); + qapi_free_QCryptoBlockOpenOptions(open_opts); + return ret; + } +@@ -635,7 +635,7 @@ static int coroutine_fn block_crypto_co_create_opts_luks(const char *filename, + fail: + bdrv_unref(bs); + qapi_free_QCryptoBlockCreateOptions(create_opts); +- QDECREF(cryptoopts); ++ qobject_unref(cryptoopts); + return ret; + } + +diff --git a/block/gluster.c b/block/gluster.c +index 4adc1a8..55be566 100644 +--- a/block/gluster.c ++++ b/block/gluster.c +@@ -650,7 +650,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf, + } + gsconf = NULL; + +- QDECREF(backing_options); ++ qobject_unref(backing_options); + backing_options = NULL; + g_free(str); + str = NULL; +@@ -663,7 +663,7 @@ out: + qapi_free_SocketAddress(gsconf); + qemu_opts_del(opts); + g_free(str); +- QDECREF(backing_options); ++ qobject_unref(backing_options); + errno = EINVAL; + return -errno; + } +diff --git a/block/iscsi.c b/block/iscsi.c +index f5aecfc..d19ae0e 100644 +--- a/block/iscsi.c ++++ b/block/iscsi.c +@@ -2143,7 +2143,7 @@ static int coroutine_fn iscsi_co_create_opts(const char *filename, QemuOpts *opt + } else { + ret = iscsi_open(bs, bs_options, 0, NULL); + } +- QDECREF(bs_options); ++ qobject_unref(bs_options); + + if (ret != 0) { + goto out; +diff --git a/block/nbd.c b/block/nbd.c +index 1e2b3ba..3e1693c 100644 +--- a/block/nbd.c ++++ b/block/nbd.c +@@ -293,8 +293,8 @@ static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options, + } + + done: +- QDECREF(addr); +- qobject_decref(crumpled_addr); ++ qobject_unref(addr); ++ qobject_unref(crumpled_addr); + visit_free(iv); + return saddr; + } +diff --git a/block/nfs.c b/block/nfs.c +index 2577df4..66fddf1 100644 +--- a/block/nfs.c ++++ b/block/nfs.c +@@ -567,7 +567,7 @@ static BlockdevOptionsNfs *nfs_options_qdict_to_qapi(QDict *options, + v = qobject_input_visitor_new_keyval(crumpled); + visit_type_BlockdevOptionsNfs(v, NULL, &opts, &local_err); + visit_free(v); +- qobject_decref(crumpled); ++ qobject_unref(crumpled); + + if (local_err) { + return NULL; +@@ -683,7 +683,7 @@ static int coroutine_fn nfs_file_co_create_opts(const char *url, QemuOpts *opts, + + ret = 0; + out: +- QDECREF(options); ++ qobject_unref(options); + qapi_free_BlockdevCreateOptions(create_options); + return ret; + } +diff --git a/block/null.c b/block/null.c +index 806a863..700a2d0 100644 +--- a/block/null.c ++++ b/block/null.c +@@ -244,7 +244,7 @@ static int coroutine_fn null_co_block_status(BlockDriverState *bs, + + static void null_refresh_filename(BlockDriverState *bs, QDict *opts) + { +- QINCREF(opts); ++ qobject_ref(opts); + qdict_del(opts, "filename"); + + if (!qdict_size(opts)) { +diff --git a/block/nvme.c b/block/nvme.c +index c4f3a7b..e192da9 100644 +--- a/block/nvme.c ++++ b/block/nvme.c +@@ -1073,7 +1073,7 @@ static int nvme_reopen_prepare(BDRVReopenState *reopen_state, + + static void nvme_refresh_filename(BlockDriverState *bs, QDict *opts) + { +- QINCREF(opts); ++ qobject_ref(opts); + qdict_del(opts, "filename"); + + if (!qdict_size(opts)) { +diff --git a/block/parallels.c b/block/parallels.c +index 799215e..045810d 100644 +--- a/block/parallels.c ++++ b/block/parallels.c +@@ -651,7 +651,7 @@ static int coroutine_fn parallels_co_create_opts(const char *filename, + qdict_put_str(qdict, "file", bs->node_name); + + qobj = qdict_crumple(qdict, errp); +- QDECREF(qdict); ++ qobject_unref(qdict); + qdict = qobject_to(QDict, qobj); + if (qdict == NULL) { + ret = -EINVAL; +@@ -682,7 +682,7 @@ static int coroutine_fn parallels_co_create_opts(const char *filename, + ret = 0; + + done: +- QDECREF(qdict); ++ qobject_unref(qdict); + bdrv_unref(bs); + qapi_free_BlockdevCreateOptions(create_options); + return ret; +diff --git a/block/qapi.c b/block/qapi.c +index 04c6fc6..e12968f 100644 +--- a/block/qapi.c ++++ b/block/qapi.c +@@ -773,7 +773,7 @@ void bdrv_image_info_specific_dump(fprintf_function func_fprintf, void *f, + visit_complete(v, &obj); + data = qdict_get(qobject_to(QDict, obj), "data"); + dump_qobject(func_fprintf, f, 1, data); +- qobject_decref(obj); ++ qobject_unref(obj); + visit_free(v); + } + +diff --git a/block/qcow.c b/block/qcow.c +index f928916..4b2f7db 100644 +--- a/block/qcow.c ++++ b/block/qcow.c +@@ -315,7 +315,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, + goto fail; + } + +- QDECREF(encryptopts); ++ qobject_unref(encryptopts); + qapi_free_QCryptoBlockOpenOptions(crypto_opts); + qemu_co_mutex_init(&s->lock); + return 0; +@@ -326,7 +326,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, + g_free(s->cluster_cache); + g_free(s->cluster_data); + qcrypto_block_free(s->crypto); +- QDECREF(encryptopts); ++ qobject_unref(encryptopts); + qapi_free_QCryptoBlockOpenOptions(crypto_opts); + return ret; + } +@@ -995,7 +995,7 @@ static int coroutine_fn qcow_co_create_opts(const char *filename, + qdict_put_str(qdict, "file", bs->node_name); + + qobj = qdict_crumple(qdict, errp); +- QDECREF(qdict); ++ qobject_unref(qdict); + qdict = qobject_to(QDict, qobj); + if (qdict == NULL) { + ret = -EINVAL; +@@ -1025,7 +1025,7 @@ static int coroutine_fn qcow_co_create_opts(const char *filename, + + ret = 0; + fail: +- QDECREF(qdict); ++ qobject_unref(qdict); + bdrv_unref(bs); + qapi_free_BlockdevCreateOptions(create_options); + return ret; +diff --git a/block/qcow2.c b/block/qcow2.c +index ef68772..2f36e63 100644 +--- a/block/qcow2.c ++++ b/block/qcow2.c +@@ -1063,7 +1063,7 @@ static int qcow2_update_options_prepare(BlockDriverState *bs, + + ret = 0; + fail: +- QDECREF(encryptopts); ++ qobject_unref(encryptopts); + qemu_opts_del(opts); + opts = NULL; + return ret; +@@ -2183,7 +2183,7 @@ static void coroutine_fn qcow2_co_invalidate_cache(BlockDriverState *bs, + qemu_co_mutex_lock(&s->lock); + ret = qcow2_do_open(bs, options, flags, &local_err); + qemu_co_mutex_unlock(&s->lock); +- QDECREF(options); ++ qobject_unref(options); + if (local_err) { + error_propagate(errp, local_err); + error_prepend(errp, "Could not reopen qcow2 layer: "); +@@ -3139,7 +3139,7 @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt + + /* Now get the QAPI type BlockdevCreateOptions */ + qobj = qdict_crumple(qdict, errp); +- QDECREF(qdict); ++ qobject_unref(qdict); + qdict = qobject_to(QDict, qobj); + if (qdict == NULL) { + ret = -EINVAL; +@@ -3168,7 +3168,7 @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt + + ret = 0; + finish: +- QDECREF(qdict); ++ qobject_unref(qdict); + bdrv_unref(bs); + qapi_free_BlockdevCreateOptions(create_options); + return ret; +diff --git a/block/qed.c b/block/qed.c +index 35ff505..1db8eaf 100644 +--- a/block/qed.c ++++ b/block/qed.c +@@ -763,7 +763,7 @@ static int coroutine_fn bdrv_qed_co_create_opts(const char *filename, + qdict_put_str(qdict, "file", bs->node_name); + + qobj = qdict_crumple(qdict, errp); +- QDECREF(qdict); ++ qobject_unref(qdict); + qdict = qobject_to(QDict, qobj); + if (qdict == NULL) { + ret = -EINVAL; +@@ -789,7 +789,7 @@ static int coroutine_fn bdrv_qed_co_create_opts(const char *filename, + ret = bdrv_qed_co_create(create_options, errp); + + fail: +- QDECREF(qdict); ++ qobject_unref(qdict); + bdrv_unref(bs); + qapi_free_BlockdevCreateOptions(create_options); + return ret; +diff --git a/block/quorum.c b/block/quorum.c +index cfe484a..862cea3 100644 +--- a/block/quorum.c ++++ b/block/quorum.c +@@ -1082,7 +1082,7 @@ static void quorum_refresh_filename(BlockDriverState *bs, QDict *options) + + children = qlist_new(); + for (i = 0; i < s->num_children; i++) { +- QINCREF(s->children[i]->bs->full_open_options); ++ qobject_ref(s->children[i]->bs->full_open_options); + qlist_append(children, s->children[i]->bs->full_open_options); + } + +diff --git a/block/rbd.c b/block/rbd.c +index c9359d0..a14b42f 100644 +--- a/block/rbd.c ++++ b/block/rbd.c +@@ -226,7 +226,7 @@ static void qemu_rbd_parse_filename(const char *filename, QDict *options, + + done: + g_free(buf); +- QDECREF(keypairs); ++ qobject_unref(keypairs); + return; + } + +@@ -275,17 +275,17 @@ static int qemu_rbd_set_keypairs(rados_t cluster, const char *keypairs_json, + key = qstring_get_str(name); + + ret = rados_conf_set(cluster, key, qstring_get_str(value)); +- QDECREF(value); ++ qobject_unref(value); + if (ret < 0) { + error_setg_errno(errp, -ret, "invalid conf option %s", key); +- QDECREF(name); ++ qobject_unref(name); + ret = -EINVAL; + break; + } +- QDECREF(name); ++ qobject_unref(name); + } + +- QDECREF(keypairs); ++ qobject_unref(keypairs); + return ret; + } + +@@ -449,7 +449,7 @@ static int coroutine_fn qemu_rbd_co_create_opts(const char *filename, + } + + exit: +- QDECREF(options); ++ qobject_unref(options); + qapi_free_BlockdevCreateOptions(create_options); + return ret; + } +@@ -664,7 +664,7 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags, + v = qobject_input_visitor_new_keyval(crumpled); + visit_type_BlockdevOptionsRbd(v, NULL, &opts, &local_err); + visit_free(v); +- qobject_decref(crumpled); ++ qobject_unref(crumpled); + + if (local_err) { + error_propagate(errp, local_err); +diff --git a/block/sheepdog.c b/block/sheepdog.c +index 387f59c..07529f4 100644 +--- a/block/sheepdog.c ++++ b/block/sheepdog.c +@@ -567,8 +567,8 @@ static SocketAddress *sd_server_config(QDict *options, Error **errp) + + done: + visit_free(iv); +- qobject_decref(crumpled_server); +- QDECREF(server); ++ qobject_unref(crumpled_server); ++ qobject_unref(server); + return saddr; + } + +@@ -1883,7 +1883,7 @@ static int sd_create_prealloc(BlockdevOptionsSheepdog *location, int64_t size, + + if (local_err) { + error_propagate(errp, local_err); +- qobject_decref(obj); ++ qobject_unref(obj); + return -EINVAL; + } + +@@ -1901,7 +1901,7 @@ static int sd_create_prealloc(BlockdevOptionsSheepdog *location, int64_t size, + ret = sd_prealloc(bs, 0, size, errp); + fail: + bdrv_unref(bs); +- QDECREF(qdict); ++ qobject_unref(qdict); + return ret; + } + +@@ -2226,7 +2226,7 @@ static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts, + v = qobject_input_visitor_new_keyval(crumpled); + visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err); + visit_free(v); +- qobject_decref(crumpled); ++ qobject_unref(crumpled); + + if (local_err) { + error_propagate(errp, local_err); +@@ -2252,7 +2252,7 @@ static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts, + ret = sd_co_create(create_options, errp); + fail: + qapi_free_BlockdevCreateOptions(create_options); +- QDECREF(qdict); ++ qobject_unref(qdict); + return ret; + } + +diff --git a/block/snapshot.c b/block/snapshot.c +index eacc1f1..2953d96 100644 +--- a/block/snapshot.c ++++ b/block/snapshot.c +@@ -214,7 +214,7 @@ int bdrv_snapshot_goto(BlockDriverState *bs, + bdrv_ref(file); + + qdict_extract_subqdict(options, &file_options, "file."); +- QDECREF(file_options); ++ qobject_unref(file_options); + qdict_put_str(options, "file", bdrv_get_node_name(file)); + + drv->bdrv_close(bs); +@@ -223,7 +223,7 @@ int bdrv_snapshot_goto(BlockDriverState *bs, + + ret = bdrv_snapshot_goto(file, snapshot_id, errp); + open_ret = drv->bdrv_open(bs, options, bs->open_flags, &local_err); +- QDECREF(options); ++ qobject_unref(options); + if (open_ret < 0) { + bdrv_unref(file); + bs->drv = NULL; +diff --git a/block/ssh.c b/block/ssh.c +index ab3acf0..412a1bf 100644 +--- a/block/ssh.c ++++ b/block/ssh.c +@@ -638,7 +638,7 @@ static BlockdevOptionsSsh *ssh_parse_options(QDict *options, Error **errp) + v = qobject_input_visitor_new(crumpled); + visit_type_BlockdevOptionsSsh(v, NULL, &result, &local_err); + visit_free(v); +- qobject_decref(crumpled); ++ qobject_unref(crumpled); + + if (local_err) { + error_propagate(errp, local_err); +@@ -917,7 +917,7 @@ static int coroutine_fn ssh_co_create_opts(const char *filename, QemuOpts *opts, + ret = ssh_co_create(create_options, errp); + + out: +- QDECREF(uri_options); ++ qobject_unref(uri_options); + qapi_free_BlockdevCreateOptions(create_options); + return ret; + } +diff --git a/block/vdi.c b/block/vdi.c +index 4a2d1ff..96a22b8 100644 +--- a/block/vdi.c ++++ b/block/vdi.c +@@ -951,7 +951,7 @@ static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts, + /* Create the vdi image (format layer) */ + ret = vdi_co_do_create(create_options, block_size, errp); + done: +- QDECREF(qdict); ++ qobject_unref(qdict); + qapi_free_BlockdevCreateOptions(create_options); + bdrv_unref(bs_file); + return ret; +diff --git a/block/vhdx.c b/block/vhdx.c +index 6ac0424..c3a4220 100644 +--- a/block/vhdx.c ++++ b/block/vhdx.c +@@ -2003,7 +2003,7 @@ static int coroutine_fn vhdx_co_create_opts(const char *filename, + qdict_put_str(qdict, "file", bs->node_name); + + qobj = qdict_crumple(qdict, errp); +- QDECREF(qdict); ++ qobject_unref(qdict); + qdict = qobject_to(QDict, qobj); + if (qdict == NULL) { + ret = -EINVAL; +@@ -2049,7 +2049,7 @@ static int coroutine_fn vhdx_co_create_opts(const char *filename, + ret = vhdx_co_create(create_options, errp); + + fail: +- QDECREF(qdict); ++ qobject_unref(qdict); + bdrv_unref(bs); + qapi_free_BlockdevCreateOptions(create_options); + return ret; +diff --git a/block/vpc.c b/block/vpc.c +index 44f99a4..0ebfcd3 100644 +--- a/block/vpc.c ++++ b/block/vpc.c +@@ -1119,7 +1119,7 @@ static int coroutine_fn vpc_co_create_opts(const char *filename, + qdict_put_str(qdict, "file", bs->node_name); + + qobj = qdict_crumple(qdict, errp); +- QDECREF(qdict); ++ qobject_unref(qdict); + qdict = qobject_to(QDict, qobj); + if (qdict == NULL) { + ret = -EINVAL; +@@ -1157,7 +1157,7 @@ static int coroutine_fn vpc_co_create_opts(const char *filename, + ret = vpc_co_create(create_options, errp); + + fail: +- QDECREF(qdict); ++ qobject_unref(qdict); + bdrv_unref(bs); + qapi_free_BlockdevCreateOptions(create_options); + return ret; +diff --git a/block/vvfat.c b/block/vvfat.c +index 1569783..662dca0 100644 +--- a/block/vvfat.c ++++ b/block/vvfat.c +@@ -3179,7 +3179,7 @@ static int enable_write_target(BlockDriverState *bs, Error **errp) + qdict_put_str(options, "write-target.driver", "qcow"); + s->qcow = bdrv_open_child(s->qcow_filename, options, "write-target", bs, + &child_vvfat_qcow, false, errp); +- QDECREF(options); ++ qobject_unref(options); + if (!s->qcow) { + ret = -EINVAL; + goto err; +diff --git a/block/vxhs.c b/block/vxhs.c +index 68edb51..96e83d9 100644 +--- a/block/vxhs.c ++++ b/block/vxhs.c +@@ -497,7 +497,7 @@ static int vxhs_open(BlockDriverState *bs, QDict *options, + + out: + g_free(of_vsa_addr); +- QDECREF(backing_options); ++ qobject_unref(backing_options); + qemu_opts_del(tcp_opts); + qemu_opts_del(opts); + g_free(cacert); +diff --git a/blockdev.c b/blockdev.c +index 60b37dc..129e444 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -617,7 +617,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, + blk_rs->read_only = read_only; + blk_rs->detect_zeroes = detect_zeroes; + +- QDECREF(bs_opts); ++ qobject_unref(bs_opts); + } else { + if (file && !*file) { + file = NULL; +@@ -673,16 +673,16 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, + + err_no_bs_opts: + qemu_opts_del(opts); +- QDECREF(interval_dict); +- QDECREF(interval_list); ++ qobject_unref(interval_dict); ++ qobject_unref(interval_list); + return blk; + + early_err: + qemu_opts_del(opts); +- QDECREF(interval_dict); +- QDECREF(interval_list); ++ qobject_unref(interval_dict); ++ qobject_unref(interval_list); + err_no_opts: +- QDECREF(bs_opts); ++ qobject_unref(bs_opts); + return NULL; + } + +@@ -1171,7 +1171,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type) + + fail: + qemu_opts_del(legacy_opts); +- QDECREF(bs_opts); ++ qobject_unref(bs_opts); + return dinfo; + } + +@@ -4068,7 +4068,7 @@ void hmp_drive_add_node(Monitor *mon, const char *optstr) + qdict = qemu_opts_to_qdict(opts, NULL); + + if (!qdict_get_try_str(qdict, "node-name")) { +- QDECREF(qdict); ++ qobject_unref(qdict); + error_report("'node-name' needs to be specified"); + goto out; + } +diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt +index a569d24..b9b6eab 100644 +--- a/docs/devel/qapi-code-gen.txt ++++ b/docs/devel/qapi-code-gen.txt +@@ -1340,7 +1340,7 @@ Example: + emit(EXAMPLE_QAPI_EVENT_MY_EVENT, qmp, &err); + + error_propagate(errp, err); +- QDECREF(qmp); ++ qobject_unref(qmp); + } + + const QEnumLookup example_QAPIEvent_lookup = { +diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c +index 976d151..b309a97 100644 +--- a/hw/i386/acpi-build.c ++++ b/hw/i386/acpi-build.c +@@ -201,21 +201,21 @@ static void acpi_get_pm_info(AcpiPmInfo *pm) + } else { + pm->s3_disabled = false; + } +- qobject_decref(o); ++ qobject_unref(o); + o = object_property_get_qobject(obj, ACPI_PM_PROP_S4_DISABLED, NULL); + if (o) { + pm->s4_disabled = qnum_get_uint(qobject_to(QNum, o)); + } else { + pm->s4_disabled = false; + } +- qobject_decref(o); ++ qobject_unref(o); + o = object_property_get_qobject(obj, ACPI_PM_PROP_S4_VAL, NULL); + if (o) { + pm->s4_val = qnum_get_uint(qobject_to(QNum, o)); + } else { + pm->s4_val = false; + } +- qobject_decref(o); ++ qobject_unref(o); + + pm->pcihp_bridge_en = + object_property_get_bool(obj, "acpi-pci-hotplug-with-bridge-support", +@@ -573,7 +573,7 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, + } + } + aml_append(parent_scope, method); +- qobject_decref(bsel); ++ qobject_unref(bsel); + } + + /** +@@ -2617,12 +2617,12 @@ static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg) + return false; + } + mcfg->mcfg_base = qnum_get_uint(qobject_to(QNum, o)); +- qobject_decref(o); ++ qobject_unref(o); + + o = object_property_get_qobject(pci_host, PCIE_HOST_MCFG_SIZE, NULL); + assert(o); + mcfg->mcfg_size = qnum_get_uint(qobject_to(QNum, o)); +- qobject_decref(o); ++ qobject_unref(o); + return true; + } + +diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c +index aa25113..8a045d6 100644 +--- a/hw/ppc/spapr_drc.c ++++ b/hw/ppc/spapr_drc.c +@@ -305,7 +305,7 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name, + + if (!drc->fdt) { + visit_type_null(v, NULL, &null, errp); +- QDECREF(null); ++ qobject_unref(null); + return; + } + +diff --git a/hw/usb/xen-usb.c b/hw/usb/xen-usb.c +index 3beeb0d..b3a90c0 100644 +--- a/hw/usb/xen-usb.c ++++ b/hw/usb/xen-usb.c +@@ -763,7 +763,7 @@ static void usbback_portid_add(struct usbback_info *usbif, unsigned port, + if (!usbif->ports[port - 1].dev) { + goto err; + } +- QDECREF(qdict); ++ qobject_unref(qdict); + speed = usbif->ports[port - 1].dev->speed; + switch (speed) { + case USB_SPEED_LOW: +@@ -796,7 +796,7 @@ static void usbback_portid_add(struct usbback_info *usbif, unsigned port, + return; + + err: +- QDECREF(qdict); ++ qobject_unref(qdict); + xen_pv_printf(&usbif->xendev, 0, "device %s could not be opened\n", busid); + } + +diff --git a/include/qapi/qmp/qnull.h b/include/qapi/qmp/qnull.h +index e8ea2c3..75b29c6 100644 +--- a/include/qapi/qmp/qnull.h ++++ b/include/qapi/qmp/qnull.h +@@ -23,7 +23,7 @@ extern QNull qnull_; + + static inline QNull *qnull(void) + { +- QINCREF(&qnull_); ++ qobject_ref(&qnull_); + return &qnull_; + } + +diff --git a/include/qapi/qmp/qobject.h b/include/qapi/qmp/qobject.h +index a713c01..e20006f 100644 +--- a/include/qapi/qmp/qobject.h ++++ b/include/qapi/qmp/qobject.h +@@ -15,17 +15,17 @@ + * ------------------------------------ + * + * - Returning references: A function that returns an object may +- * return it as either a weak or a strong reference. If the reference +- * is strong, you are responsible for calling QDECREF() on the reference +- * when you are done. ++ * return it as either a weak or a strong reference. If the ++ * reference is strong, you are responsible for calling ++ * qobject_unref() on the reference when you are done. + * + * If the reference is weak, the owner of the reference may free it at + * any time in the future. Before storing the reference anywhere, you +- * should call QINCREF() to make the reference strong. ++ * should call qobject_ref() to make the reference strong. + * + * - Transferring ownership: when you transfer ownership of a reference + * by calling a function, you are no longer responsible for calling +- * QDECREF() when the reference is no longer needed. In other words, ++ * qobject_unref() when the reference is no longer needed. In other words, + * when the function returns you must behave as if the reference to the + * passed object was weak. + */ +@@ -50,14 +50,6 @@ struct QObject { + _obj ? container_of(&(_obj)->base, QObject, base) : NULL; \ + }) + +-/* High-level interface for qobject_incref() */ +-#define QINCREF(obj) \ +- qobject_incref(QOBJECT(obj)) +- +-/* High-level interface for qobject_decref() */ +-#define QDECREF(obj) \ +- qobject_decref(obj ? QOBJECT(obj) : NULL) +- + /* Required for qobject_to() */ + #define QTYPE_CAST_TO_QNull QTYPE_QNULL + #define QTYPE_CAST_TO_QNum QTYPE_QNUM +@@ -80,10 +72,7 @@ static inline void qobject_init(QObject *obj, QType type) + obj->base.type = type; + } + +-/** +- * qobject_incref(): Increment QObject's reference count +- */ +-static inline void qobject_incref(QObject *obj) ++static inline void qobject_ref_impl(QObject *obj) + { + if (obj) { + obj->base.refcnt++; +@@ -104,11 +93,7 @@ bool qobject_is_equal(const QObject *x, const QObject *y); + */ + void qobject_destroy(QObject *obj); + +-/** +- * qobject_decref(): Decrement QObject's reference count, deallocate +- * when it reaches zero +- */ +-static inline void qobject_decref(QObject *obj) ++static inline void qobject_unref_impl(QObject *obj) + { + assert(!obj || obj->base.refcnt); + if (obj && --obj->base.refcnt == 0) { +@@ -117,6 +102,17 @@ static inline void qobject_decref(QObject *obj) + } + + /** ++ * qobject_ref(): Increment QObject's reference count ++ */ ++#define qobject_ref(obj) qobject_ref_impl(QOBJECT(obj)) ++ ++/** ++ * qobject_unref(): Decrement QObject's reference count, deallocate ++ * when it reaches zero ++ */ ++#define qobject_unref(obj) qobject_unref_impl(QOBJECT(obj)) ++ ++/** + * qobject_type(): Return the QObject's type + */ + static inline QType qobject_type(const QObject *obj) +diff --git a/migration/migration.c b/migration/migration.c +index ceb1697..ef4bb42 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -1008,14 +1008,14 @@ void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp) + /* TODO Rewrite "" to null instead */ + if (params->has_tls_creds + && params->tls_creds->type == QTYPE_QNULL) { +- QDECREF(params->tls_creds->u.n); ++ qobject_unref(params->tls_creds->u.n); + params->tls_creds->type = QTYPE_QSTRING; + params->tls_creds->u.s = strdup(""); + } + /* TODO Rewrite "" to null instead */ + if (params->has_tls_hostname + && params->tls_hostname->type == QTYPE_QNULL) { +- QDECREF(params->tls_hostname->u.n); ++ qobject_unref(params->tls_hostname->u.n); + params->tls_hostname->type = QTYPE_QSTRING; + params->tls_hostname->u.s = strdup(""); + } +diff --git a/migration/qjson.c b/migration/qjson.c +index 9d7f6eb..e9889bd 100644 +--- a/migration/qjson.c ++++ b/migration/qjson.c +@@ -109,6 +109,6 @@ void qjson_finish(QJSON *json) + + void qjson_destroy(QJSON *json) + { +- QDECREF(json->str); ++ qobject_unref(json->str); + g_free(json); + } +diff --git a/monitor.c b/monitor.c +index 4f595ae..32f72f2 100644 +--- a/monitor.c ++++ b/monitor.c +@@ -329,8 +329,8 @@ int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func, + + static void qmp_request_free(QMPRequest *req) + { +- qobject_decref(req->id); +- qobject_decref(req->req); ++ qobject_unref(req->id); ++ qobject_unref(req->req); + g_free(req); + } + +@@ -346,7 +346,7 @@ static void monitor_qmp_cleanup_req_queue_locked(Monitor *mon) + static void monitor_qmp_cleanup_resp_queue_locked(Monitor *mon) + { + while (!g_queue_is_empty(mon->qmp.qmp_responses)) { +- qobject_decref(g_queue_pop_head(mon->qmp.qmp_responses)); ++ qobject_unref((QObject *)g_queue_pop_head(mon->qmp.qmp_responses)); + } + } + +@@ -391,14 +391,14 @@ static void monitor_flush_locked(Monitor *mon) + rc = qemu_chr_fe_write(&mon->chr, (const uint8_t *) buf, len); + if ((rc < 0 && errno != EAGAIN) || (rc == len)) { + /* all flushed or error */ +- QDECREF(mon->outbuf); ++ qobject_unref(mon->outbuf); + mon->outbuf = qstring_new(); + return; + } + if (rc > 0) { + /* partial write */ + QString *tmp = qstring_from_str(buf + rc); +- QDECREF(mon->outbuf); ++ qobject_unref(mon->outbuf); + mon->outbuf = tmp; + } + if (mon->out_watch == 0) { +@@ -482,7 +482,7 @@ static void monitor_json_emitter_raw(Monitor *mon, + qstring_append_chr(json, '\n'); + monitor_puts(mon, qstring_get_str(json)); + +- QDECREF(json); ++ qobject_unref(json); + } + + static void monitor_json_emitter(Monitor *mon, QObject *data) +@@ -494,9 +494,9 @@ static void monitor_json_emitter(Monitor *mon, QObject *data) + * caller won't free the data (which will be finally freed in + * responder thread). + */ +- qobject_incref(data); ++ qobject_ref(data); + qemu_mutex_lock(&mon->qmp.qmp_queue_lock); +- g_queue_push_tail(mon->qmp.qmp_responses, (void *)data); ++ g_queue_push_tail(mon->qmp.qmp_responses, data); + qemu_mutex_unlock(&mon->qmp.qmp_queue_lock); + qemu_bh_schedule(mon_global.qmp_respond_bh); + } else { +@@ -546,7 +546,7 @@ static void monitor_qmp_bh_responder(void *opaque) + break; + } + monitor_json_emitter_raw(response.mon, response.data); +- qobject_decref(response.data); ++ qobject_unref(response.data); + } + } + +@@ -613,9 +613,9 @@ monitor_qapi_event_queue(QAPIEvent event, QDict *qdict, Error **errp) + * last send. Store event for sending when timer fires, + * replacing a prior stored event if any. + */ +- QDECREF(evstate->qdict); ++ qobject_unref(evstate->qdict); + evstate->qdict = qdict; +- QINCREF(evstate->qdict); ++ qobject_ref(evstate->qdict); + } else { + /* + * Last send was (at least) evconf->rate ns ago. +@@ -630,7 +630,7 @@ monitor_qapi_event_queue(QAPIEvent event, QDict *qdict, Error **errp) + evstate = g_new(MonitorQAPIEventState, 1); + evstate->event = event; + evstate->data = data; +- QINCREF(evstate->data); ++ qobject_ref(evstate->data); + evstate->qdict = NULL; + evstate->timer = timer_new_ns(event_clock_type, + monitor_qapi_event_handler, +@@ -660,12 +660,12 @@ static void monitor_qapi_event_handler(void *opaque) + int64_t now = qemu_clock_get_ns(event_clock_type); + + monitor_qapi_event_emit(evstate->event, evstate->qdict); +- QDECREF(evstate->qdict); ++ qobject_unref(evstate->qdict); + evstate->qdict = NULL; + timer_mod_ns(evstate->timer, now + evconf->rate); + } else { + g_hash_table_remove(monitor_qapi_event_state, evstate); +- QDECREF(evstate->data); ++ qobject_unref(evstate->data); + timer_free(evstate->timer); + g_free(evstate); + } +@@ -747,7 +747,7 @@ static void monitor_data_destroy(Monitor *mon) + json_message_parser_destroy(&mon->qmp.parser); + } + readline_free(mon->rs); +- QDECREF(mon->outbuf); ++ qobject_unref(mon->outbuf); + qemu_mutex_destroy(&mon->out_lock); + qemu_mutex_destroy(&mon->qmp.qmp_queue_lock); + monitor_qmp_cleanup_req_queue_locked(mon); +@@ -3380,7 +3380,7 @@ static QDict *monitor_parse_arguments(Monitor *mon, + return qdict; + + fail: +- QDECREF(qdict); ++ qobject_unref(qdict); + g_free(key); + return NULL; + } +@@ -3405,7 +3405,7 @@ static void handle_hmp_command(Monitor *mon, const char *cmdline) + } + + cmd->cmd(mon, qdict); +- QDECREF(qdict); ++ qobject_unref(qdict); + } + + static void cmd_completion(Monitor *mon, const char *name, const char *list) +@@ -4067,15 +4067,15 @@ static void monitor_qmp_respond(Monitor *mon, QObject *rsp, + if (rsp) { + if (id) { + /* This is for the qdict below. */ +- qobject_incref(id); ++ qobject_ref(id); + qdict_put_obj(qobject_to(QDict, rsp), "id", id); + } + + monitor_json_emitter(mon, rsp); + } + +- qobject_decref(id); +- qobject_decref(rsp); ++ qobject_unref(id); ++ qobject_unref(rsp); + } + + /* +@@ -4098,7 +4098,7 @@ static void monitor_qmp_dispatch_one(QMPRequest *req_obj) + if (trace_event_get_state_backends(TRACE_HANDLE_QMP_COMMAND)) { + QString *req_json = qobject_to_json(req); + trace_handle_qmp_command(mon, qstring_get_str(req_json)); +- QDECREF(req_json); ++ qobject_unref(req_json); + } + + old_mon = cur_mon; +@@ -4116,7 +4116,7 @@ static void monitor_qmp_dispatch_one(QMPRequest *req_obj) + monitor_resume(mon); + } + +- qobject_decref(req); ++ qobject_unref(req); + } + + /* +@@ -4208,7 +4208,7 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens) + goto err; + } + +- qobject_incref(id); ++ qobject_ref(id); + qdict_del(qdict, "id"); + + req_obj = g_new0(QMPRequest, 1); +@@ -4263,7 +4263,7 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens) + + err: + monitor_qmp_respond(mon, NULL, err, NULL); +- qobject_decref(req); ++ qobject_unref(req); + } + + static void monitor_qmp_read(void *opaque, const uint8_t *buf, int size) +@@ -4382,7 +4382,7 @@ static void monitor_qmp_event(void *opaque, int event) + monitor_qmp_caps_reset(mon); + data = get_qmp_greeting(mon); + monitor_json_emitter(mon, data); +- qobject_decref(data); ++ qobject_unref(data); + mon_refcount++; + break; + case CHR_EVENT_CLOSED: +diff --git a/qapi/qapi-dealloc-visitor.c b/qapi/qapi-dealloc-visitor.c +index fd23803..6b24afd 100644 +--- a/qapi/qapi-dealloc-visitor.c ++++ b/qapi/qapi-dealloc-visitor.c +@@ -99,7 +99,7 @@ static void qapi_dealloc_type_anything(Visitor *v, const char *name, + QObject **obj, Error **errp) + { + if (obj) { +- qobject_decref(*obj); ++ qobject_unref(*obj); + } + } + +@@ -107,7 +107,7 @@ static void qapi_dealloc_type_null(Visitor *v, const char *name, + QNull **obj, Error **errp) + { + if (obj) { +- QDECREF(*obj); ++ qobject_unref(*obj); + } + } + +diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c +index dd05907..f9377b2 100644 +--- a/qapi/qmp-dispatch.c ++++ b/qapi/qmp-dispatch.c +@@ -105,7 +105,7 @@ static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request, + args = qdict_new(); + } else { + args = qdict_get_qdict(dict, "arguments"); +- QINCREF(args); ++ qobject_ref(args); + } + + cmd->fn(args, &ret, &local_err); +@@ -117,7 +117,7 @@ static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request, + ret = QOBJECT(qdict_new()); + } + +- QDECREF(args); ++ qobject_unref(args); + + return ret; + } +@@ -166,7 +166,7 @@ QObject *qmp_dispatch(QmpCommandList *cmds, QObject *request) + } else if (ret) { + qdict_put_obj(rsp, "return", ret); + } else { +- QDECREF(rsp); ++ qobject_unref(rsp); + return NULL; + } + +diff --git a/qapi/qobject-input-visitor.c b/qapi/qobject-input-visitor.c +index a7569d5..7a290c4 100644 +--- a/qapi/qobject-input-visitor.c ++++ b/qapi/qobject-input-visitor.c +@@ -588,7 +588,7 @@ static void qobject_input_type_any(Visitor *v, const char *name, QObject **obj, + return; + } + +- qobject_incref(qobj); ++ qobject_ref(qobj); + *obj = qobj; + } + +@@ -652,7 +652,7 @@ static void qobject_input_free(Visitor *v) + qobject_input_stack_object_free(tos); + } + +- qobject_decref(qiv->root); ++ qobject_unref(qiv->root); + if (qiv->errname) { + g_string_free(qiv->errname, TRUE); + } +@@ -678,7 +678,7 @@ static QObjectInputVisitor *qobject_input_visitor_base_new(QObject *obj) + v->visitor.free = qobject_input_free; + + v->root = obj; +- qobject_incref(obj); ++ qobject_ref(obj); + + return v; + } +@@ -744,7 +744,7 @@ Visitor *qobject_input_visitor_new_str(const char *str, + } + v = qobject_input_visitor_new_keyval(QOBJECT(args)); + } +- QDECREF(args); ++ qobject_unref(args); + + return v; + } +diff --git a/qapi/qobject-output-visitor.c b/qapi/qobject-output-visitor.c +index 877e37e..3a933b4 100644 +--- a/qapi/qobject-output-visitor.c ++++ b/qapi/qobject-output-visitor.c +@@ -188,7 +188,7 @@ static void qobject_output_type_any(Visitor *v, const char *name, + QObject **obj, Error **errp) + { + QObjectOutputVisitor *qov = to_qov(v); +- qobject_incref(*obj); ++ qobject_ref(*obj); + qobject_output_add_obj(qov, name, *obj); + } + +@@ -201,7 +201,7 @@ static void qobject_output_type_null(Visitor *v, const char *name, + + /* Finish building, and return the root object. + * The root object is never null. The caller becomes the object's +- * owner, and should use qobject_decref() when done with it. */ ++ * owner, and should use qobject_unref() when done with it. */ + static void qobject_output_complete(Visitor *v, void *opaque) + { + QObjectOutputVisitor *qov = to_qov(v); +@@ -210,7 +210,7 @@ static void qobject_output_complete(Visitor *v, void *opaque) + assert(qov->root && QSLIST_EMPTY(&qov->stack)); + assert(opaque == qov->result); + +- qobject_incref(qov->root); ++ qobject_ref(qov->root); + *qov->result = qov->root; + qov->result = NULL; + } +@@ -226,7 +226,7 @@ static void qobject_output_free(Visitor *v) + g_free(e); + } + +- qobject_decref(qov->root); ++ qobject_unref(qov->root); + g_free(qov); + } + +diff --git a/qemu-img.c b/qemu-img.c +index 8320887..62b29e7 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -279,7 +279,7 @@ static BlockBackend *img_open_opts(const char *optstr, + if (qdict_haskey(options, BDRV_OPT_FORCE_SHARE) + && !qdict_get_bool(options, BDRV_OPT_FORCE_SHARE)) { + error_report("--force-share/-U conflicts with image options"); +- QDECREF(options); ++ qobject_unref(options); + return NULL; + } + qdict_put_bool(options, BDRV_OPT_FORCE_SHARE, true); +@@ -561,9 +561,9 @@ static void dump_json_image_check(ImageCheck *check, bool quiet) + str = qobject_to_json_pretty(obj); + assert(str != NULL); + qprintf(quiet, "%s\n", qstring_get_str(str)); +- qobject_decref(obj); ++ qobject_unref(obj); + visit_free(v); +- QDECREF(str); ++ qobject_unref(str); + } + + static void dump_human_image_check(ImageCheck *check, bool quiet) +@@ -2384,9 +2384,9 @@ static void dump_json_image_info_list(ImageInfoList *list) + str = qobject_to_json_pretty(obj); + assert(str != NULL); + printf("%s\n", qstring_get_str(str)); +- qobject_decref(obj); ++ qobject_unref(obj); + visit_free(v); +- QDECREF(str); ++ qobject_unref(str); + } + + static void dump_json_image_info(ImageInfo *info) +@@ -2400,9 +2400,9 @@ static void dump_json_image_info(ImageInfo *info) + str = qobject_to_json_pretty(obj); + assert(str != NULL); + printf("%s\n", qstring_get_str(str)); +- qobject_decref(obj); ++ qobject_unref(obj); + visit_free(v); +- QDECREF(str); ++ qobject_unref(str); + } + + static void dump_human_image_info_list(ImageInfoList *list) +@@ -4488,9 +4488,9 @@ static void dump_json_block_measure_info(BlockMeasureInfo *info) + str = qobject_to_json_pretty(obj); + assert(str != NULL); + printf("%s\n", qstring_get_str(str)); +- qobject_decref(obj); ++ qobject_unref(obj); + visit_free(v); +- QDECREF(str); ++ qobject_unref(str); + } + + static int img_measure(int argc, char **argv) +diff --git a/qemu-io.c b/qemu-io.c +index e692c55..72fee0d 100644 +--- a/qemu-io.c ++++ b/qemu-io.c +@@ -86,7 +86,7 @@ static int openfile(char *name, int flags, bool writethrough, bool force_share, + + if (qemuio_blk) { + error_report("file open already, try 'help close'"); +- QDECREF(opts); ++ qobject_unref(opts); + return 1; + } + +@@ -97,7 +97,7 @@ static int openfile(char *name, int flags, bool writethrough, bool force_share, + if (qdict_haskey(opts, BDRV_OPT_FORCE_SHARE) + && !qdict_get_bool(opts, BDRV_OPT_FORCE_SHARE)) { + error_report("-U conflicts with image options"); +- QDECREF(opts); ++ qobject_unref(opts); + return 1; + } + qdict_put_bool(opts, BDRV_OPT_FORCE_SHARE, true); +@@ -243,7 +243,7 @@ static int open_f(BlockBackend *blk, int argc, char **argv) + } else if (optind == argc) { + openfile(NULL, flags, writethrough, force_share, opts); + } else { +- QDECREF(opts); ++ qobject_unref(opts); + qemuio_command_usage(&open_cmd); + } + return 0; +diff --git a/qga/main.c b/qga/main.c +index df1888e..1e1cec7 100644 +--- a/qga/main.c ++++ b/qga/main.c +@@ -563,7 +563,7 @@ static int send_response(GAState *s, QObject *payload) + response_qstr = qstring_new(); + qstring_append_chr(response_qstr, QGA_SENTINEL_BYTE); + qstring_append(response_qstr, qstring_get_str(payload_qstr)); +- QDECREF(payload_qstr); ++ qobject_unref(payload_qstr); + } else { + response_qstr = payload_qstr; + } +@@ -571,7 +571,7 @@ static int send_response(GAState *s, QObject *payload) + qstring_append_chr(response_qstr, '\n'); + buf = qstring_get_str(response_qstr); + status = ga_channel_write_all(s->channel, buf, strlen(buf)); +- QDECREF(response_qstr); ++ qobject_unref(response_qstr); + if (status != G_IO_STATUS_NORMAL) { + return -EIO; + } +@@ -592,7 +592,7 @@ static void process_command(GAState *s, QDict *req) + if (ret < 0) { + g_warning("error sending response: %s", strerror(-ret)); + } +- qobject_decref(rsp); ++ qobject_unref(rsp); + } + } + +@@ -609,7 +609,7 @@ static void process_event(JSONMessageParser *parser, GQueue *tokens) + g_debug("process_event: called"); + qdict = qobject_to(QDict, json_parser_parse_err(tokens, NULL, &err)); + if (err || !qdict) { +- QDECREF(qdict); ++ qobject_unref(qdict); + qdict = qdict_new(); + if (!err) { + g_warning("failed to parse event: unknown error"); +@@ -626,7 +626,7 @@ static void process_event(JSONMessageParser *parser, GQueue *tokens) + process_command(s, qdict); + } else { + if (!qdict_haskey(qdict, "error")) { +- QDECREF(qdict); ++ qobject_unref(qdict); + qdict = qdict_new(); + g_warning("unrecognized payload format"); + error_setg(&err, QERR_UNSUPPORTED); +@@ -639,7 +639,7 @@ static void process_event(JSONMessageParser *parser, GQueue *tokens) + } + } + +- QDECREF(qdict); ++ qobject_unref(qdict); + } + + /* false return signals GAChannel to close the current client connection */ +diff --git a/qmp.c b/qmp.c +index f722616..9e95b88 100644 +--- a/qmp.c ++++ b/qmp.c +@@ -710,7 +710,7 @@ void qmp_object_add(const char *type, const char *id, + error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict"); + return; + } +- QINCREF(pdict); ++ qobject_ref(pdict); + } else { + pdict = qdict_new(); + } +@@ -721,7 +721,7 @@ void qmp_object_add(const char *type, const char *id, + if (obj) { + object_unref(obj); + } +- QDECREF(pdict); ++ qobject_unref(pdict); + } + + void qmp_object_del(const char *id, Error **errp) +diff --git a/qobject/json-parser.c b/qobject/json-parser.c +index 769b960..a5aa790 100644 +--- a/qobject/json-parser.c ++++ b/qobject/json-parser.c +@@ -222,7 +222,7 @@ static QString *qstring_from_escaped_str(JSONParserContext *ctxt, + return str; + + out: +- QDECREF(str); ++ qobject_unref(str); + return NULL; + } + +@@ -311,12 +311,12 @@ static int parse_pair(JSONParserContext *ctxt, QDict *dict, va_list *ap) + + qdict_put_obj(dict, qstring_get_str(key), value); + +- QDECREF(key); ++ qobject_unref(key); + + return 0; + + out: +- QDECREF(key); ++ qobject_unref(key); + + return -1; + } +@@ -371,7 +371,7 @@ static QObject *parse_object(JSONParserContext *ctxt, va_list *ap) + return QOBJECT(dict); + + out: +- QDECREF(dict); ++ qobject_unref(dict); + return NULL; + } + +@@ -435,7 +435,7 @@ static QObject *parse_array(JSONParserContext *ctxt, va_list *ap) + return QOBJECT(list); + + out: +- QDECREF(list); ++ qobject_unref(list); + return NULL; + } + +diff --git a/qobject/qdict.c b/qobject/qdict.c +index d1997a0..2e9bd53 100644 +--- a/qobject/qdict.c ++++ b/qobject/qdict.c +@@ -123,7 +123,7 @@ void qdict_put_obj(QDict *qdict, const char *key, QObject *value) + entry = qdict_find(qdict, key, bucket); + if (entry) { + /* replace key's value */ +- qobject_decref(entry->value); ++ qobject_unref(entry->value); + entry->value = value; + } else { + /* allocate a new entry */ +@@ -373,7 +373,7 @@ QDict *qdict_clone_shallow(const QDict *src) + + for (i = 0; i < QDICT_BUCKET_MAX; i++) { + QLIST_FOREACH(entry, &src->table[i], next) { +- qobject_incref(entry->value); ++ qobject_ref(entry->value); + qdict_put_obj(dest, entry->key, entry->value); + } + } +@@ -390,7 +390,7 @@ static void qentry_destroy(QDictEntry *e) + assert(e->key != NULL); + assert(e->value != NULL); + +- qobject_decref(e->value); ++ qobject_unref(e->value); + g_free(e->key); + g_free(e); + } +@@ -480,7 +480,7 @@ void qdict_copy_default(QDict *dst, QDict *src, const char *key) + + val = qdict_get(src, key); + if (val) { +- qobject_incref(val); ++ qobject_ref(val); + qdict_put_obj(dst, key, val); + } + } +@@ -526,7 +526,7 @@ static void qdict_flatten_qlist(QList *qlist, QDict *target, const char *prefix) + qdict_flatten_qlist(qobject_to(QList, value), target, new_key); + } else { + /* All other types are moved to the target unchanged. */ +- qobject_incref(value); ++ qobject_ref(value); + qdict_put_obj(target, new_key, value); + } + +@@ -566,7 +566,7 @@ static void qdict_flatten_qdict(QDict *qdict, QDict *target, const char *prefix) + delete = true; + } else if (prefix) { + /* All other objects are moved to the target unchanged. */ +- qobject_incref(value); ++ qobject_ref(value); + qdict_put_obj(target, new_key, value); + delete = true; + } +@@ -610,7 +610,7 @@ void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start) + while (entry != NULL) { + next = qdict_next(src, entry); + if (strstart(entry->key, start, &p)) { +- qobject_incref(entry->value); ++ qobject_ref(entry->value); + qdict_put_obj(*dst, p, entry->value); + qdict_del(src, entry->key); + } +@@ -684,7 +684,7 @@ void qdict_array_split(QDict *src, QList **dst) + qdict_extract_subqdict(src, &subqdict, prefix); + assert(qdict_size(subqdict) > 0); + } else { +- qobject_incref(subqobj); ++ qobject_ref(subqobj); + qdict_del(src, indexstr); + } + +@@ -894,7 +894,7 @@ QObject *qdict_crumple(const QDict *src, Error **errp) + qdict_put_obj(two_level, prefix, QOBJECT(child_dict)); + } + +- qobject_incref(ent->value); ++ qobject_ref(ent->value); + qdict_put_obj(child_dict, suffix, ent->value); + } else { + if (child) { +@@ -902,7 +902,7 @@ QObject *qdict_crumple(const QDict *src, Error **errp) + prefix); + goto error; + } +- qobject_incref(ent->value); ++ qobject_ref(ent->value); + qdict_put_obj(two_level, prefix, ent->value); + } + +@@ -924,11 +924,11 @@ QObject *qdict_crumple(const QDict *src, Error **errp) + + qdict_put_obj(multi_level, ent->key, child); + } else { +- qobject_incref(ent->value); ++ qobject_ref(ent->value); + qdict_put_obj(multi_level, ent->key, ent->value); + } + } +- QDECREF(two_level); ++ qobject_unref(two_level); + two_level = NULL; + + /* Step 3: detect if we need to turn our dict into list */ +@@ -951,10 +951,10 @@ QObject *qdict_crumple(const QDict *src, Error **errp) + goto error; + } + +- qobject_incref(child); ++ qobject_ref(child); + qlist_append_obj(qobject_to(QList, dst), child); + } +- QDECREF(multi_level); ++ qobject_unref(multi_level); + multi_level = NULL; + } else { + dst = QOBJECT(multi_level); +@@ -964,9 +964,9 @@ QObject *qdict_crumple(const QDict *src, Error **errp) + + error: + g_free(prefix); +- QDECREF(multi_level); +- QDECREF(two_level); +- qobject_decref(dst); ++ qobject_unref(multi_level); ++ qobject_unref(two_level); ++ qobject_unref(dst); + return NULL; + } + +@@ -1055,7 +1055,7 @@ void qdict_join(QDict *dest, QDict *src, bool overwrite) + next = qdict_next(src, entry); + + if (overwrite || !qdict_haskey(dest, entry->key)) { +- qobject_incref(entry->value); ++ qobject_ref(entry->value); + qdict_put_obj(dest, entry->key, entry->value); + qdict_del(src, entry->key); + } +@@ -1088,7 +1088,7 @@ bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp) + } + + qobj = qdict_get(qdict, renames->from); +- qobject_incref(qobj); ++ qobject_ref(qobj); + qdict_put_obj(qdict, renames->to, qobj); + qdict_del(qdict, renames->from); + } +diff --git a/qobject/qjson.c b/qobject/qjson.c +index 655d38a..9816a65 100644 +--- a/qobject/qjson.c ++++ b/qobject/qjson.c +@@ -104,7 +104,7 @@ static void to_json_dict_iter(const char *key, QObject *obj, void *opaque) + + qkey = qstring_from_str(key); + to_json(QOBJECT(qkey), s->str, s->pretty, s->indent); +- QDECREF(qkey); ++ qobject_unref(qkey); + + qstring_append(s->str, ": "); + to_json(obj, s->str, s->pretty, s->indent); +diff --git a/qobject/qlist.c b/qobject/qlist.c +index 954fe98..37c1c16 100644 +--- a/qobject/qlist.c ++++ b/qobject/qlist.c +@@ -39,7 +39,7 @@ static void qlist_copy_elem(QObject *obj, void *opaque) + { + QList *dst = opaque; + +- qobject_incref(obj); ++ qobject_ref(obj); + qlist_append_obj(dst, obj); + } + +@@ -196,7 +196,7 @@ void qlist_destroy_obj(QObject *obj) + + QTAILQ_FOREACH_SAFE(entry, &qlist->head, next, next_entry) { + QTAILQ_REMOVE(&qlist->head, entry, next); +- qobject_decref(entry->value); ++ qobject_unref(entry->value); + g_free(entry); + } + +diff --git a/qom/object.c b/qom/object.c +index 4677951..76a89af 100644 +--- a/qom/object.c ++++ b/qom/object.c +@@ -1129,7 +1129,7 @@ void object_property_set_str(Object *obj, const char *value, + QString *qstr = qstring_from_str(value); + object_property_set_qobject(obj, QOBJECT(qstr), name, errp); + +- QDECREF(qstr); ++ qobject_unref(qstr); + } + + char *object_property_get_str(Object *obj, const char *name, +@@ -1147,7 +1147,7 @@ char *object_property_get_str(Object *obj, const char *name, + error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "string"); + } + +- qobject_decref(ret); ++ qobject_unref(ret); + return retval; + } + +@@ -1187,7 +1187,7 @@ void object_property_set_bool(Object *obj, bool value, + QBool *qbool = qbool_from_bool(value); + object_property_set_qobject(obj, QOBJECT(qbool), name, errp); + +- QDECREF(qbool); ++ qobject_unref(qbool); + } + + bool object_property_get_bool(Object *obj, const char *name, +@@ -1208,7 +1208,7 @@ bool object_property_get_bool(Object *obj, const char *name, + retval = qbool_get_bool(qbool); + } + +- qobject_decref(ret); ++ qobject_unref(ret); + return retval; + } + +@@ -1218,7 +1218,7 @@ void object_property_set_int(Object *obj, int64_t value, + QNum *qnum = qnum_from_int(value); + object_property_set_qobject(obj, QOBJECT(qnum), name, errp); + +- QDECREF(qnum); ++ qobject_unref(qnum); + } + + int64_t object_property_get_int(Object *obj, const char *name, +@@ -1238,7 +1238,7 @@ int64_t object_property_get_int(Object *obj, const char *name, + retval = -1; + } + +- qobject_decref(ret); ++ qobject_unref(ret); + return retval; + } + +@@ -1248,7 +1248,7 @@ void object_property_set_uint(Object *obj, uint64_t value, + QNum *qnum = qnum_from_uint(value); + + object_property_set_qobject(obj, QOBJECT(qnum), name, errp); +- QDECREF(qnum); ++ qobject_unref(qnum); + } + + uint64_t object_property_get_uint(Object *obj, const char *name, +@@ -1267,7 +1267,7 @@ uint64_t object_property_get_uint(Object *obj, const char *name, + retval = 0; + } + +- qobject_decref(ret); ++ qobject_unref(ret); + return retval; + } + +diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c +index 2f76e1f..980ffc2 100644 +--- a/qom/object_interfaces.c ++++ b/qom/object_interfaces.c +@@ -140,7 +140,7 @@ Object *user_creatable_add_opts(QemuOpts *opts, Error **errp) + qemu_opts_set_id(opts, (char *) id); + qemu_opt_set(opts, "qom-type", type, &error_abort); + g_free(type); +- QDECREF(pdict); ++ qobject_unref(pdict); + return obj; + } + +diff --git a/scripts/coccinelle/qobject.cocci b/scripts/coccinelle/qobject.cocci +index 47bcafe..9fee9c0 100644 +--- a/scripts/coccinelle/qobject.cocci ++++ b/scripts/coccinelle/qobject.cocci +@@ -3,11 +3,11 @@ + expression Obj, Key, E; + @@ + ( +-- qobject_incref(QOBJECT(E)); +-+ QINCREF(E); ++- qobject_ref(QOBJECT(E)); +++ qobject_ref(E); + | +-- qobject_decref(QOBJECT(E)); +-+ QDECREF(E); ++- qobject_unref(QOBJECT(E)); +++ qobject_unref(E); + | + - qdict_put_obj(Obj, Key, QOBJECT(E)); + + qdict_put(Obj, Key, E); +diff --git a/scripts/qapi/events.py b/scripts/qapi/events.py +index 3dc523c..4426861 100644 +--- a/scripts/qapi/events.py ++++ b/scripts/qapi/events.py +@@ -142,7 +142,7 @@ out: + ''') + ret += mcgen(''' + error_propagate(errp, err); +- QDECREF(qmp); ++ qobject_unref(qmp); + } + ''') + return ret +diff --git a/target/ppc/translate_init.c b/target/ppc/translate_init.c +index 391b94b..17b06c7 100644 +--- a/target/ppc/translate_init.c ++++ b/target/ppc/translate_init.c +@@ -8351,7 +8351,7 @@ static void getset_compat_deprecated(Object *obj, Visitor *v, const char *name, + "use max-cpu-compat machine property instead"); + } + visit_type_null(v, name, &null, NULL); +- QDECREF(null); ++ qobject_unref(null); + } + + static const PropertyInfo ppc_compat_deprecated_propinfo = { +diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c +index c4016e0..70b23bf 100644 +--- a/target/s390x/cpu_models.c ++++ b/target/s390x/cpu_models.c +@@ -554,7 +554,7 @@ static void cpu_info_from_model(CpuModelInfo *info, const S390CPUModel *model, + } + + if (!qdict_size(qdict)) { +- QDECREF(qdict); ++ qobject_unref(qdict); + } else { + info->props = QOBJECT(qdict); + info->has_props = true; +diff --git a/tests/ahci-test.c b/tests/ahci-test.c +index fb3cd84..1a7b761 100644 +--- a/tests/ahci-test.c ++++ b/tests/ahci-test.c +@@ -1566,7 +1566,7 @@ static void atapi_wait_tray(bool open) + } else { + g_assert(!qdict_get_bool(data, "tray-open")); + } +- QDECREF(rsp); ++ qobject_unref(rsp); + } + + static void test_atapi_tray(void) +@@ -1596,7 +1596,7 @@ static void test_atapi_tray(void) + "'arguments': {'id': 'cd0'}}"); + atapi_wait_tray(true); + rsp = qmp_receive(); +- QDECREF(rsp); ++ qobject_unref(rsp); + + qmp_discard_response("{'execute': 'blockdev-remove-medium', " + "'arguments': {'id': 'cd0'}}"); +@@ -1623,7 +1623,7 @@ static void test_atapi_tray(void) + "'arguments': {'id': 'cd0'}}"); + atapi_wait_tray(false); + rsp = qmp_receive(); +- QDECREF(rsp); ++ qobject_unref(rsp); + + /* Now, to convince ATAPI we understand the media has changed... */ + ahci_atapi_test_ready(ahci, port, false, SENSE_NOT_READY); +diff --git a/tests/check-qdict.c b/tests/check-qdict.c +index 07bb8f4..eba5d35 100644 +--- a/tests/check-qdict.c ++++ b/tests/check-qdict.c +@@ -34,7 +34,7 @@ static void qdict_new_test(void) + g_assert(qdict->base.refcnt == 1); + g_assert(qobject_type(QOBJECT(qdict)) == QTYPE_QDICT); + +- QDECREF(qdict); ++ qobject_unref(qdict); + } + + static void qdict_put_obj_test(void) +@@ -54,7 +54,7 @@ static void qdict_put_obj_test(void) + qn = qobject_to(QNum, ent->value); + g_assert_cmpint(qnum_get_int(qn), ==, num); + +- QDECREF(qdict); ++ qobject_unref(qdict); + } + + static void qdict_destroy_simple_test(void) +@@ -65,7 +65,7 @@ static void qdict_destroy_simple_test(void) + qdict_put_int(qdict, "num", 0); + qdict_put_str(qdict, "str", "foo"); + +- QDECREF(qdict); ++ qobject_unref(qdict); + } + + static void qdict_get_test(void) +@@ -84,7 +84,7 @@ static void qdict_get_test(void) + qn = qobject_to(QNum, obj); + g_assert_cmpint(qnum_get_int(qn), ==, value); + +- QDECREF(tests_dict); ++ qobject_unref(tests_dict); + } + + static void qdict_get_int_test(void) +@@ -99,7 +99,7 @@ static void qdict_get_int_test(void) + ret = qdict_get_int(tests_dict, key); + g_assert(ret == value); + +- QDECREF(tests_dict); ++ qobject_unref(tests_dict); + } + + static void qdict_get_try_int_test(void) +@@ -121,7 +121,7 @@ static void qdict_get_try_int_test(void) + ret = qdict_get_try_int(tests_dict, "string", -42); + g_assert_cmpuint(ret, ==, -42); + +- QDECREF(tests_dict); ++ qobject_unref(tests_dict); + } + + static void qdict_get_str_test(void) +@@ -137,7 +137,7 @@ static void qdict_get_str_test(void) + g_assert(p != NULL); + g_assert(strcmp(p, str) == 0); + +- QDECREF(tests_dict); ++ qobject_unref(tests_dict); + } + + static void qdict_get_try_str_test(void) +@@ -153,7 +153,7 @@ static void qdict_get_try_str_test(void) + g_assert(p != NULL); + g_assert(strcmp(p, str) == 0); + +- QDECREF(tests_dict); ++ qobject_unref(tests_dict); + } + + static void qdict_defaults_test(void) +@@ -174,8 +174,8 @@ static void qdict_defaults_test(void) + qdict_copy_default(copy, dict, "bar"); + g_assert_cmpstr(qdict_get_str(copy, "bar"), ==, "xyz"); + +- QDECREF(copy); +- QDECREF(dict); ++ qobject_unref(copy); ++ qobject_unref(dict); + } + + static void qdict_haskey_not_test(void) +@@ -183,7 +183,7 @@ static void qdict_haskey_not_test(void) + QDict *tests_dict = qdict_new(); + g_assert(qdict_haskey(tests_dict, "test") == 0); + +- QDECREF(tests_dict); ++ qobject_unref(tests_dict); + } + + static void qdict_haskey_test(void) +@@ -194,7 +194,7 @@ static void qdict_haskey_test(void) + qdict_put_int(tests_dict, key, 0); + g_assert(qdict_haskey(tests_dict, key) == 1); + +- QDECREF(tests_dict); ++ qobject_unref(tests_dict); + } + + static void qdict_del_test(void) +@@ -210,7 +210,7 @@ static void qdict_del_test(void) + g_assert(qdict_size(tests_dict) == 0); + g_assert(qdict_haskey(tests_dict, key) == 0); + +- QDECREF(tests_dict); ++ qobject_unref(tests_dict); + } + + static void qobject_to_qdict_test(void) +@@ -218,7 +218,7 @@ static void qobject_to_qdict_test(void) + QDict *tests_dict = qdict_new(); + g_assert(qobject_to(QDict, QOBJECT(tests_dict)) == tests_dict); + +- QDECREF(tests_dict); ++ qobject_unref(tests_dict); + } + + static void qdict_iterapi_test(void) +@@ -250,7 +250,7 @@ static void qdict_iterapi_test(void) + + g_assert(count == qdict_size(tests_dict)); + +- QDECREF(tests_dict); ++ qobject_unref(tests_dict); + } + + static void qdict_flatten_test(void) +@@ -325,7 +325,7 @@ static void qdict_flatten_test(void) + + g_assert(qdict_size(dict3) == 8); + +- QDECREF(dict3); ++ qobject_unref(dict3); + } + + static void qdict_array_split_test(void) +@@ -390,31 +390,31 @@ static void qdict_array_split_test(void) + g_assert(int1); + g_assert(qlist_empty(test_list)); + +- QDECREF(test_list); ++ qobject_unref(test_list); + + g_assert(qdict_get_int(dict1, "a") == 42); + g_assert(qdict_get_int(dict1, "b") == 23); + + g_assert(qdict_size(dict1) == 2); + +- QDECREF(dict1); ++ qobject_unref(dict1); + + g_assert(qdict_get_int(dict2, "x") == 0); + + g_assert(qdict_size(dict2) == 1); + +- QDECREF(dict2); ++ qobject_unref(dict2); + + g_assert_cmpint(qnum_get_int(int1), ==, 66); + +- QDECREF(int1); ++ qobject_unref(int1); + + g_assert(qdict_get_int(test_dict, "4.y") == 1); + g_assert(qdict_get_int(test_dict, "o.o") == 7); + + g_assert(qdict_size(test_dict) == 2); + +- QDECREF(test_dict); ++ qobject_unref(test_dict); + + /* + * Test the split of +@@ -455,18 +455,18 @@ static void qdict_array_split_test(void) + g_assert(int1); + g_assert(qlist_empty(test_list)); + +- QDECREF(test_list); ++ qobject_unref(test_list); + + g_assert_cmpint(qnum_get_int(int1), ==, 42); + +- QDECREF(int1); ++ qobject_unref(int1); + + g_assert(qdict_get_int(test_dict, "1") == 23); + g_assert(qdict_get_int(test_dict, "1.x") == 84); + + g_assert(qdict_size(test_dict) == 2); + +- QDECREF(test_dict); ++ qobject_unref(test_dict); + } + + static void qdict_array_entries_test(void) +@@ -493,7 +493,7 @@ static void qdict_array_entries_test(void) + g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 3); + g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL); + +- QDECREF(dict); ++ qobject_unref(dict); + + dict = qdict_new(); + qdict_put_int(dict, "1", 0); +@@ -509,7 +509,7 @@ static void qdict_array_entries_test(void) + qdict_put_int(dict, "2.c", 0); + g_assert_cmpint(qdict_array_entries(dict, ""), ==, 3); + +- QDECREF(dict); ++ qobject_unref(dict); + } + + static void qdict_join_test(void) +@@ -587,8 +587,8 @@ static void qdict_join_test(void) + } + while (overwrite ^= true); + +- QDECREF(dict1); +- QDECREF(dict2); ++ qobject_unref(dict1); ++ qobject_unref(dict2); + } + + static void qdict_crumple_test_recursive(void) +@@ -634,21 +634,21 @@ static void qdict_crumple_test_recursive(void) + g_assert_cmpint(qdict_size(rule), ==, 2); + g_assert_cmpstr("fred", ==, qdict_get_str(rule, "match")); + g_assert_cmpstr("allow", ==, qdict_get_str(rule, "policy")); +- QDECREF(rule); ++ qobject_unref(rule); + + rule = qobject_to(QDict, qlist_pop(rules)); + g_assert(rule); + g_assert_cmpint(qdict_size(rule), ==, 2); + g_assert_cmpstr("bob", ==, qdict_get_str(rule, "match")); + g_assert_cmpstr("deny", ==, qdict_get_str(rule, "policy")); +- QDECREF(rule); ++ qobject_unref(rule); + + /* With recursive crumpling, we should see all names unescaped */ + g_assert_cmpstr("acl0", ==, qdict_get_str(vnc, "acl.name")); + g_assert_cmpstr("acl0", ==, qdict_get_str(acl, "rule.name")); + +- QDECREF(src); +- QDECREF(dst); ++ qobject_unref(src); ++ qobject_unref(dst); + } + + static void qdict_crumple_test_empty(void) +@@ -661,8 +661,8 @@ static void qdict_crumple_test_empty(void) + + g_assert_cmpint(qdict_size(dst), ==, 0); + +- QDECREF(src); +- QDECREF(dst); ++ qobject_unref(src); ++ qobject_unref(dst); + } + + static int qdict_count_entries(QDict *dict) +@@ -704,7 +704,7 @@ static void qdict_rename_keys_test(void) + g_assert(qobject_type(qdict_get(copy, "nothing")) == QTYPE_QNULL); + g_assert_cmpint(qdict_count_entries(copy), ==, 5); + +- QDECREF(copy); ++ qobject_unref(copy); + + /* Simple rename of all entries */ + renames = (QDictRenames[]) { +@@ -731,7 +731,7 @@ static void qdict_rename_keys_test(void) + g_assert(qobject_type(qdict_get(copy, "null")) == QTYPE_QNULL); + g_assert_cmpint(qdict_count_entries(copy), ==, 5); + +- QDECREF(copy); ++ qobject_unref(copy); + + /* Renames are processed top to bottom */ + renames = (QDictRenames[]) { +@@ -754,7 +754,7 @@ static void qdict_rename_keys_test(void) + g_assert(!qdict_haskey(copy, "tmp")); + g_assert_cmpint(qdict_count_entries(copy), ==, 5); + +- QDECREF(copy); ++ qobject_unref(copy); + + /* Conflicting rename */ + renames = (QDictRenames[]) { +@@ -775,7 +775,7 @@ static void qdict_rename_keys_test(void) + g_assert(qobject_type(qdict_get(copy, "nothing")) == QTYPE_QNULL); + g_assert_cmpint(qdict_count_entries(copy), ==, 5); + +- QDECREF(copy); ++ qobject_unref(copy); + + /* Renames in an empty dict */ + renames = (QDictRenames[]) { +@@ -783,13 +783,13 @@ static void qdict_rename_keys_test(void) + { NULL , NULL } + }; + +- QDECREF(dict); ++ qobject_unref(dict); + dict = qdict_new(); + + qdict_rename_keys(dict, renames, &error_abort); + g_assert(qdict_first(dict) == NULL); + +- QDECREF(dict); ++ qobject_unref(dict); + } + + static void qdict_crumple_test_bad_inputs(void) +@@ -806,7 +806,7 @@ static void qdict_crumple_test_bad_inputs(void) + g_assert(error != NULL); + error_free(error); + error = NULL; +- QDECREF(src); ++ qobject_unref(src); + + src = qdict_new(); + /* rule can't be both a list and a dict */ +@@ -817,7 +817,7 @@ static void qdict_crumple_test_bad_inputs(void) + g_assert(error != NULL); + error_free(error); + error = NULL; +- QDECREF(src); ++ qobject_unref(src); + + src = qdict_new(); + /* The input should be flat, ie no dicts or lists */ +@@ -828,7 +828,7 @@ static void qdict_crumple_test_bad_inputs(void) + g_assert(error != NULL); + error_free(error); + error = NULL; +- QDECREF(src); ++ qobject_unref(src); + + src = qdict_new(); + /* List indexes must not have gaps */ +@@ -839,7 +839,7 @@ static void qdict_crumple_test_bad_inputs(void) + g_assert(error != NULL); + error_free(error); + error = NULL; +- QDECREF(src); ++ qobject_unref(src); + + src = qdict_new(); + /* List indexes must be in %zu format */ +@@ -850,7 +850,7 @@ static void qdict_crumple_test_bad_inputs(void) + g_assert(error != NULL); + error_free(error); + error = NULL; +- QDECREF(src); ++ qobject_unref(src); + } + + /* +@@ -871,7 +871,7 @@ static void qdict_put_exists_test(void) + + g_assert(qdict_size(tests_dict) == 1); + +- QDECREF(tests_dict); ++ qobject_unref(tests_dict); + } + + static void qdict_get_not_exists_test(void) +@@ -879,7 +879,7 @@ static void qdict_get_not_exists_test(void) + QDict *tests_dict = qdict_new(); + g_assert(qdict_get(tests_dict, "foo") == NULL); + +- QDECREF(tests_dict); ++ qobject_unref(tests_dict); + } + + /* +@@ -951,7 +951,7 @@ static void qdict_stress_test(void) + + g_assert(strcmp(str1, str2) == 0); + +- QDECREF(value); ++ qobject_unref(value); + } + + // Delete everything +@@ -962,14 +962,14 @@ static void qdict_stress_test(void) + break; + + qdict_del(qdict, key); +- QDECREF(value); ++ qobject_unref(value); + + g_assert(qdict_haskey(qdict, key) == 0); + } + fclose(test_file); + + g_assert(qdict_size(qdict) == 0); +- QDECREF(qdict); ++ qobject_unref(qdict); + } + + int main(int argc, char **argv) +diff --git a/tests/check-qjson.c b/tests/check-qjson.c +index 997f4d3..da582df 100644 +--- a/tests/check-qjson.c ++++ b/tests/check-qjson.c +@@ -67,10 +67,10 @@ static void escaped_string(void) + if (test_cases[i].skip == 0) { + str = qobject_to_json(obj); + g_assert_cmpstr(qstring_get_str(str), ==, test_cases[i].encoded); +- qobject_decref(obj); ++ qobject_unref(obj); + } + +- QDECREF(str); ++ qobject_unref(str); + } + } + +@@ -99,9 +99,9 @@ static void simple_string(void) + str = qobject_to_json(obj); + g_assert(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0); + +- qobject_decref(obj); ++ qobject_unref(obj); + +- QDECREF(str); ++ qobject_unref(str); + } + } + +@@ -127,7 +127,7 @@ static void single_quote_string(void) + g_assert(str); + g_assert(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0); + +- QDECREF(str); ++ qobject_unref(str); + } + } + +@@ -823,7 +823,7 @@ static void utf8_string(void) + } else { + g_assert(!obj); + } +- qobject_decref(obj); ++ qobject_unref(obj); + + obj = QOBJECT(qstring_from_str(utf8_in)); + str = qobject_to_json(obj); +@@ -833,8 +833,8 @@ static void utf8_string(void) + } else { + g_assert(!str); + } +- QDECREF(str); +- qobject_decref(obj); ++ qobject_unref(str); ++ qobject_unref(obj); + + /* + * Disabled, because qobject_from_json() is buggy, and I can't +@@ -869,7 +869,7 @@ static void vararg_string(void) + g_assert(str); + g_assert(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0); + +- QDECREF(str); ++ qobject_unref(str); + } + } + +@@ -904,10 +904,10 @@ static void simple_number(void) + + str = qobject_to_json(QOBJECT(qnum)); + g_assert(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0); +- QDECREF(str); ++ qobject_unref(str); + } + +- QDECREF(qnum); ++ qobject_unref(qnum); + } + } + +@@ -928,8 +928,8 @@ static void large_number(void) + + str = qobject_to_json(QOBJECT(qnum)); + g_assert_cmpstr(qstring_get_str(str), ==, maxu64); +- QDECREF(str); +- QDECREF(qnum); ++ qobject_unref(str); ++ qobject_unref(qnum); + + qnum = qobject_to(QNum, qobject_from_json(gtu64, &error_abort)); + g_assert(qnum); +@@ -939,8 +939,8 @@ static void large_number(void) + + str = qobject_to_json(QOBJECT(qnum)); + g_assert_cmpstr(qstring_get_str(str), ==, gtu64); +- QDECREF(str); +- QDECREF(qnum); ++ qobject_unref(str); ++ qobject_unref(qnum); + + qnum = qobject_to(QNum, qobject_from_json(lti64, &error_abort)); + g_assert(qnum); +@@ -950,8 +950,8 @@ static void large_number(void) + + str = qobject_to_json(QOBJECT(qnum)); + g_assert_cmpstr(qstring_get_str(str), ==, "-9223372036854775808"); +- QDECREF(str); +- QDECREF(qnum); ++ qobject_unref(str); ++ qobject_unref(qnum); + } + + static void float_number(void) +@@ -983,10 +983,10 @@ static void float_number(void) + + str = qobject_to_json(obj); + g_assert(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0); +- QDECREF(str); ++ qobject_unref(str); + } + +- QDECREF(qnum); ++ qobject_unref(qnum); + } + } + +@@ -1001,16 +1001,16 @@ static void vararg_number(void) + qnum = qobject_to(QNum, qobject_from_jsonf("%d", value)); + g_assert(qnum_get_try_int(qnum, &val)); + g_assert_cmpint(val, ==, value); +- QDECREF(qnum); ++ qobject_unref(qnum); + + qnum = qobject_to(QNum, qobject_from_jsonf("%lld", value_ll)); + g_assert(qnum_get_try_int(qnum, &val)); + g_assert_cmpint(val, ==, value_ll); +- QDECREF(qnum); ++ qobject_unref(qnum); + + qnum = qobject_to(QNum, qobject_from_jsonf("%f", valuef)); + g_assert(qnum_get_double(qnum) == valuef); +- QDECREF(qnum); ++ qobject_unref(qnum); + } + + static void keyword_literal(void) +@@ -1027,9 +1027,9 @@ static void keyword_literal(void) + + str = qobject_to_json(obj); + g_assert(strcmp(qstring_get_str(str), "true") == 0); +- QDECREF(str); ++ qobject_unref(str); + +- QDECREF(qbool); ++ qobject_unref(qbool); + + obj = qobject_from_json("false", &error_abort); + qbool = qobject_to(QBool, obj); +@@ -1038,20 +1038,20 @@ static void keyword_literal(void) + + str = qobject_to_json(obj); + g_assert(strcmp(qstring_get_str(str), "false") == 0); +- QDECREF(str); ++ qobject_unref(str); + +- QDECREF(qbool); ++ qobject_unref(qbool); + + qbool = qobject_to(QBool, qobject_from_jsonf("%i", false)); + g_assert(qbool); + g_assert(qbool_get_bool(qbool) == false); +- QDECREF(qbool); ++ qobject_unref(qbool); + + /* Test that non-zero values other than 1 get collapsed to true */ + qbool = qobject_to(QBool, qobject_from_jsonf("%i", 2)); + g_assert(qbool); + g_assert(qbool_get_bool(qbool) == true); +- QDECREF(qbool); ++ qobject_unref(qbool); + + obj = qobject_from_json("null", &error_abort); + g_assert(obj != NULL); +@@ -1060,8 +1060,8 @@ static void keyword_literal(void) + null = qnull(); + g_assert(QOBJECT(null) == obj); + +- qobject_decref(obj); +- QDECREF(null); ++ qobject_unref(obj); ++ qobject_unref(null); + } + + static void simple_dict(void) +@@ -1101,12 +1101,12 @@ static void simple_dict(void) + g_assert(qlit_equal_qobject(&test_cases[i].decoded, obj)); + + str = qobject_to_json(obj); +- qobject_decref(obj); ++ qobject_unref(obj); + + obj = qobject_from_json(qstring_get_str(str), &error_abort); + g_assert(qlit_equal_qobject(&test_cases[i].decoded, obj)); +- qobject_decref(obj); +- QDECREF(str); ++ qobject_unref(obj); ++ qobject_unref(str); + } + } + +@@ -1158,7 +1158,7 @@ static void large_dict(void) + obj = qobject_from_json(gstr->str, &error_abort); + g_assert(obj != NULL); + +- qobject_decref(obj); ++ qobject_unref(obj); + g_string_free(gstr, true); + } + +@@ -1210,12 +1210,12 @@ static void simple_list(void) + g_assert(qlit_equal_qobject(&test_cases[i].decoded, obj)); + + str = qobject_to_json(obj); +- qobject_decref(obj); ++ qobject_unref(obj); + + obj = qobject_from_json(qstring_get_str(str), &error_abort); + g_assert(qlit_equal_qobject(&test_cases[i].decoded, obj)); +- qobject_decref(obj); +- QDECREF(str); ++ qobject_unref(obj); ++ qobject_unref(str); + } + } + +@@ -1272,13 +1272,13 @@ static void simple_whitespace(void) + g_assert(qlit_equal_qobject(&test_cases[i].decoded, obj)); + + str = qobject_to_json(obj); +- qobject_decref(obj); ++ qobject_unref(obj); + + obj = qobject_from_json(qstring_get_str(str), &error_abort); + g_assert(qlit_equal_qobject(&test_cases[i].decoded, obj)); + +- qobject_decref(obj); +- QDECREF(str); ++ qobject_unref(obj); ++ qobject_unref(str); + } + } + +@@ -1301,7 +1301,7 @@ static void simple_varargs(void) + obj = qobject_from_jsonf("[%d, 2, %p]", 1, embedded_obj); + g_assert(qlit_equal_qobject(&decoded, obj)); + +- qobject_decref(obj); ++ qobject_unref(obj); + } + + static void empty_input(void) +@@ -1410,7 +1410,7 @@ static void limits_nesting(void) + + obj = qobject_from_json(make_nest(buf, max_nesting), &error_abort); + g_assert(obj != NULL); +- qobject_decref(obj); ++ qobject_unref(obj); + + obj = qobject_from_json(make_nest(buf, max_nesting + 1), &err); + error_free_or_abort(&err); +diff --git a/tests/check-qlist.c b/tests/check-qlist.c +index a1c69ed..ece83e2 100644 +--- a/tests/check-qlist.c ++++ b/tests/check-qlist.c +@@ -29,7 +29,7 @@ static void qlist_new_test(void) + g_assert(qlist->base.refcnt == 1); + g_assert(qobject_type(QOBJECT(qlist)) == QTYPE_QLIST); + +- QDECREF(qlist); ++ qobject_unref(qlist); + } + + static void qlist_append_test(void) +@@ -47,7 +47,7 @@ static void qlist_append_test(void) + g_assert(entry != NULL); + g_assert(entry->value == QOBJECT(qi)); + +- QDECREF(qlist); ++ qobject_unref(qlist); + } + + static void qobject_to_qlist_test(void) +@@ -58,7 +58,7 @@ static void qobject_to_qlist_test(void) + + g_assert(qobject_to(QList, QOBJECT(qlist)) == qlist); + +- QDECREF(qlist); ++ qobject_unref(qlist); + } + + static int iter_called; +@@ -96,7 +96,7 @@ static void qlist_iter_test(void) + + g_assert(iter_called == iter_max); + +- QDECREF(qlist); ++ qobject_unref(qlist); + } + + int main(int argc, char **argv) +diff --git a/tests/check-qlit.c b/tests/check-qlit.c +index 96bbb06..bd6798d 100644 +--- a/tests/check-qlit.c ++++ b/tests/check-qlit.c +@@ -62,7 +62,7 @@ static void qlit_equal_qobject_test(void) + qdict_put(qobject_to(QDict, qobj), "bee", qlist_new()); + g_assert(!qlit_equal_qobject(&qlit, qobj)); + +- qobject_decref(qobj); ++ qobject_unref(qobj); + } + + static void qobject_from_qlit_test(void) +@@ -79,15 +79,15 @@ static void qobject_from_qlit_test(void) + bee = qdict_get_qlist(qdict, "bee"); + obj = qlist_pop(bee); + g_assert_cmpint(qnum_get_int(qobject_to(QNum, obj)), ==, 43); +- qobject_decref(obj); ++ qobject_unref(obj); + obj = qlist_pop(bee); + g_assert_cmpint(qnum_get_int(qobject_to(QNum, obj)), ==, 44); +- qobject_decref(obj); ++ qobject_unref(obj); + obj = qlist_pop(bee); + g_assert(qbool_get_bool(qobject_to(QBool, obj))); +- qobject_decref(obj); ++ qobject_unref(obj); + +- qobject_decref(qobj); ++ qobject_unref(qobj); + } + + int main(int argc, char **argv) +diff --git a/tests/check-qnull.c b/tests/check-qnull.c +index afa4400..ebf21db 100644 +--- a/tests/check-qnull.c ++++ b/tests/check-qnull.c +@@ -30,7 +30,7 @@ static void qnull_ref_test(void) + g_assert(obj == QOBJECT(&qnull_)); + g_assert(qnull_.base.refcnt == 2); + g_assert(qobject_type(obj) == QTYPE_QNULL); +- qobject_decref(obj); ++ qobject_unref(obj); + g_assert(qnull_.base.refcnt == 1); + } + +@@ -49,10 +49,10 @@ static void qnull_visit_test(void) + g_assert(qnull_.base.refcnt == 1); + obj = QOBJECT(qnull()); + v = qobject_input_visitor_new(obj); +- qobject_decref(obj); ++ qobject_unref(obj); + visit_type_null(v, NULL, &null, &error_abort); + g_assert(obj == QOBJECT(&qnull_)); +- QDECREF(null); ++ qobject_unref(null); + visit_free(v); + + null = NULL; +@@ -60,8 +60,8 @@ static void qnull_visit_test(void) + visit_type_null(v, NULL, &null, &error_abort); + visit_complete(v, &obj); + g_assert(obj == QOBJECT(&qnull_)); +- QDECREF(null); +- qobject_decref(obj); ++ qobject_unref(null); ++ qobject_unref(obj); + visit_free(v); + + g_assert(qnull_.base.refcnt == 1); +diff --git a/tests/check-qnum.c b/tests/check-qnum.c +index 9187da7..4105015 100644 +--- a/tests/check-qnum.c ++++ b/tests/check-qnum.c +@@ -35,7 +35,7 @@ static void qnum_from_int_test(void) + g_assert_cmpint(qn->base.refcnt, ==, 1); + g_assert_cmpint(qobject_type(QOBJECT(qn)), ==, QTYPE_QNUM); + +- QDECREF(qn); ++ qobject_unref(qn); + } + + static void qnum_from_uint_test(void) +@@ -50,7 +50,7 @@ static void qnum_from_uint_test(void) + g_assert(qn->base.refcnt == 1); + g_assert(qobject_type(QOBJECT(qn)) == QTYPE_QNUM); + +- QDECREF(qn); ++ qobject_unref(qn); + } + + static void qnum_from_double_test(void) +@@ -65,7 +65,7 @@ static void qnum_from_double_test(void) + g_assert_cmpint(qn->base.refcnt, ==, 1); + g_assert_cmpint(qobject_type(QOBJECT(qn)), ==, QTYPE_QNUM); + +- QDECREF(qn); ++ qobject_unref(qn); + } + + static void qnum_from_int64_test(void) +@@ -76,7 +76,7 @@ static void qnum_from_int64_test(void) + qn = qnum_from_int(value); + g_assert_cmpint((int64_t) qn->u.i64, ==, value); + +- QDECREF(qn); ++ qobject_unref(qn); + } + + static void qnum_get_int_test(void) +@@ -87,7 +87,7 @@ static void qnum_get_int_test(void) + qn = qnum_from_int(value); + g_assert_cmpint(qnum_get_int(qn), ==, value); + +- QDECREF(qn); ++ qobject_unref(qn); + } + + static void qnum_get_uint_test(void) +@@ -100,25 +100,25 @@ static void qnum_get_uint_test(void) + qn = qnum_from_uint(value); + g_assert(qnum_get_try_uint(qn, &val)); + g_assert_cmpuint(val, ==, value); +- QDECREF(qn); ++ qobject_unref(qn); + + qn = qnum_from_int(value); + g_assert(qnum_get_try_uint(qn, &val)); + g_assert_cmpuint(val, ==, value); +- QDECREF(qn); ++ qobject_unref(qn); + + /* invalid cases */ + qn = qnum_from_int(-1); + g_assert(!qnum_get_try_uint(qn, &val)); +- QDECREF(qn); ++ qobject_unref(qn); + + qn = qnum_from_uint(-1ULL); + g_assert(!qnum_get_try_int(qn, &ival)); +- QDECREF(qn); ++ qobject_unref(qn); + + qn = qnum_from_double(0.42); + g_assert(!qnum_get_try_uint(qn, &val)); +- QDECREF(qn); ++ qobject_unref(qn); + } + + static void qobject_to_qnum_test(void) +@@ -127,11 +127,11 @@ static void qobject_to_qnum_test(void) + + qn = qnum_from_int(0); + g_assert(qobject_to(QNum, QOBJECT(qn)) == qn); +- QDECREF(qn); ++ qobject_unref(qn); + + qn = qnum_from_double(0); + g_assert(qobject_to(QNum, QOBJECT(qn)) == qn); +- QDECREF(qn); ++ qobject_unref(qn); + } + + static void qnum_to_string_test(void) +@@ -143,13 +143,13 @@ static void qnum_to_string_test(void) + tmp = qnum_to_string(qn); + g_assert_cmpstr(tmp, ==, "123456"); + g_free(tmp); +- QDECREF(qn); ++ qobject_unref(qn); + + qn = qnum_from_double(0.42); + tmp = qnum_to_string(qn); + g_assert_cmpstr(tmp, ==, "0.42"); + g_free(tmp); +- QDECREF(qn); ++ qobject_unref(qn); + } + + int main(int argc, char **argv) +diff --git a/tests/check-qobject.c b/tests/check-qobject.c +index 7629b80..5cb08fc 100644 +--- a/tests/check-qobject.c ++++ b/tests/check-qobject.c +@@ -80,7 +80,7 @@ static void do_free_all(int _, ...) + + va_start(ap, _); + while ((obj = va_arg(ap, QObject *)) != NULL) { +- qobject_decref(obj); ++ qobject_unref(obj); + } + va_end(ap); + } +diff --git a/tests/check-qstring.c b/tests/check-qstring.c +index 9c4dd3f..f11a7a8 100644 +--- a/tests/check-qstring.c ++++ b/tests/check-qstring.c +@@ -31,7 +31,7 @@ static void qstring_from_str_test(void) + g_assert(strcmp(str, qstring->string) == 0); + g_assert(qobject_type(QOBJECT(qstring)) == QTYPE_QSTRING); + +- QDECREF(qstring); ++ qobject_unref(qstring); + } + + static void qstring_get_str_test(void) +@@ -44,7 +44,7 @@ static void qstring_get_str_test(void) + ret_str = qstring_get_str(qstring); + g_assert(strcmp(ret_str, str) == 0); + +- QDECREF(qstring); ++ qobject_unref(qstring); + } + + static void qstring_append_chr_test(void) +@@ -59,7 +59,7 @@ static void qstring_append_chr_test(void) + qstring_append_chr(qstring, str[i]); + + g_assert(strcmp(str, qstring_get_str(qstring)) == 0); +- QDECREF(qstring); ++ qobject_unref(qstring); + } + + static void qstring_from_substr_test(void) +@@ -70,7 +70,7 @@ static void qstring_from_substr_test(void) + g_assert(qs != NULL); + g_assert(strcmp(qstring_get_str(qs), "tualiza") == 0); + +- QDECREF(qs); ++ qobject_unref(qs); + } + + +@@ -81,7 +81,7 @@ static void qobject_to_qstring_test(void) + qstring = qstring_from_str("foo"); + g_assert(qobject_to(QString, QOBJECT(qstring)) == qstring); + +- QDECREF(qstring); ++ qobject_unref(qstring); + } + + int main(int argc, char **argv) +diff --git a/tests/cpu-plug-test.c b/tests/cpu-plug-test.c +index 112869b..48b8d09 100644 +--- a/tests/cpu-plug-test.c ++++ b/tests/cpu-plug-test.c +@@ -42,7 +42,7 @@ static void test_plug_with_cpu_add(gconstpointer data) + " 'arguments': { 'id': %d } }", i); + g_assert(response); + g_assert(!qdict_haskey(response, "error")); +- QDECREF(response); ++ qobject_unref(response); + } + + qtest_end(); +@@ -66,7 +66,7 @@ static void test_plug_without_cpu_add(gconstpointer data) + s->sockets * s->cores * s->threads); + g_assert(response); + g_assert(qdict_haskey(response, "error")); +- QDECREF(response); ++ qobject_unref(response); + + qtest_end(); + g_free(args); +diff --git a/tests/device-introspect-test.c b/tests/device-introspect-test.c +index a01321a..0b4f221 100644 +--- a/tests/device-introspect-test.c ++++ b/tests/device-introspect-test.c +@@ -40,8 +40,8 @@ static QList *qom_list_types(const char *implements, bool abstract) + " 'arguments': %p }", args); + g_assert(qdict_haskey(resp, "return")); + ret = qdict_get_qlist(resp, "return"); +- QINCREF(ret); +- QDECREF(resp); ++ qobject_ref(ret); ++ qobject_unref(resp); + return ret; + } + +@@ -54,7 +54,7 @@ static QDict *qom_type_index(QList *types) + QLIST_FOREACH_ENTRY(types, e) { + QDict *d = qobject_to(QDict, qlist_entry_obj(e)); + const char *name = qdict_get_str(d, "name"); +- QINCREF(d); ++ qobject_ref(d); + qdict_put(index, name, d); + } + return index; +@@ -108,7 +108,7 @@ static void test_one_device(const char *type) + resp = qmp("{'execute': 'device-list-properties'," + " 'arguments': {'typename': %s}}", + type); +- QDECREF(resp); ++ qobject_unref(resp); + + help = hmp("device_add \"%s,help\"", type); + g_free(help); +@@ -129,7 +129,7 @@ static void test_device_intro_list(void) + qtest_start(common_args); + + types = device_type_list(true); +- QDECREF(types); ++ qobject_unref(types); + + help = hmp("device_add help"); + g_free(help); +@@ -157,8 +157,8 @@ static void test_qom_list_parents(const char *parent) + g_assert(qom_has_parent(index, name, parent)); + } + +- QDECREF(types); +- QDECREF(index); ++ qobject_unref(types); ++ qobject_unref(index); + } + + static void test_qom_list_fields(void) +@@ -187,8 +187,8 @@ static void test_qom_list_fields(void) + test_qom_list_parents("device"); + test_qom_list_parents("sys-bus-device"); + +- QDECREF(all_types); +- QDECREF(non_abstract); ++ qobject_unref(all_types); ++ qobject_unref(non_abstract); + qtest_end(); + } + +@@ -222,7 +222,7 @@ static void test_device_intro_concrete(void) + test_one_device(type); + } + +- QDECREF(types); ++ qobject_unref(types); + qtest_end(); + } + +@@ -255,8 +255,8 @@ static void test_abstract_interfaces(void) + g_assert(qdict_haskey(d, "abstract") && qdict_get_bool(d, "abstract")); + } + +- QDECREF(all_types); +- QDECREF(index); ++ qobject_unref(all_types); ++ qobject_unref(index); + qtest_end(); + } + +diff --git a/tests/drive_del-test.c b/tests/drive_del-test.c +index 313030a..852fefc 100644 +--- a/tests/drive_del-test.c ++++ b/tests/drive_del-test.c +@@ -41,7 +41,7 @@ static void device_del(void) + response = qmp_receive(); + g_assert(response); + g_assert(qdict_haskey(response, "return")); +- QDECREF(response); ++ qobject_unref(response); + } + + static void test_drive_without_dev(void) +@@ -78,7 +78,7 @@ static void test_after_failed_device_add(void) + g_assert(response); + error = qdict_get_qdict(response, "error"); + g_assert_cmpstr(qdict_get_try_str(error, "class"), ==, "GenericError"); +- QDECREF(response); ++ qobject_unref(response); + + /* Delete the drive */ + drive_del(); +diff --git a/tests/libqos/libqos.c b/tests/libqos/libqos.c +index 5124e98..013ca68 100644 +--- a/tests/libqos/libqos.c ++++ b/tests/libqos/libqos.c +@@ -100,14 +100,14 @@ void migrate(QOSState *from, QOSState *to, const char *uri) + sub = qdict_get_qdict(rsp, "return"); + g_assert(qdict_haskey(sub, "running")); + running = qdict_get_bool(sub, "running"); +- QDECREF(rsp); ++ qobject_unref(rsp); + + /* Issue the migrate command. */ + rsp = qtest_qmp(from->qts, + "{ 'execute': 'migrate', 'arguments': { 'uri': %s }}", + uri); + g_assert(qdict_haskey(rsp, "return")); +- QDECREF(rsp); ++ qobject_unref(rsp); + + /* Wait for STOP event, but only if we were running: */ + if (running) { +@@ -132,12 +132,12 @@ void migrate(QOSState *from, QOSState *to, const char *uri) + + /* "setup", "active", "completed", "failed", "cancelled" */ + if (strcmp(st, "completed") == 0) { +- QDECREF(rsp); ++ qobject_unref(rsp); + break; + } + + if ((strcmp(st, "setup") == 0) || (strcmp(st, "active") == 0)) { +- QDECREF(rsp); ++ qobject_unref(rsp); + g_usleep(5000); + continue; + } +diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c +index a2daf61..a780330 100644 +--- a/tests/libqos/pci-pc.c ++++ b/tests/libqos/pci-pc.c +@@ -170,7 +170,7 @@ void qpci_unplug_acpi_device_test(const char *id, uint8_t slot) + g_free(cmd); + g_assert(response); + g_assert(!qdict_haskey(response, "error")); +- QDECREF(response); ++ qobject_unref(response); + + outb(ACPI_PCIHP_ADDR + PCI_EJ_BASE, 1 << slot); + +diff --git a/tests/libqtest.c b/tests/libqtest.c +index 6f33a37..43fb97e 100644 +--- a/tests/libqtest.c ++++ b/tests/libqtest.c +@@ -517,8 +517,8 @@ void qmp_fd_sendv(int fd, const char *fmt, va_list ap) + /* Send QMP request */ + socket_send(fd, str, qstring_get_length(qstr)); + +- QDECREF(qstr); +- qobject_decref(qobj); ++ qobject_unref(qstr); ++ qobject_unref(qobj); + } + } + +@@ -585,7 +585,7 @@ void qtest_async_qmp(QTestState *s, const char *fmt, ...) + void qtest_qmpv_discard_response(QTestState *s, const char *fmt, va_list ap) + { + QDict *response = qtest_qmpv(s, fmt, ap); +- QDECREF(response); ++ qobject_unref(response); + } + + void qtest_qmp_discard_response(QTestState *s, const char *fmt, ...) +@@ -596,7 +596,7 @@ void qtest_qmp_discard_response(QTestState *s, const char *fmt, ...) + va_start(ap, fmt); + response = qtest_qmpv(s, fmt, ap); + va_end(ap); +- QDECREF(response); ++ qobject_unref(response); + } + + QDict *qtest_qmp_eventwait_ref(QTestState *s, const char *event) +@@ -609,7 +609,7 @@ QDict *qtest_qmp_eventwait_ref(QTestState *s, const char *event) + (strcmp(qdict_get_str(response, "event"), event) == 0)) { + return response; + } +- QDECREF(response); ++ qobject_unref(response); + } + } + +@@ -618,7 +618,7 @@ void qtest_qmp_eventwait(QTestState *s, const char *event) + QDict *response; + + response = qtest_qmp_eventwait_ref(s, event); +- QDECREF(response); ++ qobject_unref(response); + } + + char *qtest_hmpv(QTestState *s, const char *fmt, va_list ap) +@@ -634,12 +634,12 @@ char *qtest_hmpv(QTestState *s, const char *fmt, va_list ap) + ret = g_strdup(qdict_get_try_str(resp, "return")); + while (ret == NULL && qdict_get_try_str(resp, "event")) { + /* Ignore asynchronous QMP events */ +- QDECREF(resp); ++ qobject_unref(resp); + resp = qtest_qmp_receive(s); + ret = g_strdup(qdict_get_try_str(resp, "return")); + } + g_assert(ret); +- QDECREF(resp); ++ qobject_unref(resp); + g_free(cmd); + return ret; + } +@@ -1021,7 +1021,7 @@ void qtest_cb_for_every_machine(void (*cb)(const char *machine)) + } + + qtest_end(); +- QDECREF(response); ++ qobject_unref(response); + } + + /* +@@ -1050,7 +1050,7 @@ void qtest_qmp_device_add(const char *driver, const char *id, const char *fmt, + g_assert(response); + g_assert(!qdict_haskey(response, "event")); /* We don't expect any events */ + g_assert(!qdict_haskey(response, "error")); +- QDECREF(response); ++ qobject_unref(response); + } + + /* +@@ -1095,6 +1095,6 @@ void qtest_qmp_device_del(const char *id) + g_assert(event); + g_assert_cmpstr(qdict_get_str(event, "event"), ==, "DEVICE_DELETED"); + +- QDECREF(response1); +- QDECREF(response2); ++ qobject_unref(response1); ++ qobject_unref(response2); + } +diff --git a/tests/machine-none-test.c b/tests/machine-none-test.c +index efdd4be..f286557 100644 +--- a/tests/machine-none-test.c ++++ b/tests/machine-none-test.c +@@ -88,7 +88,7 @@ static void test_machine_cpu_cli(void) + + response = qmp("{ 'execute': 'quit' }"); + g_assert(qdict_haskey(response, "return")); +- QDECREF(response); ++ qobject_unref(response); + + qtest_quit(global_qtest); + } +diff --git a/tests/migration-test.c b/tests/migration-test.c +index 422bf1a..0acd715 100644 +--- a/tests/migration-test.c ++++ b/tests/migration-test.c +@@ -193,7 +193,7 @@ static QDict *wait_command(QTestState *who, const char *command) + if (!strcmp(event_string, "STOP")) { + got_stop = true; + } +- QDECREF(response); ++ qobject_unref(response); + response = qtest_qmp_receive(who); + } + return response; +@@ -219,7 +219,7 @@ static uint64_t get_migration_pass(QTestState *who) + rsp_ram = qdict_get_qdict(rsp_return, "ram"); + result = qdict_get_try_int(rsp_ram, "dirty-sync-count", 0); + } +- QDECREF(rsp); ++ qobject_unref(rsp); + return result; + } + +@@ -235,7 +235,7 @@ static void wait_for_migration_complete(QTestState *who) + status = qdict_get_str(rsp_return, "status"); + completed = strcmp(status, "completed") == 0; + g_assert_cmpstr(status, !=, "failed"); +- QDECREF(rsp); ++ qobject_unref(rsp); + if (completed) { + return; + } +@@ -322,7 +322,7 @@ static void migrate_check_parameter(QTestState *who, const char *parameter, + qdict_get_try_int(rsp_return, parameter, -1)); + g_assert_cmpstr(result, ==, value); + g_free(result); +- QDECREF(rsp); ++ qobject_unref(rsp); + } + + static void migrate_set_parameter(QTestState *who, const char *parameter, +@@ -337,7 +337,7 @@ static void migrate_set_parameter(QTestState *who, const char *parameter, + rsp = qtest_qmp(who, cmd); + g_free(cmd); + g_assert(qdict_haskey(rsp, "return")); +- QDECREF(rsp); ++ qobject_unref(rsp); + migrate_check_parameter(who, parameter, value); + } + +@@ -355,7 +355,7 @@ static void migrate_set_capability(QTestState *who, const char *capability, + rsp = qtest_qmp(who, cmd); + g_free(cmd); + g_assert(qdict_haskey(rsp, "return")); +- QDECREF(rsp); ++ qobject_unref(rsp); + } + + static void migrate(QTestState *who, const char *uri) +@@ -369,7 +369,7 @@ static void migrate(QTestState *who, const char *uri) + rsp = qtest_qmp(who, cmd); + g_free(cmd); + g_assert(qdict_haskey(rsp, "return")); +- QDECREF(rsp); ++ qobject_unref(rsp); + } + + static void migrate_start_postcopy(QTestState *who) +@@ -378,7 +378,7 @@ static void migrate_start_postcopy(QTestState *who) + + rsp = wait_command(who, "{ 'execute': 'migrate-start-postcopy' }"); + g_assert(qdict_haskey(rsp, "return")); +- QDECREF(rsp); ++ qobject_unref(rsp); + } + + static void test_migrate_start(QTestState **from, QTestState **to, +@@ -491,7 +491,7 @@ static void deprecated_set_downtime(QTestState *who, const double value) + rsp = qtest_qmp(who, cmd); + g_free(cmd); + g_assert(qdict_haskey(rsp, "return")); +- QDECREF(rsp); ++ qobject_unref(rsp); + result_int = value * 1000L; + expected = g_strdup_printf("%" PRId64, result_int); + migrate_check_parameter(who, "downtime-limit", expected); +@@ -508,7 +508,7 @@ static void deprecated_set_speed(QTestState *who, const char *value) + rsp = qtest_qmp(who, cmd); + g_free(cmd); + g_assert(qdict_haskey(rsp, "return")); +- QDECREF(rsp); ++ qobject_unref(rsp); + migrate_check_parameter(who, "max-bandwidth", value); + } + +@@ -581,7 +581,7 @@ static void test_baddest(void) + + g_assert(!strcmp(status, "setup") || !(strcmp(status, "failed"))); + failed = !strcmp(status, "failed"); +- QDECREF(rsp); ++ qobject_unref(rsp); + } while (!failed); + + /* Is the machine currently running? */ +@@ -590,7 +590,7 @@ static void test_baddest(void) + rsp_return = qdict_get_qdict(rsp, "return"); + g_assert(qdict_haskey(rsp_return, "running")); + g_assert(qdict_get_bool(rsp_return, "running")); +- QDECREF(rsp); ++ qobject_unref(rsp); + + test_migrate_end(from, to, false); + } +diff --git a/tests/numa-test.c b/tests/numa-test.c +index 0f861d8..169213f 100644 +--- a/tests/numa-test.c ++++ b/tests/numa-test.c +@@ -111,10 +111,10 @@ static void test_query_cpus(const void *data) + } else { + g_assert_cmpint(node, ==, 1); + } +- qobject_decref(e); ++ qobject_unref(e); + } + +- QDECREF(resp); ++ qobject_unref(resp); + qtest_end(); + g_free(cli); + } +@@ -164,10 +164,10 @@ static void pc_numa_cpu(const void *data) + } else { + g_assert(false); + } +- qobject_decref(e); ++ qobject_unref(e); + } + +- QDECREF(resp); ++ qobject_unref(resp); + qtest_end(); + g_free(cli); + } +@@ -209,10 +209,10 @@ static void spapr_numa_cpu(const void *data) + } else { + g_assert(false); + } +- qobject_decref(e); ++ qobject_unref(e); + } + +- QDECREF(resp); ++ qobject_unref(resp); + qtest_end(); + g_free(cli); + } +@@ -252,10 +252,10 @@ static void aarch64_numa_cpu(const void *data) + } else { + g_assert(false); + } +- qobject_decref(e); ++ qobject_unref(e); + } + +- QDECREF(resp); ++ qobject_unref(resp); + qtest_end(); + g_free(cli); + } +diff --git a/tests/pvpanic-test.c b/tests/pvpanic-test.c +index ebdf32c..7461a72 100644 +--- a/tests/pvpanic-test.c ++++ b/tests/pvpanic-test.c +@@ -28,7 +28,7 @@ static void test_panic(void) + data = qdict_get_qdict(response, "data"); + g_assert(qdict_haskey(data, "action")); + g_assert_cmpstr(qdict_get_str(data, "action"), ==, "pause"); +- QDECREF(response); ++ qobject_unref(response); + } + + int main(int argc, char **argv) +diff --git a/tests/q35-test.c b/tests/q35-test.c +index 3eaedf4..7ea7acc 100644 +--- a/tests/q35-test.c ++++ b/tests/q35-test.c +@@ -109,7 +109,7 @@ static void test_smram_lock(void) + response = qmp("{'execute': 'system_reset', 'arguments': {} }"); + g_assert(response); + g_assert(!qdict_haskey(response, "error")); +- QDECREF(response); ++ qobject_unref(response); + + /* check open is settable again */ + smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, false); +diff --git a/tests/qmp-test.c b/tests/qmp-test.c +index f34428e..3a5c42e 100644 +--- a/tests/qmp-test.c ++++ b/tests/qmp-test.c +@@ -52,27 +52,27 @@ static void test_malformed(QTestState *qts) + /* Not even a dictionary */ + resp = qtest_qmp(qts, "null"); + g_assert_cmpstr(get_error_class(resp), ==, "GenericError"); +- QDECREF(resp); ++ qobject_unref(resp); + + /* No "execute" key */ + resp = qtest_qmp(qts, "{}"); + g_assert_cmpstr(get_error_class(resp), ==, "GenericError"); +- QDECREF(resp); ++ qobject_unref(resp); + + /* "execute" isn't a string */ + resp = qtest_qmp(qts, "{ 'execute': true }"); + g_assert_cmpstr(get_error_class(resp), ==, "GenericError"); +- QDECREF(resp); ++ qobject_unref(resp); + + /* "arguments" isn't a dictionary */ + resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd', 'arguments': [] }"); + g_assert_cmpstr(get_error_class(resp), ==, "GenericError"); +- QDECREF(resp); ++ qobject_unref(resp); + + /* extra key */ + resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd', 'extra': true }"); + g_assert_cmpstr(get_error_class(resp), ==, "GenericError"); +- QDECREF(resp); ++ qobject_unref(resp); + } + + static void test_qmp_protocol(void) +@@ -90,12 +90,12 @@ static void test_qmp_protocol(void) + test_version(qdict_get(q, "version")); + capabilities = qdict_get_qlist(q, "capabilities"); + g_assert(capabilities && qlist_empty(capabilities)); +- QDECREF(resp); ++ qobject_unref(resp); + + /* Test valid command before handshake */ + resp = qtest_qmp(qts, "{ 'execute': 'query-version' }"); + g_assert_cmpstr(get_error_class(resp), ==, "CommandNotFound"); +- QDECREF(resp); ++ qobject_unref(resp); + + /* Test malformed commands before handshake */ + test_malformed(qts); +@@ -104,17 +104,17 @@ static void test_qmp_protocol(void) + resp = qtest_qmp(qts, "{ 'execute': 'qmp_capabilities' }"); + ret = qdict_get_qdict(resp, "return"); + g_assert(ret && !qdict_size(ret)); +- QDECREF(resp); ++ qobject_unref(resp); + + /* Test repeated handshake */ + resp = qtest_qmp(qts, "{ 'execute': 'qmp_capabilities' }"); + g_assert_cmpstr(get_error_class(resp), ==, "CommandNotFound"); +- QDECREF(resp); ++ qobject_unref(resp); + + /* Test valid command */ + resp = qtest_qmp(qts, "{ 'execute': 'query-version' }"); + test_version(qdict_get(resp, "return")); +- QDECREF(resp); ++ qobject_unref(resp); + + /* Test malformed commands */ + test_malformed(qts); +@@ -124,13 +124,13 @@ static void test_qmp_protocol(void) + ret = qdict_get_qdict(resp, "return"); + g_assert(ret); + g_assert_cmpstr(qdict_get_try_str(resp, "id"), ==, "cookie#1"); +- QDECREF(resp); ++ qobject_unref(resp); + + /* Test command failure with 'id' */ + resp = qtest_qmp(qts, "{ 'execute': 'human-monitor-command', 'id': 2 }"); + g_assert_cmpstr(get_error_class(resp), ==, "GenericError"); + g_assert_cmpint(qdict_get_int(resp, "id"), ==, 2); +- QDECREF(resp); ++ qobject_unref(resp); + + qtest_quit(qts); + } +@@ -159,21 +159,21 @@ static void test_qmp_oob(void) + qstr = qobject_to(QString, entry->value); + g_assert(qstr); + g_assert_cmpstr(qstring_get_str(qstr), ==, "oob"); +- QDECREF(resp); ++ qobject_unref(resp); + + /* Try a fake capability, it should fail. */ + resp = qtest_qmp(qts, + "{ 'execute': 'qmp_capabilities', " + " 'arguments': { 'enable': [ 'cap-does-not-exist' ] } }"); + g_assert(qdict_haskey(resp, "error")); +- QDECREF(resp); ++ qobject_unref(resp); + + /* Now, enable OOB in current QMP session, it should succeed. */ + resp = qtest_qmp(qts, + "{ 'execute': 'qmp_capabilities', " + " 'arguments': { 'enable': [ 'oob' ] } }"); + g_assert(qdict_haskey(resp, "return")); +- QDECREF(resp); ++ qobject_unref(resp); + + /* + * Try any command that does not support OOB but with OOB flag. We +@@ -183,7 +183,7 @@ static void test_qmp_oob(void) + "{ 'execute': 'query-cpus'," + " 'control': { 'run-oob': true } }"); + g_assert(qdict_haskey(resp, "error")); +- QDECREF(resp); ++ qobject_unref(resp); + + /* + * First send the "x-oob-test" command with lock=true and +@@ -210,7 +210,7 @@ static void test_qmp_oob(void) + !g_strcmp0(cmd_id, "unlock-cmd")) { + acks++; + } +- QDECREF(resp); ++ qobject_unref(resp); + } + + qtest_quit(qts); +@@ -274,7 +274,7 @@ static void test_query(const void *data) + -1, &error_abort), + ==, expected_error_class); + } +- QDECREF(resp); ++ qobject_unref(resp); + + qtest_end(); + } +@@ -324,7 +324,7 @@ static void qmp_schema_init(QmpSchema *schema) + visit_type_SchemaInfoList(qiv, NULL, &schema->list, &error_abort); + visit_free(qiv); + +- QDECREF(resp); ++ qobject_unref(resp); + qtest_end(); + + schema->hash = g_hash_table_new(g_str_hash, g_str_equal); +diff --git a/tests/qom-test.c b/tests/qom-test.c +index db0d3ab..5bf3921 100644 +--- a/tests/qom-test.c ++++ b/tests/qom-test.c +@@ -59,7 +59,7 @@ static void test_properties(const char *path, bool recurse) + g_assert(response); + + if (!recurse) { +- QDECREF(response); ++ qobject_unref(response); + return; + } + +@@ -84,10 +84,10 @@ static void test_properties(const char *path, bool recurse) + path, prop); + /* qom-get may fail but should not, e.g., segfault. */ + g_assert(tmp); +- QDECREF(tmp); ++ qobject_unref(tmp); + } + } +- QDECREF(response); ++ qobject_unref(response); + } + + static void test_machine(gconstpointer data) +@@ -103,7 +103,7 @@ static void test_machine(gconstpointer data) + + response = qmp("{ 'execute': 'quit' }"); + g_assert(qdict_haskey(response, "return")); +- QDECREF(response); ++ qobject_unref(response); + + qtest_end(); + g_free(args); +diff --git a/tests/tco-test.c b/tests/tco-test.c +index aee17af..9945fb8 100644 +--- a/tests/tco-test.c ++++ b/tests/tco-test.c +@@ -241,8 +241,8 @@ static QDict *get_watchdog_action(void) + QDict *data; + + data = qdict_get_qdict(ev, "data"); +- QINCREF(data); +- QDECREF(ev); ++ qobject_ref(data); ++ qobject_unref(ev); + return data; + } + +@@ -265,7 +265,7 @@ static void test_tco_second_timeout_pause(void) + clock_step(ticks * TCO_TICK_NSEC * 2); + ad = get_watchdog_action(); + g_assert(!strcmp(qdict_get_str(ad, "action"), "pause")); +- QDECREF(ad); ++ qobject_unref(ad); + + stop_tco(&td); + test_end(&td); +@@ -290,7 +290,7 @@ static void test_tco_second_timeout_reset(void) + clock_step(ticks * TCO_TICK_NSEC * 2); + ad = get_watchdog_action(); + g_assert(!strcmp(qdict_get_str(ad, "action"), "reset")); +- QDECREF(ad); ++ qobject_unref(ad); + + stop_tco(&td); + test_end(&td); +@@ -315,7 +315,7 @@ static void test_tco_second_timeout_shutdown(void) + clock_step(ticks * TCO_TICK_NSEC * 2); + ad = get_watchdog_action(); + g_assert(!strcmp(qdict_get_str(ad, "action"), "shutdown")); +- QDECREF(ad); ++ qobject_unref(ad); + + stop_tco(&td); + test_end(&td); +@@ -340,7 +340,7 @@ static void test_tco_second_timeout_none(void) + clock_step(ticks * TCO_TICK_NSEC * 2); + ad = get_watchdog_action(); + g_assert(!strcmp(qdict_get_str(ad, "action"), "none")); +- QDECREF(ad); ++ qobject_unref(ad); + + stop_tco(&td); + test_end(&td); +diff --git a/tests/test-char.c b/tests/test-char.c +index 306c728..1880d36 100644 +--- a/tests/test-char.c ++++ b/tests/test-char.c +@@ -322,7 +322,7 @@ static void char_socket_test_common(Chardev *chr) + qdict = qobject_to(QDict, addr); + port = qdict_get_str(qdict, "port"); + tmp = g_strdup_printf("tcp:127.0.0.1:%s", port); +- QDECREF(qdict); ++ qobject_unref(qdict); + + qemu_chr_fe_init(&be, chr, &error_abort); + qemu_chr_fe_set_handlers(&be, socket_can_read, socket_read, +diff --git a/tests/test-keyval.c b/tests/test-keyval.c +index 029f052..63cb146 100644 +--- a/tests/test-keyval.c ++++ b/tests/test-keyval.c +@@ -30,7 +30,7 @@ static void test_keyval_parse(void) + /* Nothing */ + qdict = keyval_parse("", NULL, &error_abort); + g_assert_cmpuint(qdict_size(qdict), ==, 0); +- QDECREF(qdict); ++ qobject_unref(qdict); + + /* Empty key (qemu_opts_parse() accepts this) */ + qdict = keyval_parse("=val", NULL, &err); +@@ -70,7 +70,7 @@ static void test_keyval_parse(void) + qdict = keyval_parse(params + 2, NULL, &error_abort); + g_assert_cmpuint(qdict_size(qdict), ==, 1); + g_assert_cmpstr(qdict_get_try_str(qdict, long_key + 1), ==, "v"); +- QDECREF(qdict); ++ qobject_unref(qdict); + + /* Long key fragment */ + qdict = keyval_parse(params, NULL, &error_abort); +@@ -79,7 +79,7 @@ static void test_keyval_parse(void) + g_assert(sub_qdict); + g_assert_cmpuint(qdict_size(sub_qdict), ==, 1); + g_assert_cmpstr(qdict_get_try_str(sub_qdict, long_key + 1), ==, "v"); +- QDECREF(qdict); ++ qobject_unref(qdict); + g_free(params); + + /* Crap after valid key */ +@@ -92,13 +92,13 @@ static void test_keyval_parse(void) + g_assert_cmpuint(qdict_size(qdict), ==, 2); + g_assert_cmpstr(qdict_get_try_str(qdict, "a"), ==, "3"); + g_assert_cmpstr(qdict_get_try_str(qdict, "b"), ==, "2,x"); +- QDECREF(qdict); ++ qobject_unref(qdict); + + /* Even when it doesn't in qemu_opts_parse() */ + qdict = keyval_parse("id=foo,id=bar", NULL, &error_abort); + g_assert_cmpuint(qdict_size(qdict), ==, 1); + g_assert_cmpstr(qdict_get_try_str(qdict, "id"), ==, "bar"); +- QDECREF(qdict); ++ qobject_unref(qdict); + + /* Dotted keys */ + qdict = keyval_parse("a.b.c=1,a.b.c=2,d=3", NULL, &error_abort); +@@ -111,7 +111,7 @@ static void test_keyval_parse(void) + g_assert_cmpuint(qdict_size(sub_qdict), ==, 1); + g_assert_cmpstr(qdict_get_try_str(sub_qdict, "c"), ==, "2"); + g_assert_cmpstr(qdict_get_try_str(qdict, "d"), ==, "3"); +- QDECREF(qdict); ++ qobject_unref(qdict); + + /* Inconsistent dotted keys */ + qdict = keyval_parse("a.b=1,a=2", NULL, &err); +@@ -125,7 +125,7 @@ static void test_keyval_parse(void) + qdict = keyval_parse("x=y,", NULL, &error_abort); + g_assert_cmpuint(qdict_size(qdict), ==, 1); + g_assert_cmpstr(qdict_get_try_str(qdict, "x"), ==, "y"); +- QDECREF(qdict); ++ qobject_unref(qdict); + + /* Except when it isn't */ + qdict = keyval_parse(",", NULL, &err); +@@ -136,13 +136,13 @@ static void test_keyval_parse(void) + qdict = keyval_parse("x=,,id=bar", NULL, &error_abort); + g_assert_cmpuint(qdict_size(qdict), ==, 1); + g_assert_cmpstr(qdict_get_try_str(qdict, "x"), ==, ",id=bar"); +- QDECREF(qdict); ++ qobject_unref(qdict); + + /* Anti-social ID is left to caller (qemu_opts_parse() rejects it) */ + qdict = keyval_parse("id=666", NULL, &error_abort); + g_assert_cmpuint(qdict_size(qdict), ==, 1); + g_assert_cmpstr(qdict_get_try_str(qdict, "id"), ==, "666"); +- QDECREF(qdict); ++ qobject_unref(qdict); + + /* Implied value not supported (unlike qemu_opts_parse()) */ + qdict = keyval_parse("an,noaus,noaus=", NULL, &err); +@@ -160,7 +160,7 @@ static void test_keyval_parse(void) + g_assert_cmpstr(qdict_get_try_str(qdict, "implied"), ==, "an"); + g_assert_cmpstr(qdict_get_try_str(qdict, "aus"), ==, "off"); + g_assert_cmpstr(qdict_get_try_str(qdict, "noaus"), ==, ""); +- QDECREF(qdict); ++ qobject_unref(qdict); + + /* Implied dotted key */ + qdict = keyval_parse("val", "eins.zwei", &error_abort); +@@ -169,7 +169,7 @@ static void test_keyval_parse(void) + g_assert(sub_qdict); + g_assert_cmpuint(qdict_size(sub_qdict), ==, 1); + g_assert_cmpstr(qdict_get_try_str(sub_qdict, "zwei"), ==, "val"); +- QDECREF(qdict); ++ qobject_unref(qdict); + + /* Implied key with empty value (qemu_opts_parse() accepts this) */ + qdict = keyval_parse(",", "implied", &err); +@@ -198,7 +198,7 @@ static void check_list012(QList *qlist) + qstr = qobject_to(QString, qlist_pop(qlist)); + g_assert(qstr); + g_assert_cmpstr(qstring_get_str(qstr), ==, expected[i]); +- QDECREF(qstr); ++ qobject_unref(qstr); + } + g_assert(qlist_empty(qlist)); + } +@@ -218,14 +218,14 @@ static void test_keyval_parse_list(void) + NULL, &error_abort); + g_assert_cmpint(qdict_size(qdict), ==, 1); + check_list012(qdict_get_qlist(qdict, "list")); +- QDECREF(qdict); ++ qobject_unref(qdict); + + /* Multiple indexes, last one wins */ + qdict = keyval_parse("list.1=goner,list.0=null,list.01=eins,list.2=zwei", + NULL, &error_abort); + g_assert_cmpint(qdict_size(qdict), ==, 1); + check_list012(qdict_get_qlist(qdict, "list")); +- QDECREF(qdict); ++ qobject_unref(qdict); + + /* List at deeper nesting */ + qdict = keyval_parse("a.list.1=eins,a.list.00=null,a.list.2=zwei", +@@ -234,7 +234,7 @@ static void test_keyval_parse_list(void) + sub_qdict = qdict_get_qdict(qdict, "a"); + g_assert_cmpint(qdict_size(sub_qdict), ==, 1); + check_list012(qdict_get_qlist(sub_qdict, "list")); +- QDECREF(qdict); ++ qobject_unref(qdict); + + /* Inconsistent dotted keys: both list and dictionary */ + qdict = keyval_parse("a.b.c=1,a.b.0=2", NULL, &err); +@@ -262,7 +262,7 @@ static void test_keyval_visit_bool(void) + + qdict = keyval_parse("bool1=on,bool2=off", NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); +- QDECREF(qdict); ++ qobject_unref(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_bool(v, "bool1", &b, &error_abort); + g_assert(b); +@@ -274,7 +274,7 @@ static void test_keyval_visit_bool(void) + + qdict = keyval_parse("bool1=offer", NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); +- QDECREF(qdict); ++ qobject_unref(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_bool(v, "bool1", &b, &err); + error_free_or_abort(&err); +@@ -292,7 +292,7 @@ static void test_keyval_visit_number(void) + /* Lower limit zero */ + qdict = keyval_parse("number1=0", NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); +- QDECREF(qdict); ++ qobject_unref(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_uint64(v, "number1", &u, &error_abort); + g_assert_cmpuint(u, ==, 0); +@@ -304,7 +304,7 @@ static void test_keyval_visit_number(void) + qdict = keyval_parse("number1=18446744073709551615,number2=-1", + NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); +- QDECREF(qdict); ++ qobject_unref(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_uint64(v, "number1", &u, &error_abort); + g_assert_cmphex(u, ==, UINT64_MAX); +@@ -318,7 +318,7 @@ static void test_keyval_visit_number(void) + qdict = keyval_parse("number1=18446744073709551616", + NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); +- QDECREF(qdict); ++ qobject_unref(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_uint64(v, "number1", &u, &err); + error_free_or_abort(&err); +@@ -329,7 +329,7 @@ static void test_keyval_visit_number(void) + qdict = keyval_parse("number1=-18446744073709551616", + NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); +- QDECREF(qdict); ++ qobject_unref(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_uint64(v, "number1", &u, &err); + error_free_or_abort(&err); +@@ -340,7 +340,7 @@ static void test_keyval_visit_number(void) + qdict = keyval_parse("number1=0x2a,number2=052", + NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); +- QDECREF(qdict); ++ qobject_unref(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_uint64(v, "number1", &u, &error_abort); + g_assert_cmpuint(u, ==, 42); +@@ -354,7 +354,7 @@ static void test_keyval_visit_number(void) + qdict = keyval_parse("number1=3.14,number2=08", + NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); +- QDECREF(qdict); ++ qobject_unref(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_uint64(v, "number1", &u, &err); + error_free_or_abort(&err); +@@ -374,7 +374,7 @@ static void test_keyval_visit_size(void) + /* Lower limit zero */ + qdict = keyval_parse("sz1=0", NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); +- QDECREF(qdict); ++ qobject_unref(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_size(v, "sz1", &sz, &error_abort); + g_assert_cmpuint(sz, ==, 0); +@@ -390,7 +390,7 @@ static void test_keyval_visit_size(void) + "sz3=9007199254740993", + NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); +- QDECREF(qdict); ++ qobject_unref(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_size(v, "sz1", &sz, &error_abort); + g_assert_cmphex(sz, ==, 0x1fffffffffffff); +@@ -407,7 +407,7 @@ static void test_keyval_visit_size(void) + "sz2=9223372036854775295", /* 7ffffffffffffdff */ + NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); +- QDECREF(qdict); ++ qobject_unref(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_size(v, "sz1", &sz, &error_abort); + g_assert_cmphex(sz, ==, 0x7ffffffffffffc00); +@@ -422,7 +422,7 @@ static void test_keyval_visit_size(void) + "sz2=18446744073709550591", /* fffffffffffffbff */ + NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); +- QDECREF(qdict); ++ qobject_unref(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_size(v, "sz1", &sz, &error_abort); + g_assert_cmphex(sz, ==, 0xfffffffffffff800); +@@ -437,7 +437,7 @@ static void test_keyval_visit_size(void) + "sz2=18446744073709550592", /* fffffffffffffc00 */ + NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); +- QDECREF(qdict); ++ qobject_unref(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_size(v, "sz1", &sz, &err); + error_free_or_abort(&err); +@@ -450,7 +450,7 @@ static void test_keyval_visit_size(void) + qdict = keyval_parse("sz1=8b,sz2=1.5k,sz3=2M,sz4=0.1G,sz5=16777215T", + NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); +- QDECREF(qdict); ++ qobject_unref(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_size(v, "sz1", &sz, &error_abort); + g_assert_cmpuint(sz, ==, 8); +@@ -469,7 +469,7 @@ static void test_keyval_visit_size(void) + /* Beyond limit with suffix */ + qdict = keyval_parse("sz1=16777216T", NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); +- QDECREF(qdict); ++ qobject_unref(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_size(v, "sz1", &sz, &err); + error_free_or_abort(&err); +@@ -479,7 +479,7 @@ static void test_keyval_visit_size(void) + /* Trailing crap */ + qdict = keyval_parse("sz1=16E,sz2=16Gi", NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); +- QDECREF(qdict); ++ qobject_unref(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_size(v, "sz1", &sz, &err); + error_free_or_abort(&err); +@@ -498,7 +498,7 @@ static void test_keyval_visit_dict(void) + + qdict = keyval_parse("a.b.c=1,a.b.c=2,d=3", NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); +- QDECREF(qdict); ++ qobject_unref(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_start_struct(v, "a", NULL, 0, &error_abort); + visit_start_struct(v, "b", NULL, 0, &error_abort); +@@ -516,7 +516,7 @@ static void test_keyval_visit_dict(void) + + qdict = keyval_parse("a.b=", NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); +- QDECREF(qdict); ++ qobject_unref(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_start_struct(v, "a", NULL, 0, &error_abort); + visit_type_int(v, "c", &i, &err); /* a.c missing */ +@@ -539,7 +539,7 @@ static void test_keyval_visit_list(void) + qdict = keyval_parse("a.0=,a.1=I,a.2.0=II", NULL, &error_abort); + /* TODO empty list */ + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); +- QDECREF(qdict); ++ qobject_unref(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_start_list(v, "a", NULL, 0, &error_abort); + visit_type_str(v, NULL, &s, &error_abort); +@@ -562,7 +562,7 @@ static void test_keyval_visit_list(void) + + qdict = keyval_parse("a.0=,b.0.0=head", NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); +- QDECREF(qdict); ++ qobject_unref(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_start_list(v, "a", NULL, 0, &error_abort); + visit_check_list(v, &err); /* a[0] unexpected */ +@@ -591,7 +591,7 @@ static void test_keyval_visit_optional(void) + + qdict = keyval_parse("a.b=1", NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); +- QDECREF(qdict); ++ qobject_unref(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_optional(v, "b", &present); + g_assert(!present); /* b missing */ +@@ -627,7 +627,7 @@ static void test_keyval_visit_alternate(void) + */ + qdict = keyval_parse("a=1,b=2,c=on", NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); +- QDECREF(qdict); ++ qobject_unref(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_AltStrObj(v, "a", &aso, &error_abort); + g_assert_cmpint(aso->type, ==, QTYPE_QSTRING); +@@ -651,19 +651,19 @@ static void test_keyval_visit_any(void) + + qdict = keyval_parse("a.0=null,a.1=1", NULL, &error_abort); + v = qobject_input_visitor_new_keyval(QOBJECT(qdict)); +- QDECREF(qdict); ++ qobject_unref(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_any(v, "a", &any, &error_abort); + qlist = qobject_to(QList, any); + g_assert(qlist); + qstr = qobject_to(QString, qlist_pop(qlist)); + g_assert_cmpstr(qstring_get_str(qstr), ==, "null"); +- QDECREF(qstr); ++ qobject_unref(qstr); + qstr = qobject_to(QString, qlist_pop(qlist)); + g_assert_cmpstr(qstring_get_str(qstr), ==, "1"); + g_assert(qlist_empty(qlist)); +- QDECREF(qstr); +- qobject_decref(any); ++ qobject_unref(qstr); ++ qobject_unref(any); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_free(v); +diff --git a/tests/test-netfilter.c b/tests/test-netfilter.c +index 95f7839..e47075d 100644 +--- a/tests/test-netfilter.c ++++ b/tests/test-netfilter.c +@@ -29,7 +29,7 @@ static void add_one_netfilter(void) + + g_assert(response); + g_assert(!qdict_haskey(response, "error")); +- QDECREF(response); ++ qobject_unref(response); + + response = qmp("{'execute': 'object-del'," + " 'arguments': {" +@@ -37,7 +37,7 @@ static void add_one_netfilter(void) + "}}"); + g_assert(response); + g_assert(!qdict_haskey(response, "error")); +- QDECREF(response); ++ qobject_unref(response); + } + + /* add a netfilter to a netdev and then remove the netdev */ +@@ -57,7 +57,7 @@ static void remove_netdev_with_one_netfilter(void) + + g_assert(response); + g_assert(!qdict_haskey(response, "error")); +- QDECREF(response); ++ qobject_unref(response); + + response = qmp("{'execute': 'netdev_del'," + " 'arguments': {" +@@ -65,7 +65,7 @@ static void remove_netdev_with_one_netfilter(void) + "}}"); + g_assert(response); + g_assert(!qdict_haskey(response, "error")); +- QDECREF(response); ++ qobject_unref(response); + + /* add back the netdev */ + response = qmp("{'execute': 'netdev_add'," +@@ -75,7 +75,7 @@ static void remove_netdev_with_one_netfilter(void) + "}}"); + g_assert(response); + g_assert(!qdict_haskey(response, "error")); +- QDECREF(response); ++ qobject_unref(response); + } + + /* add multi(2) netfilters to a netdev and then remove them */ +@@ -95,7 +95,7 @@ static void add_multi_netfilter(void) + + g_assert(response); + g_assert(!qdict_haskey(response, "error")); +- QDECREF(response); ++ qobject_unref(response); + + response = qmp("{'execute': 'object-add'," + " 'arguments': {" +@@ -109,7 +109,7 @@ static void add_multi_netfilter(void) + + g_assert(response); + g_assert(!qdict_haskey(response, "error")); +- QDECREF(response); ++ qobject_unref(response); + + response = qmp("{'execute': 'object-del'," + " 'arguments': {" +@@ -117,7 +117,7 @@ static void add_multi_netfilter(void) + "}}"); + g_assert(response); + g_assert(!qdict_haskey(response, "error")); +- QDECREF(response); ++ qobject_unref(response); + + response = qmp("{'execute': 'object-del'," + " 'arguments': {" +@@ -125,7 +125,7 @@ static void add_multi_netfilter(void) + "}}"); + g_assert(response); + g_assert(!qdict_haskey(response, "error")); +- QDECREF(response); ++ qobject_unref(response); + } + + /* add multi(2) netfilters to a netdev and then remove the netdev */ +@@ -145,7 +145,7 @@ static void remove_netdev_with_multi_netfilter(void) + + g_assert(response); + g_assert(!qdict_haskey(response, "error")); +- QDECREF(response); ++ qobject_unref(response); + + response = qmp("{'execute': 'object-add'," + " 'arguments': {" +@@ -159,7 +159,7 @@ static void remove_netdev_with_multi_netfilter(void) + + g_assert(response); + g_assert(!qdict_haskey(response, "error")); +- QDECREF(response); ++ qobject_unref(response); + + response = qmp("{'execute': 'netdev_del'," + " 'arguments': {" +@@ -167,7 +167,7 @@ static void remove_netdev_with_multi_netfilter(void) + "}}"); + g_assert(response); + g_assert(!qdict_haskey(response, "error")); +- QDECREF(response); ++ qobject_unref(response); + + /* add back the netdev */ + response = qmp("{'execute': 'netdev_add'," +@@ -177,7 +177,7 @@ static void remove_netdev_with_multi_netfilter(void) + "}}"); + g_assert(response); + g_assert(!qdict_haskey(response, "error")); +- QDECREF(response); ++ qobject_unref(response); + } + + int main(int argc, char **argv) +diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c +index 2c422ab..77dd72b 100644 +--- a/tests/test-qemu-opts.c ++++ b/tests/test-qemu-opts.c +@@ -887,7 +887,7 @@ static void test_opts_to_qdict_basic(void) + g_assert_cmpstr(qdict_get_str(dict, "number1"), ==, "42"); + g_assert_false(qdict_haskey(dict, "number2")); + +- QDECREF(dict); ++ qobject_unref(dict); + qemu_opts_del(opts); + } + +@@ -914,7 +914,7 @@ static void test_opts_to_qdict_filtered(void) + g_assert_cmpstr(qdict_get_str(dict, "number1"), ==, "42"); + g_assert_false(qdict_haskey(dict, "number2")); + g_assert_false(qdict_haskey(dict, "bool1")); +- QDECREF(dict); ++ qobject_unref(dict); + + dict = qemu_opts_to_qdict_filtered(opts, NULL, &opts_list_02, false); + g_assert(dict != NULL); +@@ -924,7 +924,7 @@ static void test_opts_to_qdict_filtered(void) + g_assert_false(qdict_haskey(dict, "str3")); + g_assert_false(qdict_haskey(dict, "number1")); + g_assert_false(qdict_haskey(dict, "number2")); +- QDECREF(dict); ++ qobject_unref(dict); + + /* Now delete converted options from opts */ + dict = qemu_opts_to_qdict_filtered(opts, NULL, &opts_list_01, true); +@@ -935,7 +935,7 @@ static void test_opts_to_qdict_filtered(void) + g_assert_cmpstr(qdict_get_str(dict, "number1"), ==, "42"); + g_assert_false(qdict_haskey(dict, "number2")); + g_assert_false(qdict_haskey(dict, "bool1")); +- QDECREF(dict); ++ qobject_unref(dict); + + dict = qemu_opts_to_qdict_filtered(opts, NULL, &opts_list_02, true); + g_assert(dict != NULL); +@@ -945,7 +945,7 @@ static void test_opts_to_qdict_filtered(void) + g_assert_false(qdict_haskey(dict, "str3")); + g_assert_false(qdict_haskey(dict, "number1")); + g_assert_false(qdict_haskey(dict, "number2")); +- QDECREF(dict); ++ qobject_unref(dict); + + g_assert_true(QTAILQ_EMPTY(&opts->head)); + +@@ -978,13 +978,13 @@ static void test_opts_to_qdict_duplicates(void) + dict = qemu_opts_to_qdict(opts, NULL); + g_assert(dict != NULL); + g_assert_cmpstr(qdict_get_str(dict, "foo"), ==, "b"); +- QDECREF(dict); ++ qobject_unref(dict); + + /* The last one still wins if entries are deleted, and both are deleted */ + dict = qemu_opts_to_qdict_filtered(opts, NULL, NULL, true); + g_assert(dict != NULL); + g_assert_cmpstr(qdict_get_str(dict, "foo"), ==, "b"); +- QDECREF(dict); ++ qobject_unref(dict); + + g_assert_true(QTAILQ_EMPTY(&opts->head)); + +diff --git a/tests/test-qga.c b/tests/test-qga.c +index e6ab788..18e63cb 100644 +--- a/tests/test-qga.c ++++ b/tests/test-qga.c +@@ -180,7 +180,7 @@ static void test_qga_sync_delimited(gconstpointer fix) + v = qdict_get_int(ret, "return"); + g_assert_cmpint(r, ==, v); + +- QDECREF(ret); ++ qobject_unref(ret); + } + + static void test_qga_sync(gconstpointer fix) +@@ -212,7 +212,7 @@ static void test_qga_sync(gconstpointer fix) + v = qdict_get_int(ret, "return"); + g_assert_cmpint(r, ==, v); + +- QDECREF(ret); ++ qobject_unref(ret); + } + + static void test_qga_ping(gconstpointer fix) +@@ -224,7 +224,7 @@ static void test_qga_ping(gconstpointer fix) + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + +- QDECREF(ret); ++ qobject_unref(ret); + } + + static void test_qga_invalid_args(gconstpointer fix) +@@ -244,7 +244,7 @@ static void test_qga_invalid_args(gconstpointer fix) + g_assert_cmpstr(class, ==, "GenericError"); + g_assert_cmpstr(desc, ==, "Parameter 'foo' is unexpected"); + +- QDECREF(ret); ++ qobject_unref(ret); + } + + static void test_qga_invalid_cmd(gconstpointer fix) +@@ -263,7 +263,7 @@ static void test_qga_invalid_cmd(gconstpointer fix) + g_assert_cmpstr(class, ==, "CommandNotFound"); + g_assert_cmpint(strlen(desc), >, 0); + +- QDECREF(ret); ++ qobject_unref(ret); + } + + static void test_qga_info(gconstpointer fix) +@@ -280,7 +280,7 @@ static void test_qga_info(gconstpointer fix) + version = qdict_get_try_str(val, "version"); + g_assert_cmpstr(version, ==, QEMU_VERSION); + +- QDECREF(ret); ++ qobject_unref(ret); + } + + static void test_qga_get_vcpus(gconstpointer fix) +@@ -300,7 +300,7 @@ static void test_qga_get_vcpus(gconstpointer fix) + g_assert(qdict_haskey(qobject_to(QDict, entry->value), "online")); + g_assert(qdict_haskey(qobject_to(QDict, entry->value), "logical-id")); + +- QDECREF(ret); ++ qobject_unref(ret); + } + + static void test_qga_get_fsinfo(gconstpointer fix) +@@ -324,7 +324,7 @@ static void test_qga_get_fsinfo(gconstpointer fix) + g_assert(qdict_haskey(qobject_to(QDict, entry->value), "disk")); + } + +- QDECREF(ret); ++ qobject_unref(ret); + } + + static void test_qga_get_memory_block_info(gconstpointer fix) +@@ -344,7 +344,7 @@ static void test_qga_get_memory_block_info(gconstpointer fix) + g_assert_cmpint(size, >, 0); + } + +- QDECREF(ret); ++ qobject_unref(ret); + } + + static void test_qga_get_memory_blocks(gconstpointer fix) +@@ -369,7 +369,7 @@ static void test_qga_get_memory_blocks(gconstpointer fix) + } + } + +- QDECREF(ret); ++ qobject_unref(ret); + } + + static void test_qga_network_get_interfaces(gconstpointer fix) +@@ -388,7 +388,7 @@ static void test_qga_network_get_interfaces(gconstpointer fix) + entry = qlist_first(list); + g_assert(qdict_haskey(qobject_to(QDict, entry->value), "name")); + +- QDECREF(ret); ++ qobject_unref(ret); + } + + static void test_qga_file_ops(gconstpointer fix) +@@ -410,7 +410,7 @@ static void test_qga_file_ops(gconstpointer fix) + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + id = qdict_get_int(ret, "return"); +- QDECREF(ret); ++ qobject_unref(ret); + + enc = g_base64_encode(helloworld, sizeof(helloworld)); + /* write */ +@@ -426,7 +426,7 @@ static void test_qga_file_ops(gconstpointer fix) + eof = qdict_get_bool(val, "eof"); + g_assert_cmpint(count, ==, sizeof(helloworld)); + g_assert_cmpint(eof, ==, 0); +- QDECREF(ret); ++ qobject_unref(ret); + g_free(cmd); + + /* flush */ +@@ -434,7 +434,7 @@ static void test_qga_file_ops(gconstpointer fix) + " 'arguments': {'handle': %" PRId64 "} }", + id); + ret = qmp_fd(fixture->fd, cmd); +- QDECREF(ret); ++ qobject_unref(ret); + g_free(cmd); + + /* close */ +@@ -442,7 +442,7 @@ static void test_qga_file_ops(gconstpointer fix) + " 'arguments': {'handle': %" PRId64 "} }", + id); + ret = qmp_fd(fixture->fd, cmd); +- QDECREF(ret); ++ qobject_unref(ret); + g_free(cmd); + + /* check content */ +@@ -462,7 +462,7 @@ static void test_qga_file_ops(gconstpointer fix) + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + id = qdict_get_int(ret, "return"); +- QDECREF(ret); ++ qobject_unref(ret); + + /* read */ + cmd = g_strdup_printf("{'execute': 'guest-file-read'," +@@ -477,7 +477,7 @@ static void test_qga_file_ops(gconstpointer fix) + g_assert(eof); + g_assert_cmpstr(b64, ==, enc); + +- QDECREF(ret); ++ qobject_unref(ret); + g_free(cmd); + g_free(enc); + +@@ -493,7 +493,7 @@ static void test_qga_file_ops(gconstpointer fix) + g_assert_cmpint(count, ==, 0); + g_assert(eof); + g_assert_cmpstr(b64, ==, ""); +- QDECREF(ret); ++ qobject_unref(ret); + g_free(cmd); + + /* seek */ +@@ -508,7 +508,7 @@ static void test_qga_file_ops(gconstpointer fix) + eof = qdict_get_bool(val, "eof"); + g_assert_cmpint(count, ==, 6); + g_assert(!eof); +- QDECREF(ret); ++ qobject_unref(ret); + g_free(cmd); + + /* partial read */ +@@ -527,7 +527,7 @@ static void test_qga_file_ops(gconstpointer fix) + g_assert_cmpmem(dec, count, helloworld + 6, sizeof(helloworld) - 6); + g_free(dec); + +- QDECREF(ret); ++ qobject_unref(ret); + g_free(cmd); + + /* close */ +@@ -535,7 +535,7 @@ static void test_qga_file_ops(gconstpointer fix) + " 'arguments': {'handle': %" PRId64 "} }", + id); + ret = qmp_fd(fixture->fd, cmd); +- QDECREF(ret); ++ qobject_unref(ret); + g_free(cmd); + } + +@@ -555,7 +555,7 @@ static void test_qga_file_write_read(gconstpointer fix) + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + id = qdict_get_int(ret, "return"); +- QDECREF(ret); ++ qobject_unref(ret); + + enc = g_base64_encode(helloworld, sizeof(helloworld)); + /* write */ +@@ -571,7 +571,7 @@ static void test_qga_file_write_read(gconstpointer fix) + eof = qdict_get_bool(val, "eof"); + g_assert_cmpint(count, ==, sizeof(helloworld)); + g_assert_cmpint(eof, ==, 0); +- QDECREF(ret); ++ qobject_unref(ret); + g_free(cmd); + + /* read (check implicit flush) */ +@@ -586,7 +586,7 @@ static void test_qga_file_write_read(gconstpointer fix) + g_assert_cmpint(count, ==, 0); + g_assert(eof); + g_assert_cmpstr(b64, ==, ""); +- QDECREF(ret); ++ qobject_unref(ret); + g_free(cmd); + + /* seek to 0 */ +@@ -601,7 +601,7 @@ static void test_qga_file_write_read(gconstpointer fix) + eof = qdict_get_bool(val, "eof"); + g_assert_cmpint(count, ==, 0); + g_assert(!eof); +- QDECREF(ret); ++ qobject_unref(ret); + g_free(cmd); + + /* read */ +@@ -616,7 +616,7 @@ static void test_qga_file_write_read(gconstpointer fix) + g_assert_cmpint(count, ==, sizeof(helloworld)); + g_assert(eof); + g_assert_cmpstr(b64, ==, enc); +- QDECREF(ret); ++ qobject_unref(ret); + g_free(cmd); + g_free(enc); + +@@ -625,7 +625,7 @@ static void test_qga_file_write_read(gconstpointer fix) + " 'arguments': {'handle': %" PRId64 "} }", + id); + ret = qmp_fd(fixture->fd, cmd); +- QDECREF(ret); ++ qobject_unref(ret); + g_free(cmd); + } + +@@ -642,7 +642,7 @@ static void test_qga_get_time(gconstpointer fix) + time = qdict_get_int(ret, "return"); + g_assert_cmpint(time, >, 0); + +- QDECREF(ret); ++ qobject_unref(ret); + } + + static void test_qga_blacklist(gconstpointer data) +@@ -661,7 +661,7 @@ static void test_qga_blacklist(gconstpointer data) + desc = qdict_get_try_str(error, "desc"); + g_assert_cmpstr(class, ==, "GenericError"); + g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled")); +- QDECREF(ret); ++ qobject_unref(ret); + + ret = qmp_fd(fix.fd, "{'execute': 'guest-get-time'}"); + g_assert_nonnull(ret); +@@ -670,12 +670,12 @@ static void test_qga_blacklist(gconstpointer data) + desc = qdict_get_try_str(error, "desc"); + g_assert_cmpstr(class, ==, "GenericError"); + g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled")); +- QDECREF(ret); ++ qobject_unref(ret); + + /* check something work */ + ret = qmp_fd(fix.fd, "{'execute': 'guest-get-fsinfo'}"); + qmp_assert_no_error(ret); +- QDECREF(ret); ++ qobject_unref(ret); + + fixture_tear_down(&fix, NULL); + } +@@ -772,7 +772,7 @@ static void test_qga_fsfreeze_status(gconstpointer fix) + status = qdict_get_try_str(ret, "return"); + g_assert_cmpstr(status, ==, "thawed"); + +- QDECREF(ret); ++ qobject_unref(ret); + } + + static void test_qga_guest_exec(gconstpointer fix) +@@ -795,7 +795,7 @@ static void test_qga_guest_exec(gconstpointer fix) + val = qdict_get_qdict(ret, "return"); + pid = qdict_get_int(val, "pid"); + g_assert_cmpint(pid, >, 0); +- QDECREF(ret); ++ qobject_unref(ret); + + /* wait for completion */ + now = g_get_monotonic_time(); +@@ -807,7 +807,7 @@ static void test_qga_guest_exec(gconstpointer fix) + val = qdict_get_qdict(ret, "return"); + exited = qdict_get_bool(val, "exited"); + if (!exited) { +- QDECREF(ret); ++ qobject_unref(ret); + } + } while (!exited && + g_get_monotonic_time() < now + 5 * G_TIME_SPAN_SECOND); +@@ -822,7 +822,7 @@ static void test_qga_guest_exec(gconstpointer fix) + g_assert_cmpint(len, ==, 12); + g_assert_cmpstr((char *)decoded, ==, "\" test_str \""); + g_free(decoded); +- QDECREF(ret); ++ qobject_unref(ret); + } + + static void test_qga_guest_exec_invalid(gconstpointer fix) +@@ -841,7 +841,7 @@ static void test_qga_guest_exec_invalid(gconstpointer fix) + desc = qdict_get_str(error, "desc"); + g_assert_cmpstr(class, ==, "GenericError"); + g_assert_cmpint(strlen(desc), >, 0); +- QDECREF(ret); ++ qobject_unref(ret); + + /* invalid pid */ + ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec-status'," +@@ -853,7 +853,7 @@ static void test_qga_guest_exec_invalid(gconstpointer fix) + desc = qdict_get_str(error, "desc"); + g_assert_cmpstr(class, ==, "GenericError"); + g_assert_cmpint(strlen(desc), >, 0); +- QDECREF(ret); ++ qobject_unref(ret); + } + + static void test_qga_guest_get_osinfo(gconstpointer data) +@@ -905,7 +905,7 @@ static void test_qga_guest_get_osinfo(gconstpointer data) + g_assert_nonnull(str); + g_assert_cmpstr(str, ==, "unit-test"); + +- QDECREF(ret); ++ qobject_unref(ret); + g_free(env[0]); + fixture_tear_down(&fixture, NULL); + } +diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c +index db690cc..e0ed461 100644 +--- a/tests/test-qmp-cmds.c ++++ b/tests/test-qmp-cmds.c +@@ -106,8 +106,8 @@ static void test_dispatch_cmd(void) + assert(resp != NULL); + assert(!qdict_haskey(qobject_to(QDict, resp), "error")); + +- qobject_decref(resp); +- QDECREF(req); ++ qobject_unref(resp); ++ qobject_unref(req); + } + + /* test commands that return an error due to invalid parameters */ +@@ -123,8 +123,8 @@ static void test_dispatch_cmd_failure(void) + assert(resp != NULL); + assert(qdict_haskey(qobject_to(QDict, resp), "error")); + +- qobject_decref(resp); +- QDECREF(req); ++ qobject_unref(resp); ++ qobject_unref(req); + + /* check that with extra arguments it throws an error */ + req = qdict_new(); +@@ -137,8 +137,8 @@ static void test_dispatch_cmd_failure(void) + assert(resp != NULL); + assert(qdict_haskey(qobject_to(QDict, resp), "error")); + +- qobject_decref(resp); +- QDECREF(req); ++ qobject_unref(resp); ++ qobject_unref(req); + } + + static QObject *test_qmp_dispatch(QDict *req) +@@ -153,8 +153,8 @@ static QObject *test_qmp_dispatch(QDict *req) + assert(resp && !qdict_haskey(resp, "error")); + ret = qdict_get(resp, "return"); + assert(ret); +- qobject_incref(ret); +- qobject_decref(resp_obj); ++ qobject_ref(ret); ++ qobject_unref(resp_obj); + return ret; + } + +@@ -195,7 +195,7 @@ static void test_dispatch_cmd_io(void) + assert(qdict_get_int(ret_dict_dict2_userdef, "integer") == 422); + assert(!strcmp(qdict_get_str(ret_dict_dict2_userdef, "string"), "hello2")); + assert(!strcmp(qdict_get_str(ret_dict_dict2, "string"), "blah4")); +- QDECREF(ret); ++ qobject_unref(ret); + + qdict_put_int(args3, "a", 66); + qdict_put(req, "arguments", args3); +@@ -204,9 +204,9 @@ static void test_dispatch_cmd_io(void) + ret3 = qobject_to(QNum, test_qmp_dispatch(req)); + g_assert(qnum_get_try_int(ret3, &val)); + g_assert_cmpint(val, ==, 66); +- QDECREF(ret3); ++ qobject_unref(ret3); + +- QDECREF(req); ++ qobject_unref(req); + } + + /* test generated dealloc functions for generated types */ +@@ -257,7 +257,7 @@ static void test_dealloc_partial(void) + v = qobject_input_visitor_new(QOBJECT(ud2_dict)); + visit_type_UserDefTwo(v, NULL, &ud2, &err); + visit_free(v); +- QDECREF(ud2_dict); ++ qobject_unref(ud2_dict); + } + + /* verify that visit_type_XXX() cleans up properly on error */ +diff --git a/tests/test-qmp-event.c b/tests/test-qmp-event.c +index bb10366..3a7c227 100644 +--- a/tests/test-qmp-event.c ++++ b/tests/test-qmp-event.c +@@ -133,7 +133,7 @@ static void event_prepare(TestEventData *data, + static void event_teardown(TestEventData *data, + const void *unused) + { +- QDECREF(data->expect); ++ qobject_unref(data->expect); + test_event_data = NULL; + + g_mutex_unlock(&test_event_lock); +diff --git a/tests/test-qobject-input-visitor.c b/tests/test-qobject-input-visitor.c +index 6dc59c6..0f4d234 100644 +--- a/tests/test-qobject-input-visitor.c ++++ b/tests/test-qobject-input-visitor.c +@@ -35,7 +35,7 @@ typedef struct TestInputVisitorData { + static void visitor_input_teardown(TestInputVisitorData *data, + const void *unused) + { +- qobject_decref(data->obj); ++ qobject_unref(data->obj); + data->obj = NULL; + + if (data->qiv) { +@@ -483,7 +483,7 @@ static void test_visitor_in_any(TestInputVisitorData *data, + g_assert(qnum); + g_assert(qnum_get_try_int(qnum, &val)); + g_assert_cmpint(val, ==, -42); +- qobject_decref(res); ++ qobject_unref(res); + + v = visitor_input_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }"); + visit_type_any(v, NULL, &res, &error_abort); +@@ -505,7 +505,7 @@ static void test_visitor_in_any(TestInputVisitorData *data, + qstring = qobject_to(QString, qobj); + g_assert(qstring); + g_assert_cmpstr(qstring_get_str(qstring), ==, "foo"); +- qobject_decref(res); ++ qobject_unref(res); + } + + static void test_visitor_in_null(TestInputVisitorData *data, +@@ -530,7 +530,7 @@ static void test_visitor_in_null(TestInputVisitorData *data, + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_null(v, "a", &null, &error_abort); + g_assert(qobject_type(QOBJECT(null)) == QTYPE_QNULL); +- QDECREF(null); ++ qobject_unref(null); + visit_type_null(v, "b", &null, &err); + error_free_or_abort(&err); + g_assert(!null); +@@ -1262,7 +1262,7 @@ static void do_test_visitor_in_qmp_introspect(TestInputVisitorData *data, + g_assert(schema); + + qapi_free_SchemaInfoList(schema); +- qobject_decref(obj); ++ qobject_unref(obj); + visit_free(v); + } + +diff --git a/tests/test-qobject-output-visitor.c b/tests/test-qobject-output-visitor.c +index ecf21c0..be63585 100644 +--- a/tests/test-qobject-output-visitor.c ++++ b/tests/test-qobject-output-visitor.c +@@ -40,7 +40,7 @@ static void visitor_output_teardown(TestOutputVisitorData *data, + { + visit_free(data->ov); + data->ov = NULL; +- qobject_decref(data->obj); ++ qobject_unref(data->obj); + data->obj = NULL; + } + +@@ -346,7 +346,7 @@ static void test_visitor_out_any(TestOutputVisitorData *data, + g_assert(qnum); + g_assert(qnum_get_try_int(qnum, &val)); + g_assert_cmpint(val, ==, -42); +- qobject_decref(qobj); ++ qobject_unref(qobj); + + visitor_reset(data); + qdict = qdict_new(); +@@ -355,7 +355,7 @@ static void test_visitor_out_any(TestOutputVisitorData *data, + qdict_put_str(qdict, "string", "foo"); + qobj = QOBJECT(qdict); + visit_type_any(data->ov, NULL, &qobj, &error_abort); +- qobject_decref(qobj); ++ qobject_unref(qobj); + qdict = qobject_to(QDict, visitor_get(data)); + g_assert(qdict); + qnum = qobject_to(QNum, qdict_get(qdict, "integer")); +@@ -630,7 +630,7 @@ static void check_native_list(QObject *qobj, + qvalue = qobject_to(QNum, tmp); + g_assert(qnum_get_try_uint(qvalue, &val)); + g_assert_cmpint(val, ==, i); +- qobject_decref(qlist_pop(qlist)); ++ qobject_unref(qlist_pop(qlist)); + } + break; + +@@ -654,7 +654,7 @@ static void check_native_list(QObject *qobj, + qvalue = qobject_to(QNum, tmp); + g_assert(qnum_get_try_int(qvalue, &val)); + g_assert_cmpint(val, ==, i); +- qobject_decref(qlist_pop(qlist)); ++ qobject_unref(qlist_pop(qlist)); + } + break; + case USER_DEF_NATIVE_LIST_UNION_KIND_BOOLEAN: +@@ -665,7 +665,7 @@ static void check_native_list(QObject *qobj, + g_assert(tmp); + qvalue = qobject_to(QBool, tmp); + g_assert_cmpint(qbool_get_bool(qvalue), ==, i % 3 == 0); +- qobject_decref(qlist_pop(qlist)); ++ qobject_unref(qlist_pop(qlist)); + } + break; + case USER_DEF_NATIVE_LIST_UNION_KIND_STRING: +@@ -678,7 +678,7 @@ static void check_native_list(QObject *qobj, + qvalue = qobject_to(QString, tmp); + sprintf(str, "%d", i); + g_assert_cmpstr(qstring_get_str(qvalue), ==, str); +- qobject_decref(qlist_pop(qlist)); ++ qobject_unref(qlist_pop(qlist)); + } + break; + case USER_DEF_NATIVE_LIST_UNION_KIND_NUMBER: +@@ -695,7 +695,7 @@ static void check_native_list(QObject *qobj, + g_string_printf(double_actual, "%.6f", qnum_get_double(qvalue)); + g_assert_cmpstr(double_actual->str, ==, double_expected->str); + +- qobject_decref(qlist_pop(qlist)); ++ qobject_unref(qlist_pop(qlist)); + g_string_free(double_expected, true); + g_string_free(double_actual, true); + } +@@ -703,7 +703,7 @@ static void check_native_list(QObject *qobj, + default: + g_assert_not_reached(); + } +- QDECREF(qlist); ++ qobject_unref(qlist); + } + + static void test_native_list(TestOutputVisitorData *data, +diff --git a/tests/test-visitor-serialization.c b/tests/test-visitor-serialization.c +index d18d90d..1c5a8b9 100644 +--- a/tests/test-visitor-serialization.c ++++ b/tests/test-visitor-serialization.c +@@ -1036,10 +1036,10 @@ static void qmp_deserialize(void **native_out, void *datap, + output_json = qobject_to_json(obj_orig); + obj = qobject_from_json(qstring_get_str(output_json), &error_abort); + +- QDECREF(output_json); ++ qobject_unref(output_json); + d->qiv = qobject_input_visitor_new(obj); +- qobject_decref(obj_orig); +- qobject_decref(obj); ++ qobject_unref(obj_orig); ++ qobject_unref(obj); + visit(d->qiv, native_out, errp); + } + +diff --git a/tests/test-x86-cpuid-compat.c b/tests/test-x86-cpuid-compat.c +index 9e4a508..c1ee197 100644 +--- a/tests/test-x86-cpuid-compat.c ++++ b/tests/test-x86-cpuid-compat.c +@@ -19,7 +19,7 @@ static char *get_cpu0_qom_path(void) + + cpu0 = qobject_to(QDict, qlist_peek(ret)); + path = g_strdup(qdict_get_str(cpu0, "qom_path")); +- QDECREF(resp); ++ qobject_unref(resp); + return path; + } + +@@ -30,8 +30,8 @@ static QObject *qom_get(const char *path, const char *prop) + " 'property': %s } }", + path, prop); + QObject *ret = qdict_get(resp, "return"); +- qobject_incref(ret); +- QDECREF(resp); ++ qobject_ref(ret); ++ qobject_unref(resp); + return ret; + } + +@@ -41,7 +41,7 @@ static bool qom_get_bool(const char *path, const char *prop) + QBool *value = qobject_to(QBool, qom_get(path, prop)); + bool b = qbool_get_bool(value); + +- QDECREF(value); ++ qobject_unref(value); + return b; + } + #endif +@@ -66,7 +66,7 @@ static void test_cpuid_prop(const void *data) + g_assert_cmpint(val, ==, args->expected_value); + qtest_end(); + +- QDECREF(value); ++ qobject_unref(value); + g_free(path); + } + +@@ -142,8 +142,8 @@ static void test_feature_flag(const void *data) + + g_assert(!!(value & (1U << args->bitnr)) == args->expected_value); + +- QDECREF(present); +- QDECREF(filtered); ++ qobject_unref(present); ++ qobject_unref(filtered); + g_free(path); + } + +diff --git a/tests/tmp105-test.c b/tests/tmp105-test.c +index 66c7a01..d093cff 100644 +--- a/tests/tmp105-test.c ++++ b/tests/tmp105-test.c +@@ -74,7 +74,7 @@ static int qmp_tmp105_get_temperature(const char *id) + "'property': 'temperature' } }", id); + g_assert(qdict_haskey(response, "return")); + ret = qdict_get_int(response, "return"); +- QDECREF(response); ++ qobject_unref(response); + return ret; + } + +@@ -85,7 +85,7 @@ static void qmp_tmp105_set_temperature(const char *id, int value) + response = qmp("{ 'execute': 'qom-set', 'arguments': { 'path': %s, " + "'property': 'temperature', 'value': %d } }", id, value); + g_assert(qdict_haskey(response, "return")); +- QDECREF(response); ++ qobject_unref(response); + } + + #define TMP105_PRECISION (1000/16) +diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c +index 61d9972..bbc8091 100644 +--- a/tests/vhost-user-test.c ++++ b/tests/vhost-user-test.c +@@ -727,7 +727,7 @@ static void test_migrate(void) + rsp = qmp("{ 'execute': 'migrate_set_speed'," + "'arguments': { 'value': 10 } }"); + g_assert(qdict_haskey(rsp, "return")); +- QDECREF(rsp); ++ qobject_unref(rsp); + + cmd = g_strdup_printf("{ 'execute': 'migrate'," + "'arguments': { 'uri': '%s' } }", +@@ -735,7 +735,7 @@ static void test_migrate(void) + rsp = qmp(cmd); + g_free(cmd); + g_assert(qdict_haskey(rsp, "return")); +- QDECREF(rsp); ++ qobject_unref(rsp); + + wait_for_log_fd(s); + +@@ -751,7 +751,7 @@ static void test_migrate(void) + rsp = qmp("{ 'execute': 'migrate_set_speed'," + "'arguments': { 'value': 0 } }"); + g_assert(qdict_haskey(rsp, "return")); +- QDECREF(rsp); ++ qobject_unref(rsp); + + qmp_eventwait("STOP"); + +diff --git a/tests/virtio-net-test.c b/tests/virtio-net-test.c +index 0a3c5dd..b285a26 100644 +--- a/tests/virtio-net-test.c ++++ b/tests/virtio-net-test.c +@@ -173,7 +173,7 @@ static void rx_stop_cont_test(QVirtioDevice *dev, + qvirtqueue_kick(dev, vq, free_head); + + rsp = qmp("{ 'execute' : 'stop'}"); +- QDECREF(rsp); ++ qobject_unref(rsp); + + ret = iov_send(socket, iov, 2, 0, sizeof(len) + sizeof(test)); + g_assert_cmpint(ret, ==, sizeof(test) + sizeof(len)); +@@ -182,9 +182,9 @@ static void rx_stop_cont_test(QVirtioDevice *dev, + * ensure the packet data gets queued in QEMU, before we do 'cont'. + */ + rsp = qmp("{ 'execute' : 'query-status'}"); +- QDECREF(rsp); ++ qobject_unref(rsp); + rsp = qmp("{ 'execute' : 'cont'}"); +- QDECREF(rsp); ++ qobject_unref(rsp); + + qvirtio_wait_used_elem(dev, vq, free_head, NULL, QVIRTIO_NET_TIMEOUT_US); + memread(req_addr + VNET_HDR_SIZE, buffer, sizeof(test)); +diff --git a/tests/vmgenid-test.c b/tests/vmgenid-test.c +index 2ec274e..8d915c6 100644 +--- a/tests/vmgenid-test.c ++++ b/tests/vmgenid-test.c +@@ -125,7 +125,7 @@ static void read_guid_from_monitor(QemuUUID *guid) + guid_str = qdict_get_str(rsp_ret, "guid"); + g_assert(qemu_uuid_parse(guid_str, guid) == 0); + } +- QDECREF(rsp); ++ qobject_unref(rsp); + } + + static char disk[] = "tests/vmgenid-test-disk-XXXXXX"; +diff --git a/tests/wdt_ib700-test.c b/tests/wdt_ib700-test.c +index 3b5bbcf..797288d 100644 +--- a/tests/wdt_ib700-test.c ++++ b/tests/wdt_ib700-test.c +@@ -16,7 +16,7 @@ static void qmp_check_no_event(QTestState *s) + { + QDict *resp = qtest_qmp(s, "{'execute':'query-status'}"); + g_assert(qdict_haskey(resp, "return")); +- QDECREF(resp); ++ qobject_unref(resp); + } + + static QDict *ib700_program_and_wait(QTestState *s) +@@ -48,8 +48,8 @@ static QDict *ib700_program_and_wait(QTestState *s) + qtest_clock_step(s, 2 * NANOSECONDS_PER_SECOND); + event = qtest_qmp_eventwait_ref(s, "WATCHDOG"); + data = qdict_get_qdict(event, "data"); +- QINCREF(data); +- QDECREF(event); ++ qobject_ref(data); ++ qobject_unref(event); + return data; + } + +@@ -62,7 +62,7 @@ static void ib700_pause(void) + qtest_irq_intercept_in(s, "ioapic"); + d = ib700_program_and_wait(s); + g_assert(!strcmp(qdict_get_str(d, "action"), "pause")); +- QDECREF(d); ++ qobject_unref(d); + qtest_qmp_eventwait(s, "STOP"); + qtest_quit(s); + } +@@ -75,7 +75,7 @@ static void ib700_reset(void) + qtest_irq_intercept_in(s, "ioapic"); + d = ib700_program_and_wait(s); + g_assert(!strcmp(qdict_get_str(d, "action"), "reset")); +- QDECREF(d); ++ qobject_unref(d); + qtest_qmp_eventwait(s, "RESET"); + qtest_quit(s); + } +@@ -89,7 +89,7 @@ static void ib700_shutdown(void) + qtest_irq_intercept_in(s, "ioapic"); + d = ib700_program_and_wait(s); + g_assert(!strcmp(qdict_get_str(d, "action"), "reset")); +- QDECREF(d); ++ qobject_unref(d); + qtest_qmp_eventwait(s, "SHUTDOWN"); + qtest_quit(s); + } +@@ -102,7 +102,7 @@ static void ib700_none(void) + qtest_irq_intercept_in(s, "ioapic"); + d = ib700_program_and_wait(s); + g_assert(!strcmp(qdict_get_str(d, "action"), "none")); +- QDECREF(d); ++ qobject_unref(d); + qtest_quit(s); + } + +diff --git a/util/keyval.c b/util/keyval.c +index 1c7351a..13def4a 100644 +--- a/util/keyval.c ++++ b/util/keyval.c +@@ -126,7 +126,7 @@ static int key_to_index(const char *key, const char **end) + * Else, fail because we have conflicting needs on how to map + * @key_in_cur. + * In any case, take over the reference to @value, i.e. if the caller +- * wants to hold on to a reference, it needs to QINCREF(). ++ * wants to hold on to a reference, it needs to qobject_ref(). + * Use @key up to @key_cursor to identify the key in error messages. + * On success, return the mapped value. + * On failure, store an error through @errp and return NULL. +@@ -143,7 +143,7 @@ static QObject *keyval_parse_put(QDict *cur, + if (qobject_type(old) != (value ? QTYPE_QSTRING : QTYPE_QDICT)) { + error_setg(errp, "Parameters '%.*s.*' used inconsistently", + (int)(key_cursor - key), key); +- QDECREF(value); ++ qobject_unref(value); + return NULL; + } + if (!value) { +@@ -375,10 +375,10 @@ static QObject *keyval_listify(QDict *cur, GSList *key_of_cur, Error **errp) + error_setg(errp, "Parameter '%s%d' missing", key, i); + g_free(key); + g_free(elt); +- QDECREF(list); ++ qobject_unref(list); + return NULL; + } +- qobject_incref(elt[i]); ++ qobject_ref(elt[i]); + qlist_append_obj(list, elt[i]); + } + +@@ -404,7 +404,7 @@ QDict *keyval_parse(const char *params, const char *implied_key, + while (*s) { + s = keyval_parse_one(qdict, s, implied_key, errp); + if (!s) { +- QDECREF(qdict); ++ qobject_unref(qdict); + return NULL; + } + implied_key = NULL; +@@ -412,7 +412,7 @@ QDict *keyval_parse(const char *params, const char *implied_key, + + listified = keyval_listify(qdict, NULL, errp); + if (!listified) { +- QDECREF(qdict); ++ qobject_unref(qdict); + return NULL; + } + assert(listified == QOBJECT(qdict)); +diff --git a/util/qemu-config.c b/util/qemu-config.c +index 20f7d14..14d8402 100644 +--- a/util/qemu-config.c ++++ b/util/qemu-config.c +@@ -562,8 +562,8 @@ static void config_parse_qdict_section(QDict *options, QemuOptsList *opts, + } + + out: +- QDECREF(subqdict); +- QDECREF(list); ++ qobject_unref(subqdict); ++ qobject_unref(list); + } + + void qemu_config_parse_qdict(QDict *options, QemuOptsList **lists, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qobject-Use-qobject_to-instead-of-type-cast.patch b/SOURCES/kvm-qobject-Use-qobject_to-instead-of-type-cast.patch new file mode 100644 index 0000000..aedd1a1 --- /dev/null +++ b/SOURCES/kvm-qobject-Use-qobject_to-instead-of-type-cast.patch @@ -0,0 +1,55 @@ +From 5dcc5026b76ccfe45ed4a4ed56c8c949ead76e98 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Mon, 18 Jun 2018 08:43:08 +0200 +Subject: [PATCH 01/54] qobject: Use qobject_to() instead of type cast +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20180618084330.30009-2-armbru@redhat.com> +Patchwork-id: 80732 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 01/23] qobject: Use qobject_to() instead of type cast +Bugzilla: 1557995 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +The proper way to convert from (abstract) QObject to a (concrete) +subtype is qobject_to(). Look for offenders that type cast instead: + + $ git-grep '(Q[A-Z][a-z]* \*)' + hmp.c: qmp_device_add((QDict *)qdict, NULL, &err); + include/qapi/qmp/qobject.h: return (QObject *)obj; + qobject/qobject.c:static void (*qdestroy[QTYPE__MAX])(QObject *) = { + tests/check-qdict.c: dst = (QDict *)qdict_crumple(src, &error_abort); + +The first two cast away const, the third isn't a type cast. Fix the +fourth. + +Signed-off-by: Markus Armbruster +Message-Id: <20180426152805.8469-1-armbru@redhat.com> +Reviewed-by: Eric Blake +Reviewed-by: Marc-André Lureau +(cherry picked from commit 46cfbf13b06d551072ed17fbfca67c103edf814f) +Signed-off-by: Miroslav Rezanina +--- + tests/check-qdict.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/check-qdict.c b/tests/check-qdict.c +index 2e73c2f..08d4303 100644 +--- a/tests/check-qdict.c ++++ b/tests/check-qdict.c +@@ -657,7 +657,7 @@ static void qdict_crumple_test_empty(void) + + src = qdict_new(); + +- dst = (QDict *)qdict_crumple(src, &error_abort); ++ dst = qobject_to(QDict, qdict_crumple(src, &error_abort)); + + g_assert_cmpint(qdict_size(dst), ==, 0); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qobject-use-a-QObjectBase_-struct.patch b/SOURCES/kvm-qobject-use-a-QObjectBase_-struct.patch new file mode 100644 index 0000000..fced9cb --- /dev/null +++ b/SOURCES/kvm-qobject-use-a-QObjectBase_-struct.patch @@ -0,0 +1,254 @@ +From a05d912ac29700014b1d6a894240a62f883e4409 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Mon, 18 Jun 2018 08:43:10 +0200 +Subject: [PATCH 03/54] qobject: use a QObjectBase_ struct +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Markus Armbruster +Message-id: <20180618084330.30009-4-armbru@redhat.com> +Patchwork-id: 80742 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 03/23] qobject: use a QObjectBase_ struct +Bugzilla: 1557995 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +From: Marc-André Lureau + +By moving the base fields to a QObjectBase_, QObject can be a type +which also has a 'base' field. This allows writing a generic QOBJECT() +macro that will work with any QObject type, including QObject +itself. The container_of() macro ensures that the object to cast has a +QObjectBase_ base field, giving some type safety guarantees. QObject +must have no members but QObjectBase_ base, or else QOBJECT() breaks. + +QObjectBase_ is not a typedef and uses a trailing underscore to make +it obvious it is not for normal use and to avoid potential abuse. + +Signed-off-by: Marc-André Lureau +Reviewed-by: Eric Blake +Message-Id: <20180419150145.24795-3-marcandre.lureau@redhat.com> +Reviewed-by: Markus Armbruster +Signed-off-by: Markus Armbruster +(cherry picked from commit 3d3eacaeccaab718ea0e2ddaa578bfae9e311c59) +Signed-off-by: Miroslav Rezanina +--- + include/qapi/qmp/qbool.h | 2 +- + include/qapi/qmp/qdict.h | 2 +- + include/qapi/qmp/qlist.h | 2 +- + include/qapi/qmp/qnull.h | 2 +- + include/qapi/qmp/qnum.h | 2 +- + include/qapi/qmp/qobject.h | 31 ++++++++++++++++++++----------- + include/qapi/qmp/qstring.h | 2 +- + qobject/qobject.c | 12 ++++++------ + tests/check-qdict.c | 6 +++--- + 9 files changed, 35 insertions(+), 26 deletions(-) + +diff --git a/include/qapi/qmp/qbool.h b/include/qapi/qmp/qbool.h +index b9a44a1..5f61e38 100644 +--- a/include/qapi/qmp/qbool.h ++++ b/include/qapi/qmp/qbool.h +@@ -17,7 +17,7 @@ + #include "qapi/qmp/qobject.h" + + struct QBool { +- QObject base; ++ struct QObjectBase_ base; + bool value; + }; + +diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h +index 2cc3e90..921a28d 100644 +--- a/include/qapi/qmp/qdict.h ++++ b/include/qapi/qmp/qdict.h +@@ -25,7 +25,7 @@ typedef struct QDictEntry { + } QDictEntry; + + struct QDict { +- QObject base; ++ struct QObjectBase_ base; + size_t size; + QLIST_HEAD(,QDictEntry) table[QDICT_BUCKET_MAX]; + }; +diff --git a/include/qapi/qmp/qlist.h b/include/qapi/qmp/qlist.h +index 5c673ac..8d2c32c 100644 +--- a/include/qapi/qmp/qlist.h ++++ b/include/qapi/qmp/qlist.h +@@ -22,7 +22,7 @@ typedef struct QListEntry { + } QListEntry; + + struct QList { +- QObject base; ++ struct QObjectBase_ base; + QTAILQ_HEAD(,QListEntry) head; + }; + +diff --git a/include/qapi/qmp/qnull.h b/include/qapi/qmp/qnull.h +index c992ee2..e8ea2c3 100644 +--- a/include/qapi/qmp/qnull.h ++++ b/include/qapi/qmp/qnull.h +@@ -16,7 +16,7 @@ + #include "qapi/qmp/qobject.h" + + struct QNull { +- QObject base; ++ struct QObjectBase_ base; + }; + + extern QNull qnull_; +diff --git a/include/qapi/qmp/qnum.h b/include/qapi/qmp/qnum.h +index 3e47475..45bf02a 100644 +--- a/include/qapi/qmp/qnum.h ++++ b/include/qapi/qmp/qnum.h +@@ -45,7 +45,7 @@ typedef enum { + * convert under the hood. + */ + struct QNum { +- QObject base; ++ struct QObjectBase_ base; + QNumKind kind; + union { + int64_t i64; +diff --git a/include/qapi/qmp/qobject.h b/include/qapi/qmp/qobject.h +index 5206ff9..a713c01 100644 +--- a/include/qapi/qmp/qobject.h ++++ b/include/qapi/qmp/qobject.h +@@ -34,13 +34,21 @@ + + #include "qapi/qapi-builtin-types.h" + +-struct QObject { ++/* Not for use outside include/qapi/qmp/ */ ++struct QObjectBase_ { + QType type; + size_t refcnt; + }; + +-/* Get the 'base' part of an object */ +-#define QOBJECT(obj) (&(obj)->base) ++/* this struct must have no other members than base */ ++struct QObject { ++ struct QObjectBase_ base; ++}; ++ ++#define QOBJECT(obj) ({ \ ++ typeof(obj) _obj = (obj); \ ++ _obj ? container_of(&(_obj)->base, QObject, base) : NULL; \ ++}) + + /* High-level interface for qobject_incref() */ + #define QINCREF(obj) \ +@@ -68,8 +76,8 @@ QEMU_BUILD_BUG_MSG(QTYPE__MAX != 7, + static inline void qobject_init(QObject *obj, QType type) + { + assert(QTYPE_NONE < type && type < QTYPE__MAX); +- obj->refcnt = 1; +- obj->type = type; ++ obj->base.refcnt = 1; ++ obj->base.type = type; + } + + /** +@@ -77,8 +85,9 @@ static inline void qobject_init(QObject *obj, QType type) + */ + static inline void qobject_incref(QObject *obj) + { +- if (obj) +- obj->refcnt++; ++ if (obj) { ++ obj->base.refcnt++; ++ } + } + + /** +@@ -101,8 +110,8 @@ void qobject_destroy(QObject *obj); + */ + static inline void qobject_decref(QObject *obj) + { +- assert(!obj || obj->refcnt); +- if (obj && --obj->refcnt == 0) { ++ assert(!obj || obj->base.refcnt); ++ if (obj && --obj->base.refcnt == 0) { + qobject_destroy(obj); + } + } +@@ -112,8 +121,8 @@ static inline void qobject_decref(QObject *obj) + */ + static inline QType qobject_type(const QObject *obj) + { +- assert(QTYPE_NONE < obj->type && obj->type < QTYPE__MAX); +- return obj->type; ++ assert(QTYPE_NONE < obj->base.type && obj->base.type < QTYPE__MAX); ++ return obj->base.type; + } + + /** +diff --git a/include/qapi/qmp/qstring.h b/include/qapi/qmp/qstring.h +index 30ae260..b3b3d44 100644 +--- a/include/qapi/qmp/qstring.h ++++ b/include/qapi/qmp/qstring.h +@@ -16,7 +16,7 @@ + #include "qapi/qmp/qobject.h" + + struct QString { +- QObject base; ++ struct QObjectBase_ base; + char *string; + size_t length; + size_t capacity; +diff --git a/qobject/qobject.c b/qobject/qobject.c +index 87649c5..cf4b7e2 100644 +--- a/qobject/qobject.c ++++ b/qobject/qobject.c +@@ -37,9 +37,9 @@ static void (*qdestroy[QTYPE__MAX])(QObject *) = { + + void qobject_destroy(QObject *obj) + { +- assert(!obj->refcnt); +- assert(QTYPE_QNULL < obj->type && obj->type < QTYPE__MAX); +- qdestroy[obj->type](obj); ++ assert(!obj->base.refcnt); ++ assert(QTYPE_QNULL < obj->base.type && obj->base.type < QTYPE__MAX); ++ qdestroy[obj->base.type](obj); + } + + +@@ -62,11 +62,11 @@ bool qobject_is_equal(const QObject *x, const QObject *y) + return true; + } + +- if (!x || !y || x->type != y->type) { ++ if (!x || !y || x->base.type != y->base.type) { + return false; + } + +- assert(QTYPE_NONE < x->type && x->type < QTYPE__MAX); ++ assert(QTYPE_NONE < x->base.type && x->base.type < QTYPE__MAX); + +- return qis_equal[x->type](x, y); ++ return qis_equal[x->base.type](x, y); + } +diff --git a/tests/check-qdict.c b/tests/check-qdict.c +index 08d4303..07bb8f4 100644 +--- a/tests/check-qdict.c ++++ b/tests/check-qdict.c +@@ -570,11 +570,11 @@ static void qdict_join_test(void) + } + + /* Check the references */ +- g_assert(qdict_get(dict1, "foo")->refcnt == 1); +- g_assert(qdict_get(dict1, "bar")->refcnt == 1); ++ g_assert(qdict_get(dict1, "foo")->base.refcnt == 1); ++ g_assert(qdict_get(dict1, "bar")->base.refcnt == 1); + + if (!overwrite) { +- g_assert(qdict_get(dict2, "foo")->refcnt == 1); ++ g_assert(qdict_get(dict2, "foo")->base.refcnt == 1); + } + + /* Clean up */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qom-provide-root-container-for-internal-objs.patch b/SOURCES/kvm-qom-provide-root-container-for-internal-objs.patch deleted file mode 100644 index 82aeff5..0000000 --- a/SOURCES/kvm-qom-provide-root-container-for-internal-objs.patch +++ /dev/null @@ -1,86 +0,0 @@ -From f105da1e0b15cdded39ad0a96501aace13e3bd6b Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Fri, 22 Dec 2017 11:08:44 +0100 -Subject: [PATCH 26/42] qom: provide root container for internal objs -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Stefan Hajnoczi -Message-id: <20171222110900.24813-5-stefanha@redhat.com> -Patchwork-id: 78486 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 04/20] qom: provide root container for internal objs -Bugzilla: 1519721 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -From: Peter Xu - -We have object_get_objects_root() to keep user created objects, however -no place for objects that will be used internally. Create such a -container for internal objects. - -CC: Andreas Färber -CC: Markus Armbruster -CC: Paolo Bonzini -Suggested-by: Daniel P. Berrange -Signed-off-by: Peter Xu -Reviewed-by: Fam Zheng -Message-id: 20170928025958.1420-2-peterx@redhat.com -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit 7c47c4ead75d0b733ee8f2f51fd1de0644cc1308) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - include/qom/object.h | 11 +++++++++++ - qom/object.c | 11 +++++++++++ - 2 files changed, 22 insertions(+) - -diff --git a/include/qom/object.h b/include/qom/object.h -index 1b82899..dde5086 100644 ---- a/include/qom/object.h -+++ b/include/qom/object.h -@@ -1214,6 +1214,17 @@ Object *object_get_root(void); - Object *object_get_objects_root(void); - - /** -+ * object_get_internal_root: -+ * -+ * Get the container object that holds internally used object -+ * instances. Any object which is put into this container must not be -+ * user visible, and it will not be exposed in the QOM tree. -+ * -+ * Returns: the internal object container -+ */ -+Object *object_get_internal_root(void); -+ -+/** - * object_get_canonical_path_component: - * - * Returns: The final component in the object's canonical path. The canonical -diff --git a/qom/object.c b/qom/object.c -index fe6e744..4e4b2f7 100644 ---- a/qom/object.c -+++ b/qom/object.c -@@ -1370,6 +1370,17 @@ Object *object_get_objects_root(void) - return container_get(object_get_root(), "/objects"); - } - -+Object *object_get_internal_root(void) -+{ -+ static Object *internal_root; -+ -+ if (!internal_root) { -+ internal_root = object_new("container"); -+ } -+ -+ return internal_root; -+} -+ - static void object_get_child_property(Object *obj, Visitor *v, - const char *name, void *opaque, - Error **errp) --- -1.8.3.1 - diff --git a/SOURCES/kvm-qxl-fix-local-renderer-crash.patch b/SOURCES/kvm-qxl-fix-local-renderer-crash.patch new file mode 100644 index 0000000..b0c90fc --- /dev/null +++ b/SOURCES/kvm-qxl-fix-local-renderer-crash.patch @@ -0,0 +1,52 @@ +From e79d4d03368f7346249033e0f5ad2732228852ca Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 13 Jun 2018 13:15:57 +0200 +Subject: [PATCH 02/89] qxl: fix local renderer crash +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Gerd Hoffmann +Message-id: <20180613131557.12255-2-kraxel@redhat.com> +Patchwork-id: 80662 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/1] qxl: fix local renderer crash +Bugzilla: 1567733 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Marc-André Lureau +RH-Acked-by: Laszlo Ersek + +Make sure we only ask the spice local renderer for display updates in +case we have a valid primary surface. Without that spice is confused +and throws errors in case a display update request (triggered by +screendump for example) happens in parallel to a mode switch and hits +the race window where the old primary surface is gone and the new isn't +establisted yet. + +Cc: qemu-stable@nongnu.org +Fixes: https://bugzilla.redhat.com//show_bug.cgi?id=1567733 +Signed-off-by: Gerd Hoffmann +Reviewed-by: Marc-André Lureau +Message-id: 20180427115528.345-1-kraxel@redhat.com +(cherry picked from commit 5bd5c27c7d284d01477c5cc022ce22438c46bf9f) +Signed-off-by: Miroslav Rezanina +--- + hw/display/qxl-render.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c +index e7ac4f8..c62b9a5 100644 +--- a/hw/display/qxl-render.c ++++ b/hw/display/qxl-render.c +@@ -169,7 +169,8 @@ void qxl_render_update(PCIQXLDevice *qxl) + + qemu_mutex_lock(&qxl->ssd.lock); + +- if (!runstate_is_running() || !qxl->guest_primary.commands) { ++ if (!runstate_is_running() || !qxl->guest_primary.commands || ++ qxl->mode == QXL_MODE_UNDEFINED) { + qxl_render_update_area_unlocked(qxl); + qemu_mutex_unlock(&qxl->ssd.lock); + return; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-raw-Check-byte-range-uniformly.patch b/SOURCES/kvm-raw-Check-byte-range-uniformly.patch new file mode 100644 index 0000000..72c1689 --- /dev/null +++ b/SOURCES/kvm-raw-Check-byte-range-uniformly.patch @@ -0,0 +1,159 @@ +From f0714015bbe871d1f0c1fe9d8b8c7bd2afc2a0a0 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 29 Jun 2018 06:11:42 +0200 +Subject: [PATCH 38/57] raw: Check byte range uniformly + +RH-Author: Fam Zheng +Message-id: <20180629061153.12687-3-famz@redhat.com> +Patchwork-id: 81152 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v2 02/13] raw: Check byte range uniformly +Bugzilla: 1482537 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Kevin Wolf + +We don't verify the request range against s->size in the I/O callbacks +except for raw_co_pwritev. This is inconsistent (especially for +raw_co_pwrite_zeroes and raw_co_pdiscard), so fix them, in the meanwhile +make the helper reusable by the coming new callbacks. + +Note that in most cases the block layer already verifies the request +byte range against our reported image length, before invoking the driver +callbacks. The exception is during image creating, after +blk_set_allow_write_beyond_eof(blk, true) is called. But in that case, +the requests are not directly from the user or guest. So there is no +visible behavior change in adding the check code. + +The int64_t -> uint64_t inconsistency, as shown by the type casting, is +pre-existing due to the interface. + +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Eric Blake +Signed-off-by: Fam Zheng +Message-id: 20180601092648.24614-3-famz@redhat.com +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 384455385248762e74a080978f18f0c8f74757fe) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/raw-format.c | 64 +++++++++++++++++++++++++++++++++--------------------- + 1 file changed, 39 insertions(+), 25 deletions(-) + +diff --git a/block/raw-format.c b/block/raw-format.c +index fe33693..b69a067 100644 +--- a/block/raw-format.c ++++ b/block/raw-format.c +@@ -167,16 +167,37 @@ static void raw_reopen_abort(BDRVReopenState *state) + state->opaque = NULL; + } + ++/* Check and adjust the offset, against 'offset' and 'size' options. */ ++static inline int raw_adjust_offset(BlockDriverState *bs, uint64_t *offset, ++ uint64_t bytes, bool is_write) ++{ ++ BDRVRawState *s = bs->opaque; ++ ++ if (s->has_size && (*offset > s->size || bytes > (s->size - *offset))) { ++ /* There's not enough space for the write, or the read request is ++ * out-of-range. Don't read/write anything to prevent leaking out of ++ * the size specified in options. */ ++ return is_write ? -ENOSPC : -EINVAL;; ++ } ++ ++ if (*offset > INT64_MAX - s->offset) { ++ return -EINVAL; ++ } ++ *offset += s->offset; ++ ++ return 0; ++} ++ + static int coroutine_fn raw_co_preadv(BlockDriverState *bs, uint64_t offset, + uint64_t bytes, QEMUIOVector *qiov, + int flags) + { +- BDRVRawState *s = bs->opaque; ++ int ret; + +- if (offset > UINT64_MAX - s->offset) { +- return -EINVAL; ++ ret = raw_adjust_offset(bs, &offset, bytes, false); ++ if (ret) { ++ return ret; + } +- offset += s->offset; + + BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO); + return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags); +@@ -186,23 +207,11 @@ static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, uint64_t offset, + uint64_t bytes, QEMUIOVector *qiov, + int flags) + { +- BDRVRawState *s = bs->opaque; + void *buf = NULL; + BlockDriver *drv; + QEMUIOVector local_qiov; + int ret; + +- if (s->has_size && (offset > s->size || bytes > (s->size - offset))) { +- /* There's not enough space for the data. Don't write anything and just +- * fail to prevent leaking out of the size specified in options. */ +- return -ENOSPC; +- } +- +- if (offset > UINT64_MAX - s->offset) { +- ret = -EINVAL; +- goto fail; +- } +- + if (bs->probed && offset < BLOCK_PROBE_BUF_SIZE && bytes) { + /* Handling partial writes would be a pain - so we just + * require that guests have 512-byte request alignment if +@@ -237,7 +246,10 @@ static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, uint64_t offset, + qiov = &local_qiov; + } + +- offset += s->offset; ++ ret = raw_adjust_offset(bs, &offset, bytes, true); ++ if (ret) { ++ goto fail; ++ } + + BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO); + ret = bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags); +@@ -267,22 +279,24 @@ static int coroutine_fn raw_co_pwrite_zeroes(BlockDriverState *bs, + int64_t offset, int bytes, + BdrvRequestFlags flags) + { +- BDRVRawState *s = bs->opaque; +- if (offset > UINT64_MAX - s->offset) { +- return -EINVAL; ++ int ret; ++ ++ ret = raw_adjust_offset(bs, (uint64_t *)&offset, bytes, true); ++ if (ret) { ++ return ret; + } +- offset += s->offset; + return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags); + } + + static int coroutine_fn raw_co_pdiscard(BlockDriverState *bs, + int64_t offset, int bytes) + { +- BDRVRawState *s = bs->opaque; +- if (offset > UINT64_MAX - s->offset) { +- return -EINVAL; ++ int ret; ++ ++ ret = raw_adjust_offset(bs, (uint64_t *)&offset, bytes, true); ++ if (ret) { ++ return ret; + } +- offset += s->offset; + return bdrv_co_pdiscard(bs->file->bs, offset, bytes); + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-raw-Implement-copy-offloading.patch b/SOURCES/kvm-raw-Implement-copy-offloading.patch new file mode 100644 index 0000000..9062abf --- /dev/null +++ b/SOURCES/kvm-raw-Implement-copy-offloading.patch @@ -0,0 +1,80 @@ +From 5d79960f00eebe7a8a8bcd423f39c4e72f3366d1 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Fri, 29 Jun 2018 06:11:43 +0200 +Subject: [PATCH 39/57] raw: Implement copy offloading + +RH-Author: Fam Zheng +Message-id: <20180629061153.12687-4-famz@redhat.com> +Patchwork-id: 81155 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v2 03/13] raw: Implement copy offloading +Bugzilla: 1482537 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Max Reitz +RH-Acked-by: Kevin Wolf + +Just pass down to ->file. + +Signed-off-by: Fam Zheng +Reviewed-by: Stefan Hajnoczi +Message-id: 20180601092648.24614-4-famz@redhat.com +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 72d219e2f916adeec9845473d239571a267f3314) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/raw-format.c | 32 ++++++++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +diff --git a/block/raw-format.c b/block/raw-format.c +index b69a067..f2e468d 100644 +--- a/block/raw-format.c ++++ b/block/raw-format.c +@@ -497,6 +497,36 @@ static int raw_probe_geometry(BlockDriverState *bs, HDGeometry *geo) + return bdrv_probe_geometry(bs->file->bs, geo); + } + ++static int coroutine_fn raw_co_copy_range_from(BlockDriverState *bs, ++ BdrvChild *src, uint64_t src_offset, ++ BdrvChild *dst, uint64_t dst_offset, ++ uint64_t bytes, BdrvRequestFlags flags) ++{ ++ int ret; ++ ++ ret = raw_adjust_offset(bs, &src_offset, bytes, false); ++ if (ret) { ++ return ret; ++ } ++ return bdrv_co_copy_range_from(bs->file, src_offset, dst, dst_offset, ++ bytes, flags); ++} ++ ++static int coroutine_fn raw_co_copy_range_to(BlockDriverState *bs, ++ BdrvChild *src, uint64_t src_offset, ++ BdrvChild *dst, uint64_t dst_offset, ++ uint64_t bytes, BdrvRequestFlags flags) ++{ ++ int ret; ++ ++ ret = raw_adjust_offset(bs, &dst_offset, bytes, true); ++ if (ret) { ++ return ret; ++ } ++ return bdrv_co_copy_range_to(src, src_offset, bs->file, dst_offset, bytes, ++ flags); ++} ++ + BlockDriver bdrv_raw = { + .format_name = "raw", + .instance_size = sizeof(BDRVRawState), +@@ -513,6 +543,8 @@ BlockDriver bdrv_raw = { + .bdrv_co_pwrite_zeroes = &raw_co_pwrite_zeroes, + .bdrv_co_pdiscard = &raw_co_pdiscard, + .bdrv_co_block_status = &raw_co_block_status, ++ .bdrv_co_copy_range_from = &raw_co_copy_range_from, ++ .bdrv_co_copy_range_to = &raw_co_copy_range_to, + .bdrv_truncate = &raw_truncate, + .bdrv_getlength = &raw_getlength, + .has_variable_length = true, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-rbd-Drop-deprecated-drive-parameter-filename.patch b/SOURCES/kvm-rbd-Drop-deprecated-drive-parameter-filename.patch new file mode 100644 index 0000000..05ce0ee --- /dev/null +++ b/SOURCES/kvm-rbd-Drop-deprecated-drive-parameter-filename.patch @@ -0,0 +1,59 @@ +From 61a2510cbf901b95759402df893e63be02b510d1 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Mon, 18 Jun 2018 08:43:13 +0200 +Subject: [PATCH 06/54] rbd: Drop deprecated -drive parameter "filename" + +RH-Author: Markus Armbruster +Message-id: <20180618084330.30009-7-armbru@redhat.com> +Patchwork-id: 80735 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 06/23] rbd: Drop deprecated -drive parameter "filename" +Bugzilla: 1557995 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Parameter "filename" is deprecated since commit 91589d9e5ca, v2.10.0. +Time to get rid of it. + +Signed-off-by: Markus Armbruster +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit bb9f762ff35459e34630d731a5a91c02602150d1) +Signed-off-by: Miroslav Rezanina +--- + block/rbd.c | 16 ---------------- + 1 file changed, 16 deletions(-) + +diff --git a/block/rbd.c b/block/rbd.c +index a14b42f..2842c0e 100644 +--- a/block/rbd.c ++++ b/block/rbd.c +@@ -625,25 +625,9 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags, + QObject *crumpled = NULL; + const QDictEntry *e; + Error *local_err = NULL; +- const char *filename; + char *keypairs, *secretid; + int r; + +- /* If we are given a filename, parse the filename, with precedence given to +- * filename encoded options */ +- filename = qdict_get_try_str(options, "filename"); +- if (filename) { +- warn_report("'filename' option specified. " +- "This is an unsupported option, and may be deprecated " +- "in the future"); +- qemu_rbd_parse_filename(filename, options, &local_err); +- qdict_del(options, "filename"); +- if (local_err) { +- error_propagate(errp, local_err); +- return -EINVAL; +- } +- } +- + keypairs = g_strdup(qdict_get_try_str(options, "=keyvalue-pairs")); + if (keypairs) { + qdict_del(options, "=keyvalue-pairs"); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-rbd-New-parameter-auth-client-required.patch b/SOURCES/kvm-rbd-New-parameter-auth-client-required.patch new file mode 100644 index 0000000..b95bd48 --- /dev/null +++ b/SOURCES/kvm-rbd-New-parameter-auth-client-required.patch @@ -0,0 +1,187 @@ +From 92e418ec44b35eedff728cc692a09bd001d0762e Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Mon, 18 Jun 2018 08:43:29 +0200 +Subject: [PATCH 22/54] rbd: New parameter auth-client-required + +RH-Author: Markus Armbruster +Message-id: <20180618084330.30009-23-armbru@redhat.com> +Patchwork-id: 80731 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 22/23] rbd: New parameter auth-client-required +Bugzilla: 1557995 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Parameter auth-client-required lets you configure authentication +methods. We tried to provide that in v2.9.0, but backed out due to +interface design doubts (commit 464444fcc16). + +This commit is similar to what we backed out, but simpler: we use a +list of enumeration values instead of a list of objects with a member +of enumeration type. + +Let's review our reasons for backing out the first try, as stated in +the commit message: + + * The implementation uses deprecated rados_conf_set() key + "auth_supported". No biggie. + +Fixed: we use "auth-client-required". + + * The implementation makes -drive silently ignore invalid parameters + "auth" and "auth-supported.*.X" where X isn't "auth". Fixable (in + fact I'm going to fix similar bugs around parameter server), so + again no biggie. + +That fix is commit 2836284db60. This commit doesn't bring the bugs +back. + + * BlockdevOptionsRbd member @password-secret applies only to + authentication method cephx. Should it be a variant member of + RbdAuthMethod? + +We've had time to ponder, and we decided to stick to the way Ceph +configuration works: the key configured separately, and silently +ignored if the authentication method doesn't use it. + + * BlockdevOptionsRbd member @user could apply to both methods cephx + and none, but I'm not sure it's actually used with none. If it + isn't, should it be a variant member of RbdAuthMethod? + +Likewise. + + * The client offers a *set* of authentication methods, not a list. + Should the methods be optional members of BlockdevOptionsRbd instead + of members of list @auth-supported? The latter begs the question + what multiple entries for the same method mean. Trivial question + now that RbdAuthMethod contains nothing but @type, but less so when + RbdAuthMethod acquires other members, such the ones discussed above. + +Again, we decided to stick to the way Ceph configuration works, except +we make auth-client-required a list of enumeration values instead of a +string containing keywords separated by delimiters. + + * How BlockdevOptionsRbd member @auth-supported interacts with + settings from a configuration file specified with @conf is + undocumented. I suspect it's untested, too. + +Not actually true, the documentation for @conf says "Values in the +configuration file will be overridden by options specified via QAPI", +and we've tested this. + +Signed-off-by: Markus Armbruster +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit a3699de4dde82bc76b33a83798a9da82c2336cce) +Signed-off-by: Miroslav Rezanina +--- + block/rbd.c | 42 ++++++++++++++++++++++++++++++++---------- + qapi/block-core.json | 13 +++++++++++++ + 2 files changed, 45 insertions(+), 10 deletions(-) + +diff --git a/block/rbd.c b/block/rbd.c +index c834d72..9c0903f 100644 +--- a/block/rbd.c ++++ b/block/rbd.c +@@ -233,20 +233,42 @@ done: + + + static int qemu_rbd_set_auth(rados_t cluster, const char *secretid, ++ BlockdevOptionsRbd *opts, + Error **errp) + { +- if (secretid == 0) { +- return 0; +- } ++ char *acr; ++ int r; ++ GString *accu; ++ RbdAuthModeList *auth; ++ ++ if (secretid) { ++ gchar *secret = qcrypto_secret_lookup_as_base64(secretid, ++ errp); ++ if (!secret) { ++ return -1; ++ } + +- gchar *secret = qcrypto_secret_lookup_as_base64(secretid, +- errp); +- if (!secret) { +- return -1; ++ rados_conf_set(cluster, "key", secret); ++ g_free(secret); + } + +- rados_conf_set(cluster, "key", secret); +- g_free(secret); ++ if (opts->has_auth_client_required) { ++ accu = g_string_new(""); ++ for (auth = opts->auth_client_required; auth; auth = auth->next) { ++ if (accu->str[0]) { ++ g_string_append_c(accu, ';'); ++ } ++ g_string_append(accu, RbdAuthMode_str(auth->value)); ++ } ++ acr = g_string_free(accu, FALSE); ++ r = rados_conf_set(cluster, "auth_client_required", acr); ++ g_free(acr); ++ if (r < 0) { ++ error_setg_errno(errp, -r, ++ "Could not set 'auth_client_required'"); ++ return r; ++ } ++ } + + return 0; + } +@@ -578,7 +600,7 @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx, + } + } + +- if (qemu_rbd_set_auth(*cluster, secretid, errp) < 0) { ++ if (qemu_rbd_set_auth(*cluster, secretid, opts, errp) < 0) { + r = -EIO; + goto failed_shutdown; + } +diff --git a/qapi/block-core.json b/qapi/block-core.json +index b38d5d6..28001fb 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -3170,6 +3170,14 @@ + + + ## ++# @RbdAuthMode: ++# ++# Since: 3.0 ++## ++{ 'enum': 'RbdAuthMode', ++ 'data': [ 'cephx', 'none' ] } ++ ++## + # @BlockdevOptionsRbd: + # + # @pool: Ceph pool name. +@@ -3184,6 +3192,10 @@ + # + # @user: Ceph id name. + # ++# @auth-client-required: Acceptable authentication modes. ++# This maps to Ceph configuration option ++# "auth_client_required". (Since 3.0) ++# + # @server: Monitor host address and port. This maps + # to the "mon_host" Ceph option. + # +@@ -3195,6 +3207,7 @@ + '*conf': 'str', + '*snapshot': 'str', + '*user': 'str', ++ '*auth-client-required': ['RbdAuthMode'], + '*server': ['InetSocketAddressBase'] } } + + ## +-- +1.8.3.1 + diff --git a/SOURCES/kvm-rbd-New-parameter-key-secret.patch b/SOURCES/kvm-rbd-New-parameter-key-secret.patch new file mode 100644 index 0000000..6f027c0 --- /dev/null +++ b/SOURCES/kvm-rbd-New-parameter-key-secret.patch @@ -0,0 +1,162 @@ +From c4b9fcd4bf4179a565e2f10d4c93ef6801007270 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Mon, 18 Jun 2018 08:43:30 +0200 +Subject: [PATCH 23/54] rbd: New parameter key-secret + +RH-Author: Markus Armbruster +Message-id: <20180618084330.30009-24-armbru@redhat.com> +Patchwork-id: 80727 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 23/23] rbd: New parameter key-secret +Bugzilla: 1557995 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +Legacy -drive supports "password-secret" parameter that isn't +available with -blockdev / blockdev-add. That's because we backed out +our first try to provide it there due to interface design doubts, in +commit 577d8c9a811, v2.9.0. + +This is the second try. It brings back the parameter, except it's +named "key-secret" now. + +Let's review our reasons for backing out the first try, as stated in +the commit message: + + * BlockdevOptionsRbd member @password-secret isn't actually a + password, it's a key generated by Ceph. + +Addressed by the rename. + + * We're not sure where member @password-secret belongs (see the + previous commit). + +See previous commit. + + * How @password-secret interacts with settings from a configuration + file specified with @conf is undocumented. + +Not actually true, the documentation for @conf says "Values in the +configuration file will be overridden by options specified via QAPI", +and we've tested this. + +Signed-off-by: Markus Armbruster +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit d083f954a95d37b460df0c2fbfe46ad7eb207b10) +[Conflict due to lack of commit e8e16d4baff "rbd: Switch to byte-based +callbacks" trivially resolved] + +Signed-off-by: Miroslav Rezanina +--- + block/rbd.c | 41 +++++++++++++++++++++++++---------------- + qapi/block-core.json | 6 ++++++ + 2 files changed, 31 insertions(+), 16 deletions(-) + +diff --git a/block/rbd.c b/block/rbd.c +index 9c0903f..3242bcd 100644 +--- a/block/rbd.c ++++ b/block/rbd.c +@@ -232,24 +232,25 @@ done: + } + + +-static int qemu_rbd_set_auth(rados_t cluster, const char *secretid, +- BlockdevOptionsRbd *opts, ++static int qemu_rbd_set_auth(rados_t cluster, BlockdevOptionsRbd *opts, + Error **errp) + { +- char *acr; ++ char *key, *acr; + int r; + GString *accu; + RbdAuthModeList *auth; + +- if (secretid) { +- gchar *secret = qcrypto_secret_lookup_as_base64(secretid, +- errp); +- if (!secret) { +- return -1; ++ if (opts->key_secret) { ++ key = qcrypto_secret_lookup_as_base64(opts->key_secret, errp); ++ if (!key) { ++ return -EIO; ++ } ++ r = rados_conf_set(cluster, "key", key); ++ g_free(key); ++ if (r < 0) { ++ error_setg_errno(errp, -r, "Could not set 'key'"); ++ return r; + } +- +- rados_conf_set(cluster, "key", secret); +- g_free(secret); + } + + if (opts->has_auth_client_required) { +@@ -360,9 +361,7 @@ static QemuOptsList runtime_opts = { + }, + }; + +-/* FIXME Deprecate and remove keypairs or make it available in QMP. +- * password_secret should eventually be configurable in opts->location. Support +- * for it in .bdrv_open will make it work here as well. */ ++/* FIXME Deprecate and remove keypairs or make it available in QMP. */ + static int qemu_rbd_do_create(BlockdevCreateOptions *options, + const char *keypairs, const char *password_secret, + Error **errp) +@@ -568,6 +567,16 @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx, + Error *local_err = NULL; + int r; + ++ if (secretid) { ++ if (opts->key_secret) { ++ error_setg(errp, ++ "Legacy 'password-secret' clashes with 'key-secret'"); ++ return -EINVAL; ++ } ++ opts->key_secret = g_strdup(secretid); ++ opts->has_key_secret = true; ++ } ++ + mon_host = qemu_rbd_mon_host(opts, &local_err); + if (local_err) { + error_propagate(errp, local_err); +@@ -600,8 +609,8 @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx, + } + } + +- if (qemu_rbd_set_auth(*cluster, secretid, opts, errp) < 0) { +- r = -EIO; ++ r = qemu_rbd_set_auth(*cluster, opts, errp); ++ if (r < 0) { + goto failed_shutdown; + } + +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 28001fb..46469be 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -3196,6 +3196,11 @@ + # This maps to Ceph configuration option + # "auth_client_required". (Since 3.0) + # ++# @key-secret: ID of a QCryptoSecret object providing a key ++# for cephx authentication. ++# This maps to Ceph configuration option ++# "key". (Since 3.0) ++# + # @server: Monitor host address and port. This maps + # to the "mon_host" Ceph option. + # +@@ -3208,6 +3213,7 @@ + '*snapshot': 'str', + '*user': 'str', + '*auth-client-required': ['RbdAuthMode'], ++ '*key-secret': 'str', + '*server': ['InetSocketAddressBase'] } } + + ## +-- +1.8.3.1 + diff --git a/SOURCES/kvm-redhat-Define-the-pseries-rhel7.3-sxxm-machine-type.patch b/SOURCES/kvm-redhat-Define-the-pseries-rhel7.3-sxxm-machine-type.patch deleted file mode 100644 index 7442514..0000000 --- a/SOURCES/kvm-redhat-Define-the-pseries-rhel7.3-sxxm-machine-type.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 7acdd1342ff5e62360250b4ff60768e91c070864 Mon Sep 17 00:00:00 2001 -From: Suraj Jitindar Singh -Date: Tue, 13 Mar 2018 05:21:39 +0100 -Subject: [PATCH 17/17] redhat: Define the pseries-rhel7.3-sxxm machine type - -RH-Author: Suraj Jitindar Singh -Message-id: <1520918499-27663-12-git-send-email-sursingh@redhat.com> -Patchwork-id: 79247 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 11/11] redhat: Define the pseries-rhel7.3-sxxm machine type -Bugzilla: 1554957 -RH-Acked-by: David Gibson -RH-Acked-by: Laurent Vivier -RH-Acked-by: Miroslav Rezanina - -The sxxm (speculative execution exploit mitigation) machine type is a -variant of the 7.3 machine type with workarounds for speculative -execution vulnerabilities enabled by default. - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1548919 - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr.c | 22 ++++++++++++++++++++++ - 1 file changed, 22 insertions(+) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 3d210b3..fa07a75 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -4263,6 +4263,28 @@ static void spapr_machine_rhel730_class_options(MachineClass *mc) - DEFINE_SPAPR_MACHINE(rhel730, "rhel7.3.0", false); - - /* -+ * pseries-rhel7.3.0-sxxm -+ * -+ * pseries-rhel7.3.0 with speculative execution exploit mitigations enabled by default -+ */ -+static void spapr_machine_rhel730sxxm_instance_options(MachineState *machine) -+{ -+ spapr_machine_rhel730_instance_options(machine); -+} -+ -+static void spapr_machine_rhel730sxxm_class_options(MachineClass *mc) -+{ -+ sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); -+ -+ spapr_machine_rhel730_class_options(mc); -+ smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND; -+ smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND; -+ smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_FIXED_CCD; -+} -+ -+DEFINE_SPAPR_MACHINE(rhel730sxxm, "rhel7.3.0-sxxm", false); -+ -+/* - * pseries-rhel7.2.0 - */ - /* Should be like SPAPR_COMPAT_2_5 + 2_4 + 2_3, but "dynamic-reconfiguration" --- -1.8.3.1 - diff --git a/SOURCES/kvm-redhat-Define-the-pseries-rhel7.4-sxxm-machine-type.patch b/SOURCES/kvm-redhat-Define-the-pseries-rhel7.4-sxxm-machine-type.patch deleted file mode 100644 index 07469ed..0000000 --- a/SOURCES/kvm-redhat-Define-the-pseries-rhel7.4-sxxm-machine-type.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 4921c669250aa91ce11c041568c0de093c211e29 Mon Sep 17 00:00:00 2001 -From: Suraj Jitindar Singh -Date: Tue, 13 Mar 2018 05:21:38 +0100 -Subject: [PATCH 16/17] redhat: Define the pseries-rhel7.4-sxxm machine type - -RH-Author: Suraj Jitindar Singh -Message-id: <1520918499-27663-11-git-send-email-sursingh@redhat.com> -Patchwork-id: 79256 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 10/11] redhat: Define the pseries-rhel7.4-sxxm machine type -Bugzilla: 1554957 -RH-Acked-by: David Gibson -RH-Acked-by: Laurent Vivier -RH-Acked-by: Miroslav Rezanina - -The sxxm (speculative execution exploit mitigation) machine type is a -variant of the 7.4 machine type with workarounds for speculative -execution vulnerabilities enabled by default. - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1548919 - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr.c | 22 ++++++++++++++++++++++ - 1 file changed, 22 insertions(+) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 9d63c00..3d210b3 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -4189,6 +4189,28 @@ static void spapr_machine_rhel740_class_options(MachineClass *mc) - DEFINE_SPAPR_MACHINE(rhel740, "rhel7.4.0", false); - - /* -+ * pseries-rhel7.4.0-sxxm -+ * -+ * pseries-rhel7.4.0 with speculative execution exploit mitigations enabled by default -+ */ -+static void spapr_machine_rhel740sxxm_instance_options(MachineState *machine) -+{ -+ spapr_machine_rhel740_instance_options(machine); -+} -+ -+static void spapr_machine_rhel740sxxm_class_options(MachineClass *mc) -+{ -+ sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); -+ -+ spapr_machine_rhel740_class_options(mc); -+ smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND; -+ smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND; -+ smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_FIXED_CCD; -+} -+ -+DEFINE_SPAPR_MACHINE(rhel740sxxm, "rhel7.4.0-sxxm", false); -+ -+/* - * pseries-rhel7.3.0 - * like SPAPR_COMPAT_2_6/_2_7/_2_8 but "ddw" has been backported to RHEL7_3 - */ --- -1.8.3.1 - diff --git a/SOURCES/kvm-redhat-Define-the-pseries-rhel7.5-sxxm-machine-type.patch b/SOURCES/kvm-redhat-Define-the-pseries-rhel7.5-sxxm-machine-type.patch deleted file mode 100644 index f623c7f..0000000 --- a/SOURCES/kvm-redhat-Define-the-pseries-rhel7.5-sxxm-machine-type.patch +++ /dev/null @@ -1,62 +0,0 @@ -From ac371ebbc83fd09970f259f77481956673c885cf Mon Sep 17 00:00:00 2001 -From: Suraj Jitindar Singh -Date: Tue, 13 Mar 2018 05:21:37 +0100 -Subject: [PATCH 15/17] redhat: Define the pseries-rhel7.5-sxxm machine type - -RH-Author: Suraj Jitindar Singh -Message-id: <1520918499-27663-10-git-send-email-sursingh@redhat.com> -Patchwork-id: 79250 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 09/11] redhat: Define the pseries-rhel7.5-sxxm machine type -Bugzilla: 1554957 -RH-Acked-by: David Gibson -RH-Acked-by: Laurent Vivier -RH-Acked-by: Miroslav Rezanina - -The sxxm (speculative execution exploit mitigation) machine type is a -variant of the 7.5 machine type with workarounds for speculative -execution vulnerabilities enabled by default. - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1548919 - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr.c | 22 ++++++++++++++++++++++ - 1 file changed, 22 insertions(+) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index a43e64c..9d63c00 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -4131,6 +4131,28 @@ static void spapr_machine_rhel750_class_options(MachineClass *mc) - - DEFINE_SPAPR_MACHINE(rhel750, "rhel7.5.0", true); - -+/* -+ * pseries-rhel7.5.0-sxxm -+ * -+ * pseries-rhel7.5.0 with speculative execution exploit mitigations enabled by default -+ */ -+static void spapr_machine_rhel750sxxm_instance_options(MachineState *machine) -+{ -+ spapr_machine_rhel750_instance_options(machine); -+} -+ -+static void spapr_machine_rhel750sxxm_class_options(MachineClass *mc) -+{ -+ sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); -+ -+ spapr_machine_rhel750_class_options(mc); -+ smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND; -+ smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND; -+ smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_FIXED_CCD; -+} -+ -+DEFINE_SPAPR_MACHINE(rhel750sxxm, "rhel7.5.0-sxxm", false); -+ - #if defined(CONFIG_RHV) - - /* --- -1.8.3.1 - diff --git a/SOURCES/kvm-redhat-add-CONFIG_RHV-flag.patch b/SOURCES/kvm-redhat-add-CONFIG_RHV-flag.patch deleted file mode 100644 index 365d2b2..0000000 --- a/SOURCES/kvm-redhat-add-CONFIG_RHV-flag.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 4506913c42c58ef5a667779596af1c4bd1b11102 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Fri, 6 Oct 2017 16:04:07 +0200 -Subject: [PATCH 04/69] redhat: add CONFIG_RHV flag - -RH-Author: Laurent Vivier -Message-id: <20171006160407.18609-1-lvivier@redhat.com> -Patchwork-id: 76906 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH v3] redhat: add CONFIG_RHV flag -Bugzilla: 1498865 -RH-Acked-by: Miroslav Rezanina -RH-Acked-by: Thomas Huth -RH-Acked-by: Laszlo Ersek - -We need to know if the binaries we build are for qemu-kvm-rhev -or qemu-kvm-ma. - -Add an option to configure to select the target: ---rhel-target=rhv for qemu-kvm-rhev or ---rhel-target=rhel for qemu-kvm-ma. - -If RHEL target is rhv, the CONFIG_RHV macro is defined. -By default, configure selects "rhv" target. - -Signed-off-by: Laurent Vivier -Signed-off-by: Miroslav Rezanina ---- - configure | 9 +++++++++ - redhat/Makefile | 2 +- - redhat/Makefile.local | 1 + - redhat/build_configure.sh | 9 +++++++++ - redhat/qemu-kvm.spec.template | 5 +++++ - 5 files changed, 25 insertions(+), 1 deletion(-) - -diff --git a/configure b/configure -index 457b2ff..0da6821 100755 ---- a/configure -+++ b/configure -@@ -407,6 +407,7 @@ jemalloc="no" - replication="yes" - vxhs="" - vtd="yes" -+rhel_target="rhv" - - supported_cpu="no" - supported_os="no" -@@ -1301,6 +1302,8 @@ for opt do - ;; - --enable-vtd) vtd="yes" - ;; -+ --rhel-target=*) rhel_target="$optarg" -+ ;; - *) - echo "ERROR: unknown option $opt" - echo "Try '$0 --help' for more information" -@@ -1469,6 +1472,7 @@ Advanced options (experts only): - xen pv domain builder - --enable-debug-stack-usage - track the maximum stack usage of stacks created by qemu_alloc_stack -+ --rhel-target set RHEL target (rhv or rhel) - - Optional features, enabled with --enable-FEATURE and - disabled with --disable-FEATURE, default is enabled if available: -@@ -5395,6 +5399,7 @@ echo "avx2 optimization $avx2_opt" - echo "replication support $replication" - echo "VxHS block device $vxhs" - echo "VT-d emulation $vtd" -+echo "RHEL target $rhel_target" - - if test "$sdl_too_old" = "yes"; then - echo "-> Your SDL version is too old - please upgrade to have SDL support" -@@ -6064,6 +6069,10 @@ if test "$vtd" = "yes" ; then - echo "CONFIG_VTD=y" >> $config_host_mak - fi - -+if test "$rhel_target" = "rhv" ; then -+ echo "CONFIG_RHV=y" >> $config_host_mak -+fi -+ - if test "$tcg_interpreter" = "yes"; then - QEMU_INCLUDES="-I\$(SRC_PATH)/tcg/tci $QEMU_INCLUDES" - elif test "$ARCH" = "sparc64" ; then --- -1.8.3.1 - diff --git a/SOURCES/kvm-redhat-define-HW_COMPAT_RHEL7_4.patch b/SOURCES/kvm-redhat-define-HW_COMPAT_RHEL7_4.patch deleted file mode 100644 index 114e46d..0000000 --- a/SOURCES/kvm-redhat-define-HW_COMPAT_RHEL7_4.patch +++ /dev/null @@ -1,51 +0,0 @@ -From ea157600dac6db592419ad9a8562ad86a8103627 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Mon, 9 Oct 2017 14:23:15 +0200 -Subject: [PATCH 06/69] redhat: define HW_COMPAT_RHEL7_4 - -RH-Author: Laurent Vivier -Message-id: <20171009142318.6262-2-lvivier@redhat.com> -Patchwork-id: 77033 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 1/4] redhat: define HW_COMPAT_RHEL7_4 -Bugzilla: 1478478 -RH-Acked-by: David Gibson -RH-Acked-by: Thomas Huth -RH-Acked-by: Dr. David Alan Gilbert - -Signed-off-by: Laurent Vivier -Signed-off-by: Miroslav Rezanina ---- - include/hw/compat.h | 19 +++++++++++++++++++ - 1 file changed, 19 insertions(+) - -diff --git a/include/hw/compat.h b/include/hw/compat.h -index aa616e3..85c6cbe 100644 ---- a/include/hw/compat.h -+++ b/include/hw/compat.h -@@ -413,4 +413,23 @@ - .value = "off",\ - }, - -+/* Mostly like HW_COMPAT_2_9 except -+ * x-mtu-bypass-backend has already been -+ * backported to RHEL7.4 -+ */ -+#define HW_COMPAT_RHEL7_4 \ -+ { /* HW_COMPAT_RHEL7_4 */ \ -+ .driver = "pci-bridge",\ -+ .property = "shpc",\ -+ .value = "off",\ -+ },{ /* HW_COMPAT_RHEL7_4 */ \ -+ .driver = "intel-iommu",\ -+ .property = "pt",\ -+ .value = "off",\ -+ },{ /* HW_COMPAT_RHEL7_4 */ \ -+ .driver = "pcie-root-port",\ -+ .property = "x-migrate-msix",\ -+ .value = "false",\ -+ }, -+ - #endif /* HW_COMPAT_H */ --- -1.8.3.1 - diff --git a/SOURCES/kvm-redhat-define-HW_COMPAT_RHEL7_5.patch b/SOURCES/kvm-redhat-define-HW_COMPAT_RHEL7_5.patch new file mode 100644 index 0000000..030f15d --- /dev/null +++ b/SOURCES/kvm-redhat-define-HW_COMPAT_RHEL7_5.patch @@ -0,0 +1,61 @@ +From 49805edee0bec708c9f59e87bd17edb03acca9f6 Mon Sep 17 00:00:00 2001 +From: Laurent Vivier +Date: Fri, 1 Jun 2018 08:30:38 +0200 +Subject: [PATCH 3/8] redhat: define HW_COMPAT_RHEL7_5 + +RH-Author: Laurent Vivier +Message-id: <20180524141145.7532-2-lvivier@redhat.com> +Patchwork-id: 80471 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/2] redhat: define HW_COMPAT_RHEL7_5 +Bugzilla: 1557054 +RH-Acked-by: Eduardo Habkost +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek + +Signed-off-by: Laurent Vivier +Signed-off-by: Miroslav Rezanina +--- + include/hw/compat.h | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/include/hw/compat.h b/include/hw/compat.h +index 666eed9..d711b5c5 100644 +--- a/include/hw/compat.h ++++ b/include/hw/compat.h +@@ -478,4 +478,33 @@ + .value = "false",\ + }, + ++/* like HW_COMPAT_2_10 and HW_COMPAT_2_11 ++ */ ++#define HW_COMPAT_RHEL7_5 \ ++ { /* HW_COMPAT_RHEL7_5 */ \ ++ .driver = "hpet",\ ++ .property = "hpet-offset-saved",\ ++ .value = "false",\ ++ },{ /* HW_COMPAT_RHEL7_5 */ \ ++ .driver = "virtio-blk-pci",\ ++ .property = "vectors",\ ++ .value = "2",\ ++ },{ /* HW_COMPAT_RHEL7_5 */ \ ++ .driver = "vhost-user-blk-pci",\ ++ .property = "vectors",\ ++ .value = "2",\ ++ },{ /* HW_COMPAT_RHEL7_5 */ \ ++ .driver = "e1000",\ ++ .property = "migrate_tso_props",\ ++ .value = "off",\ ++ },{ /* HW_COMPAT_RHEL7_5 */ \ ++ .driver = "virtio-mouse-device",\ ++ .property = "wheel-axis",\ ++ .value = "false",\ ++ },{ /* HW_COMPAT_RHEL7_5 */ \ ++ .driver = "virtio-tablet-device",\ ++ .property = "wheel-axis",\ ++ .value = "false",\ ++ }, ++ + #endif /* HW_COMPAT_H */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-redhat-define-pseries-rhel7.5.0-machine-type.patch b/SOURCES/kvm-redhat-define-pseries-rhel7.5.0-machine-type.patch deleted file mode 100644 index 98030db..0000000 --- a/SOURCES/kvm-redhat-define-pseries-rhel7.5.0-machine-type.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 86ef5cd189077ab6a1a3b55ed844408c1ba8f75a Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Mon, 9 Oct 2017 14:23:16 +0200 -Subject: [PATCH 07/69] redhat: define pseries-rhel7.5.0 machine type - -RH-Author: Laurent Vivier -Message-id: <20171009142318.6262-3-lvivier@redhat.com> -Patchwork-id: 77034 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 2/4] redhat: define pseries-rhel7.5.0 machine type -Bugzilla: 1478478 -RH-Acked-by: David Gibson -RH-Acked-by: Thomas Huth -RH-Acked-by: Laszlo Ersek - -As we don't support migration from PEGAS 1.0, pseries-rhel7.4.0alt is removed -(replaced) in this patch. - -Signed-off-by: Laurent Vivier -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr.c | 29 ++++++++++++++++++++++------- - 1 file changed, 22 insertions(+), 7 deletions(-) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 30b2c5b..cb317f8 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -3946,32 +3946,47 @@ DEFINE_SPAPR_MACHINE(2_1, "2.1", false); - #endif - - /* -- * pseries-rhel7.4.0alt -+ * pseries-rhel7.5.0 - */ --static void spapr_machine_rhel740alt_instance_options(MachineState *machine) -+ -+static void spapr_machine_rhel750_instance_options(MachineState *machine) - { - } - --static void spapr_machine_rhel740alt_class_options(MachineClass *mc) -+static void spapr_machine_rhel750_class_options(MachineClass *mc) - { - /* Defaults for the latest behaviour inherited from the base class */ - } - --DEFINE_SPAPR_MACHINE(rhel740alt, "rhel7.4.0alt", true); -- -+DEFINE_SPAPR_MACHINE(rhel750, "rhel7.5.0", true); - - /* - * pseries-rhel7.4.0 -+ * like SPAPR_COMPAT_2_9 - */ - -+#define SPAPR_COMPAT_RHEL7_4 \ -+ HW_COMPAT_RHEL7_4 \ -+ { \ -+ .driver = TYPE_POWERPC_CPU, \ -+ .property = "pre-2.10-migration", \ -+ .value = "on", \ -+ }, \ -+ - static void spapr_machine_rhel740_instance_options(MachineState *machine) - { -- spapr_machine_rhel740alt_instance_options(machine); -+ spapr_machine_rhel750_instance_options(machine); - } - - static void spapr_machine_rhel740_class_options(MachineClass *mc) - { -- spapr_machine_rhel740alt_class_options(mc); -+ sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); -+ -+ spapr_machine_rhel750_class_options(mc); -+ SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_RHEL7_4); -+ mc->numa_auto_assign_ram = numa_legacy_auto_assign_ram; -+ smc->pre_2_10_has_unused_icps = true; -+ smc->resize_hpt_default = SPAPR_RESIZE_HPT_DISABLED; - } - - DEFINE_SPAPR_MACHINE(rhel740, "rhel7.4.0", false); --- -1.8.3.1 - diff --git a/SOURCES/kvm-redhat-define-pseries-rhel7.6.0-machine-types.patch b/SOURCES/kvm-redhat-define-pseries-rhel7.6.0-machine-types.patch new file mode 100644 index 0000000..c36213a --- /dev/null +++ b/SOURCES/kvm-redhat-define-pseries-rhel7.6.0-machine-types.patch @@ -0,0 +1,72 @@ +From 7b1ad037d92201aee894afd9cc70a852721f2d9d Mon Sep 17 00:00:00 2001 +From: Laurent Vivier +Date: Thu, 24 May 2018 14:11:45 +0200 +Subject: [PATCH 4/8] redhat: define pseries-rhel7.6.0 machine types + +RH-Author: Laurent Vivier +Message-id: <20180524141145.7532-3-lvivier@redhat.com> +Patchwork-id: 80470 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 2/2] redhat: define pseries-rhel7.6.0 machine types +Bugzilla: 1557054 +RH-Acked-by: Eduardo Habkost +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Miroslav Rezanina + +Signed-off-by: Laurent Vivier +Signed-off-by: Miroslav Rezanina +--- + hw/ppc/spapr.c | 26 ++++++++++++++++++++++++-- + 1 file changed, 24 insertions(+), 2 deletions(-) + +diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c +index 6f005a0..e2df370 100644 +--- a/hw/ppc/spapr.c ++++ b/hw/ppc/spapr.c +@@ -4354,19 +4354,41 @@ DEFINE_SPAPR_MACHINE(2_1, "2.1", false); + #endif + + /* ++ * pseries-rhel7.6.0 ++ */ ++ ++static void spapr_machine_rhel760_instance_options(MachineState *machine) ++{ ++} ++ ++static void spapr_machine_rhel760_class_options(MachineClass *mc) ++{ ++ /* Defaults for the latest behaviour inherited from the base class */ ++} ++ ++DEFINE_SPAPR_MACHINE(rhel760, "rhel7.6.0", true); ++ ++/* + * pseries-rhel7.5.0 ++ * like SPAPR_COMPAT_2_11 and SPAPR_COMPAT_2_10 ++ * SPAPR_CAP_HTM already enabled in 7.4 ++ * + */ ++#define SPAPR_COMPAT_RHEL7_5 \ ++ HW_COMPAT_RHEL7_5 \ + + static void spapr_machine_rhel750_instance_options(MachineState *machine) + { ++ spapr_machine_rhel760_instance_options(machine); + } + + static void spapr_machine_rhel750_class_options(MachineClass *mc) + { +- /* Defaults for the latest behaviour inherited from the base class */ ++ spapr_machine_rhel760_class_options(mc); ++ SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_RHEL7_5); + } + +-DEFINE_SPAPR_MACHINE(rhel750, "rhel7.5.0", true); ++DEFINE_SPAPR_MACHINE(rhel750, "rhel7.5.0", false); + + /* + * pseries-rhel7.5.0-sxxm +-- +1.8.3.1 + diff --git a/SOURCES/kvm-redhat-fix-HW_COMPAT_RHEL7_3.patch b/SOURCES/kvm-redhat-fix-HW_COMPAT_RHEL7_3.patch deleted file mode 100644 index 077104b..0000000 --- a/SOURCES/kvm-redhat-fix-HW_COMPAT_RHEL7_3.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 58702e8dbb2b2abc09b737d55d633228329d7256 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Thu, 5 Oct 2017 08:16:15 +0200 -Subject: [PATCH 09/34] redhat: fix HW_COMPAT_RHEL7_3 - -RH-Author: Laurent Vivier -Message-id: <20171005081615.20677-1-lvivier@redhat.com> -Patchwork-id: 76810 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH] redhat: fix HW_COMPAT_RHEL7_3 -Bugzilla: 1498754 -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Thomas Huth -RH-Acked-by: Stefan Hajnoczi - -BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1498754 -BREW: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=14179622 -Upstream-status: downstream only - -x-mtu-bypass-backend has been added to HW_COMPAT_2_1 instead of -HW_COMPAT_RHEL7_3. Fix that. - -Signed-off-by: Laurent Vivier -Signed-off-by: Miroslav Rezanina ---- - include/hw/compat.h | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/include/hw/compat.h b/include/hw/compat.h -index 56cefc9..aa616e3 100644 ---- a/include/hw/compat.h -+++ b/include/hw/compat.h -@@ -227,10 +227,6 @@ - .driver = "virtio-pci",\ - .property = "virtio-pci-bus-master-bug-migration",\ - .value = "on",\ -- },{ /* HW_COMPAT_RHEL7_3 */ \ -- .driver = "virtio-net-device",\ -- .property = "x-mtu-bypass-backend",\ -- .value = "off",\ - }, - - /* Mostly like HW_COMPAT_2_1 but: -@@ -411,6 +407,10 @@ - .driver = "e1000e",\ - .property = "__redhat_e1000e_7_3_intr_state",\ - .value = "on",\ -+ },{ /* HW_COMPAT_RHEL7_3 */ \ -+ .driver = "virtio-net-device",\ -+ .property = "x-mtu-bypass-backend",\ -+ .value = "off",\ - }, - - #endif /* HW_COMPAT_H */ --- -1.8.3.1 - diff --git a/SOURCES/kvm-redhat-globally-limit-the-maximum-number-of-CPUs.patch b/SOURCES/kvm-redhat-globally-limit-the-maximum-number-of-CPUs.patch deleted file mode 100644 index 4a288ed..0000000 --- a/SOURCES/kvm-redhat-globally-limit-the-maximum-number-of-CPUs.patch +++ /dev/null @@ -1,77 +0,0 @@ -From bb722e9effd08ea9d64091914c6f09d061017cad Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 9 Jan 2018 10:32:52 +0100 -Subject: [PATCH 02/12] redhat: globally limit the maximum number of CPUs - -RH-Author: David Hildenbrand -Message-id: <20180109103253.24517-2-david@redhat.com> -Patchwork-id: 78531 -O-Subject: [RHEL-7.5 qemu-kvm-ma PATCH v2 1/2] redhat: globally limit the maximum number of CPUs -Bugzilla: 1527449 -RH-Acked-by: David Gibson -RH-Acked-by: Thomas Huth -RH-Acked-by: Cornelia Huck - -Upstream-status: n/a - -For RHEL, we support 240, for RHV up to 384 VCPUs. Let's limit this -globally instead of fixing up all machines. This way, we can easily -change (increase) the product specific levels later. - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - vl.c | 23 +++++++++++++++++++++++ - 1 file changed, 23 insertions(+) - -diff --git a/vl.c b/vl.c -index bef5ae3..90b542f 100644 ---- a/vl.c -+++ b/vl.c -@@ -135,6 +135,12 @@ int main(int argc, char **argv) - #define MAX_VIRTIO_CONSOLES 1 - #define MAX_SCLP_CONSOLES 1 - -+#if defined(CONFIG_RHV) -+#define RHEL_MAX_CPUS 384 -+#else -+#define RHEL_MAX_CPUS 240 -+#endif -+ - static const char *data_dir[16]; - static int data_dir_idx; - const char *bios_name = NULL; -@@ -1501,6 +1507,20 @@ MachineClass *find_default_machine(void) - return mc; - } - -+/* Maximum number of CPUs limited for Red Hat Enterprise Linux */ -+static void limit_max_cpus_in_machines(void) -+{ -+ GSList *el, *machines = object_class_get_list(TYPE_MACHINE, false); -+ -+ for (el = machines; el; el = el->next) { -+ MachineClass *mc = el->data; -+ -+ if (mc->max_cpus > RHEL_MAX_CPUS) { -+ mc->max_cpus = RHEL_MAX_CPUS; -+ } -+ } -+} -+ - MachineInfoList *qmp_query_machines(Error **errp) - { - GSList *el, *machines = object_class_get_list(TYPE_MACHINE, false); -@@ -4130,6 +4150,9 @@ int main(int argc, char **argv, char **envp) - - replay_configure(icount_opts); - -+ /* Maximum number of CPUs limited for Red Hat Enterprise Linux */ -+ limit_max_cpus_in_machines(); -+ - machine_class = select_machine(); - - set_memory_options(&ram_slots, &maxram_size, machine_class); --- -1.8.3.1 - diff --git a/SOURCES/kvm-redhat-remove-manual-max_cpus-limitations-for-ppc.patch b/SOURCES/kvm-redhat-remove-manual-max_cpus-limitations-for-ppc.patch deleted file mode 100644 index ea010eb..0000000 --- a/SOURCES/kvm-redhat-remove-manual-max_cpus-limitations-for-ppc.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 92fef14623387db071a79f64fa7996ce8ea9040e Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 9 Jan 2018 10:32:53 +0100 -Subject: [PATCH 03/12] redhat: remove manual max_cpus limitations for ppc - -RH-Author: David Hildenbrand -Message-id: <20180109103253.24517-3-david@redhat.com> -Patchwork-id: 78532 -O-Subject: [RHEL-7.5 qemu-kvm-ma PATCH v2 2/2] redhat: remove manual max_cpus limitations for ppc -Bugzilla: 1527449 -RH-Acked-by: David Gibson -RH-Acked-by: Thomas Huth -RH-Acked-by: Cornelia Huck - -Upstream-status: n/a - -We now globally limit the number of VCPUs, depending on release type -(RHEL vs. RHV). Especially, there is no way one can specify more than -max_cpus VCPUs for a VM. - -This allows us the restore the ppc max_cpus limitation to the upstream -default and minimize the ppc hack in kvm-all.c. - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - accel/kvm/kvm-all.c | 10 ---------- - hw/ppc/spapr.c | 3 +-- - 2 files changed, 1 insertion(+), 12 deletions(-) - -diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c -index 94c4968..158fe66 100644 ---- a/accel/kvm/kvm-all.c -+++ b/accel/kvm/kvm-all.c -@@ -1629,21 +1629,11 @@ static int kvm_init(MachineState *ms) - - #ifdef HOST_PPC64 - /* -- * RHEL hack: -- * - * On POWER, the kernel advertises a soft limit based on the - * number of CPU threads on the host. We want to allow exceeding - * this for testing purposes, so we don't want to set hard limit - * to soft limit as on x86. -- * -- * However the POWER hard limit advertised by the kernel is 2048 -- * (== NR_CPUS) but we only want to allow up to the number of -- * vCPUs we actually test, so we force the hard limit to 384 - */ -- hard_vcpus_limit = 384; -- if (soft_vcpus_limit > hard_vcpus_limit) { -- soft_vcpus_limit = hard_vcpus_limit; -- } - #else - /* RHEL doesn't support nr_vcpus > soft_vcpus_limit */ - hard_vcpus_limit = soft_vcpus_limit; -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index d320b6c..d7fac62 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -3586,8 +3586,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) - mc->init = ppc_spapr_init; - mc->reset = ppc_spapr_reset; - mc->block_default_type = IF_SCSI; -- /* RHEL: set to max # of supported vcpus */ -- mc->max_cpus = 384; -+ mc->max_cpus = 1024; - mc->no_parallel = 1; - mc->default_boot_order = ""; - mc->default_ram_size = 512 * M_BYTE; --- -1.8.3.1 - diff --git a/SOURCES/kvm-remove-duplicate-HW_COMPAT_RHEL7_5.patch b/SOURCES/kvm-remove-duplicate-HW_COMPAT_RHEL7_5.patch new file mode 100644 index 0000000..b649d61 --- /dev/null +++ b/SOURCES/kvm-remove-duplicate-HW_COMPAT_RHEL7_5.patch @@ -0,0 +1,66 @@ +From 9a021c064ee477faa45d396ab2c0174483711733 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 13 Jun 2018 10:40:25 +0200 +Subject: [PATCH 3/9] remove duplicate HW_COMPAT_RHEL7_5 + +RH-Author: Gerd Hoffmann +Message-id: <20180613104026.4395-2-kraxel@redhat.com> +Patchwork-id: 80654 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/2] remove duplicate HW_COMPAT_RHEL7_5 +Bugzilla: 1542080 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Daniel P. Berrange + +There are *two* HW_COMPAT_RHEL7_5 #defines in include/hw/compat.h. +Looks like a mismerge. Drop the second one. The first seems to be +the one we want keep as it documents which upstream release the compat +settings are coming from. + +Signed-off-by: Gerd Hoffmann +Signed-off-by: Miroslav Rezanina +--- + include/hw/compat.h | 29 ----------------------------- + 1 file changed, 29 deletions(-) + +diff --git a/include/hw/compat.h b/include/hw/compat.h +index d711b5c5..666eed9 100644 +--- a/include/hw/compat.h ++++ b/include/hw/compat.h +@@ -478,33 +478,4 @@ + .value = "false",\ + }, + +-/* like HW_COMPAT_2_10 and HW_COMPAT_2_11 +- */ +-#define HW_COMPAT_RHEL7_5 \ +- { /* HW_COMPAT_RHEL7_5 */ \ +- .driver = "hpet",\ +- .property = "hpet-offset-saved",\ +- .value = "false",\ +- },{ /* HW_COMPAT_RHEL7_5 */ \ +- .driver = "virtio-blk-pci",\ +- .property = "vectors",\ +- .value = "2",\ +- },{ /* HW_COMPAT_RHEL7_5 */ \ +- .driver = "vhost-user-blk-pci",\ +- .property = "vectors",\ +- .value = "2",\ +- },{ /* HW_COMPAT_RHEL7_5 */ \ +- .driver = "e1000",\ +- .property = "migrate_tso_props",\ +- .value = "off",\ +- },{ /* HW_COMPAT_RHEL7_5 */ \ +- .driver = "virtio-mouse-device",\ +- .property = "wheel-axis",\ +- .value = "false",\ +- },{ /* HW_COMPAT_RHEL7_5 */ \ +- .driver = "virtio-tablet-device",\ +- .property = "wheel-axis",\ +- .value = "false",\ +- }, +- + #endif /* HW_COMPAT_H */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-s390-ccw-Fix-alignment-for-CCW1.patch b/SOURCES/kvm-s390-ccw-Fix-alignment-for-CCW1.patch deleted file mode 100644 index d3bbccf..0000000 --- a/SOURCES/kvm-s390-ccw-Fix-alignment-for-CCW1.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 5ddb3b822086c04493be468cc27e356cf174307d Mon Sep 17 00:00:00 2001 -From: Thomas Huth -Date: Wed, 22 Nov 2017 10:43:30 +0100 -Subject: [PATCH 13/15] s390-ccw: Fix alignment for CCW1 - -RH-Author: Thomas Huth -Message-id: <1511347411-16226-3-git-send-email-thuth@redhat.com> -Patchwork-id: 77775 -O-Subject: [RHEL-7.5 qemu-kvm-ma PATCH 2/3] s390-ccw: Fix alignment for CCW1 -Bugzilla: 1514352 -RH-Acked-by: David Hildenbrand -RH-Acked-by: Cornelia Huck -RH-Acked-by: Miroslav Rezanina - -From: Farhan Ali - -The commit 198c0d1f9df8c4 s390x/css: check ccw address validity -exposes an alignment issue in ccw bios. - -According to PoP the CCW must be doubleword aligned. Let's fix -this in the bios. - -Cc: qemu-stable@nongnu.org -Signed-off-by: Farhan Ali -Reviewed-by: Halil Pasic -Reviewed-by: Eric Farman -Acked-by: Christian Borntraeger -Message-Id: <3ed8b810b6592daee6a775037ce21f850e40647d.1503667215.git.alifm@linux.vnet.ibm.com> -Signed-off-by: Cornelia Huck -(cherry picked from commit 3a1e4561ad63b303b092387ae006bd41468ece63) -Signed-off-by: Miroslav Rezanina ---- - pc-bios/s390-ccw/cio.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/pc-bios/s390-ccw/cio.h b/pc-bios/s390-ccw/cio.h -index f5b4549..55eaeee 100644 ---- a/pc-bios/s390-ccw/cio.h -+++ b/pc-bios/s390-ccw/cio.h -@@ -133,7 +133,7 @@ struct ccw1 { - __u8 flags; - __u16 count; - __u32 cda; --} __attribute__ ((packed)); -+} __attribute__ ((packed, aligned(8))); - - #define CCW_FLAG_DC 0x80 - #define CCW_FLAG_CC 0x40 --- -1.8.3.1 - diff --git a/SOURCES/kvm-s390-ccw-force-diag-308-subcode-to-unsigned-long.patch b/SOURCES/kvm-s390-ccw-force-diag-308-subcode-to-unsigned-long.patch new file mode 100644 index 0000000..f2eea48 --- /dev/null +++ b/SOURCES/kvm-s390-ccw-force-diag-308-subcode-to-unsigned-long.patch @@ -0,0 +1,53 @@ +From 098630a1298aa56f6dfffaeecbddf2d0f39c55a8 Mon Sep 17 00:00:00 2001 +From: Thomas Huth +Date: Mon, 7 May 2018 07:58:03 +0200 +Subject: [PATCH 07/13] s390-ccw: force diag 308 subcode to unsigned long + +RH-Author: Thomas Huth +Message-id: <1525679888-9234-2-git-send-email-thuth@redhat.com> +Patchwork-id: 80049 +O-Subject: [RHEL-7.6 qemu-kvm-ma PATCH 1/6] s390-ccw: force diag 308 subcode to unsigned long +Bugzilla: 1523857 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Cornelia Huck +RH-Acked-by: Laszlo Ersek + +From: Cornelia Huck + +We currently pass an integer as the subcode parameter. However, +the upper bits of the register containing the subcode need to +be 0, which is not guaranteed unless we explicitly specify the +subcode to be an unsigned long value. + +Fixes: d046c51dad3 ("pc-bios/s390-ccw: Get device address via diag 308/6") +Cc: qemu-stable@nongnu.org +Signed-off-by: Cornelia Huck +Acked-by: Christian Borntraeger +Tested-by: Thomas Huth +Signed-off-by: Thomas Huth +(cherry picked from commit 63d8b5ace31c1e1f3996fe4cd551d6d377594d5a) +Signed-off-by: Miroslav Rezanina +--- + pc-bios/s390-ccw/iplb.h | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/pc-bios/s390-ccw/iplb.h b/pc-bios/s390-ccw/iplb.h +index 5357a36..ded20c8 100644 +--- a/pc-bios/s390-ccw/iplb.h ++++ b/pc-bios/s390-ccw/iplb.h +@@ -101,10 +101,11 @@ static inline bool manage_iplb(IplParameterBlock *iplb, bool store) + { + register unsigned long addr asm("0") = (unsigned long) iplb; + register unsigned long rc asm("1") = 0; ++ unsigned long subcode = store ? 6 : 5; + + asm volatile ("diag %0,%2,0x308\n" + : "+d" (addr), "+d" (rc) +- : "d" (store ? 6 : 5) ++ : "d" (subcode) + : "memory", "cc"); + return rc == 0x01; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-s390x-add-RHEL-7.6-machine-type-for-ccw.patch b/SOURCES/kvm-s390x-add-RHEL-7.6-machine-type-for-ccw.patch new file mode 100644 index 0000000..b09f293 --- /dev/null +++ b/SOURCES/kvm-s390x-add-RHEL-7.6-machine-type-for-ccw.patch @@ -0,0 +1,139 @@ +From ea16161ecfee857c3d83841f806c5fa55837c483 Mon Sep 17 00:00:00 2001 +From: Cornelia Huck +Date: Thu, 17 May 2018 11:52:08 +0200 +Subject: [PATCH 2/8] s390x: add RHEL 7.6 machine type for ccw + +RH-Author: Cornelia Huck +Message-id: <20180517115208.20738-1-cohuck@redhat.com> +Patchwork-id: 80375 +O-Subject: [RHEL-7.6 qemu-kvm-ma PATCH v2] s390x: add RHEL 7.6 machine type for ccw +Bugzilla: 1562138 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1562138 +Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=16338248 +Branch: rhv7/master-2.12.0 +Upstream: n/a +Tested: Managedsave/restore between qemu-kvm-ma-2.10 and qemu-kvm-ma-2.12 + with 7.5.0 machine type; started guest with 7.6.0 machine type + +Follows the s390x-specific 2.10->2.12 compat handling (sclp masks, +qemu cpu model) and introduces generic compat defines for 7.5->7.6 +(even though not applicable on s390x). + +Signed-off-by: Cornelia Huck +Signed-off-by: Miroslav Rezanina +--- + hw/s390x/s390-virtio-ccw.c | 35 ++++++++++++++++++++++++++++++++--- + include/hw/compat.h | 28 ++++++++++++++++++++++++++++ + 2 files changed, 60 insertions(+), 3 deletions(-) + +diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c +index 3956ac3..64e2a3b 100644 +--- a/hw/s390x/s390-virtio-ccw.c ++++ b/hw/s390x/s390-virtio-ccw.c +@@ -671,6 +671,8 @@ bool css_migration_enabled(void) + } \ + type_init(ccw_machine_register_##suffix) + ++#if 0 /* Disabled for Red Hat Enterprise Linux */ ++ + #define CCW_COMPAT_2_11 \ + HW_COMPAT_2_11 \ + {\ +@@ -682,8 +684,6 @@ bool css_migration_enabled(void) + #define CCW_COMPAT_2_10 \ + HW_COMPAT_2_10 + +-#if 0 /* Disabled for Red Hat Enterprise Linux */ +- + #define CCW_COMPAT_2_9 \ + HW_COMPAT_2_9 \ + {\ +@@ -883,14 +883,43 @@ DEFINE_CCW_MACHINE(2_4, "2.4", false); + + #else + ++/* ++ * like CCW_COMPAT_2_11, but includes HW_COMPAT_RHEL7_5 (derived from ++ * HW_COMPAT_2_11 and HW_COMPAT_2_10) instead of HW_COMPAT_2_11 ++ */ ++#define CCW_COMPAT_RHEL7_5 \ ++ HW_COMPAT_RHEL7_5 \ ++ {\ ++ .driver = TYPE_SCLP_EVENT_FACILITY,\ ++ .property = "allow_all_mask_sizes",\ ++ .value = "off",\ ++ }, ++ ++static void ccw_machine_rhel760_instance_options(MachineState *machine) ++{ ++} ++ ++static void ccw_machine_rhel760_class_options(MachineClass *mc) ++{ ++} ++DEFINE_CCW_MACHINE(rhel760, "rhel7.6.0", true); ++ + static void ccw_machine_rhel750_instance_options(MachineState *machine) + { ++ static const S390FeatInit qemu_cpu_feat = { S390_FEAT_LIST_QEMU_V2_11 }; ++ ccw_machine_rhel760_instance_options(machine); ++ ++ /* before 2.12 we emulated the very first z900, and RHEL 7.5 is ++ based on 2.10 */ ++ s390_set_qemu_cpu_model(0x2064, 7, 1, qemu_cpu_feat); + } + + static void ccw_machine_rhel750_class_options(MachineClass *mc) + { ++ ccw_machine_rhel760_class_options(mc); ++ SET_MACHINE_COMPAT(mc, CCW_COMPAT_RHEL7_5); + } +-DEFINE_CCW_MACHINE(rhel750, "rhel7.5.0", true); ++DEFINE_CCW_MACHINE(rhel750, "rhel7.5.0", false); + + #endif + +diff --git a/include/hw/compat.h b/include/hw/compat.h +index 503b5c8..666eed9 100644 +--- a/include/hw/compat.h ++++ b/include/hw/compat.h +@@ -450,4 +450,32 @@ + .value = "off",\ + }, + ++/* The same as HW_COMPAT_2_11 + HW_COMPAT_2_10 */ ++#define HW_COMPAT_RHEL7_5 \ ++ { /* HW_COMPAT_RHEL7_5 from HW_COMPAT_2_11 */ \ ++ .driver = "hpet",\ ++ .property = "hpet-offset-saved",\ ++ .value = "false",\ ++ },{ /* HW_COMPAT_RHEL7_5 from HW_COMPAT_2_11 */ \ ++ .driver = "virtio-blk-pci",\ ++ .property = "vectors",\ ++ .value = "2",\ ++ },{ /* HW_COMPAT_RHEL7_5 from HW_COMPAT_2_11 */ \ ++ .driver = "vhost-user-blk-pci",\ ++ .property = "vectors",\ ++ .value = "2",\ ++ },{ /* HW_COMPAT_RHEL7_5 from HW_COMPAT_2_11 */ \ ++ .driver = "e1000",\ ++ .property = "migrate_tso_props",\ ++ .value = "off",\ ++ },{ /* HW_COMPAT_RHEL7_5 from HW_COMPAT_2_10 */ \ ++ .driver = "virtio-mouse-device",\ ++ .property = "wheel-axis",\ ++ .value = "false",\ ++ },{ /* HW_COMPAT_RHEL7_5 from HW_COMPAT_2_10 */ \ ++ .driver = "virtio-tablet-device",\ ++ .property = "wheel-axis",\ ++ .value = "false",\ ++ }, ++ + #endif /* HW_COMPAT_H */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-s390x-ais-for-2.10-stable-disable-ais-facility.patch b/SOURCES/kvm-s390x-ais-for-2.10-stable-disable-ais-facility.patch deleted file mode 100644 index 4b20d6c..0000000 --- a/SOURCES/kvm-s390x-ais-for-2.10-stable-disable-ais-facility.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 49a0dc9e670b7f67713a7f9115028a4a29fbd03b Mon Sep 17 00:00:00 2001 -From: Cornelia Huck -Date: Thu, 5 Oct 2017 12:04:05 +0200 -Subject: [PATCH 11/34] s390x/ais: for 2.10 stable: disable ais facility - -RH-Author: Cornelia Huck -Message-id: <20171005120406.16642-2-cohuck@redhat.com> -Patchwork-id: 76818 -O-Subject: [RHV7.5 qemu-kvm-ma PATCH 1/2] s390x/ais: for 2.10 stable: disable ais facility -Bugzilla: 1494548 -RH-Acked-by: Thomas Huth -RH-Acked-by: Jens Freimann -RH-Acked-by: Dr. David Alan Gilbert - -From: Christian Borntraeger - -The migration interface for ais was introduced with kernel 4.13 -but the capability itself had been active since 4.12. As migration -support is considered necessary lets disable ais in the 2.10 -stable version. A proper fix and re-enablement will be done -for qemu 2.11. - -Signed-off-by: Christian Borntraeger -Message-Id: <20170921140834.14233-2-borntraeger@de.ibm.com> -Signed-off-by: Cornelia Huck -(cherry picked from commit 3f2d07b3b01ea61126b382633ab4006320923048) -Signed-off-by: Miroslav Rezanina ---- - target/s390x/kvm.c | 9 +++++++-- - 1 file changed, 7 insertions(+), 2 deletions(-) - -diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c -index c4c5791..eb0dbb3 100644 ---- a/target/s390x/kvm.c -+++ b/target/s390x/kvm.c -@@ -308,8 +308,13 @@ int kvm_arch_init(MachineState *ms, KVMState *s) - } - } - -- /* Try to enable AIS facility */ -- kvm_vm_enable_cap(s, KVM_CAP_S390_AIS, 0); -+ /* -+ * The migration interface for ais was introduced with kernel 4.13 -+ * but the capability itself had been active since 4.12. As migration -+ * support is considered necessary let's disable ais in the 2.10 -+ * machine. -+ */ -+ /* kvm_vm_enable_cap(s, KVM_CAP_S390_AIS, 0); */ - - qemu_mutex_init(&qemu_sigp_mutex); - --- -1.8.3.1 - diff --git a/SOURCES/kvm-s390x-cpumodel-Disable-unsupported-CPU-models.patch b/SOURCES/kvm-s390x-cpumodel-Disable-unsupported-CPU-models.patch deleted file mode 100644 index 311921c..0000000 --- a/SOURCES/kvm-s390x-cpumodel-Disable-unsupported-CPU-models.patch +++ /dev/null @@ -1,70 +0,0 @@ -From d5959fcefcda5639e99793f21688ba071bc2886a Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Fri, 10 Nov 2017 14:49:04 +0100 -Subject: [PATCH 7/7] s390x/cpumodel: Disable unsupported CPU models - -RH-Author: David Hildenbrand -Message-id: <20171110144904.7026-3-david@redhat.com> -Patchwork-id: 77648 -O-Subject: [RHEL-7.5 qemu-kvm-ma PATCH v3 2/2] s390x/cpumodel: Disable unsupported CPU models -Bugzilla: 1504138 -RH-Acked-by: Thomas Huth -RH-Acked-by: Cornelia Huck -RH-Acked-by: Eduardo Habkost - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1504138 -Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=14527097 -Upstream-status: RHEL-only - -We will only be supporting CPU models >= HW generation 11 (including -z196, z12, z13, z14). - -As completely removing CPU models is tricky (mainly due to TCG), we -simply disallow to instantiate them with KVM. - -In addition, report via query-cpu-definitions, that these models are -not runnable under kvm. - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - target/s390x/cpu_models.c | 3 +++ - target/s390x/kvm.c | 8 ++++++++ - 2 files changed, 11 insertions(+) - -diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c -index e055852..d8f7bed 100644 ---- a/target/s390x/cpu_models.c -+++ b/target/s390x/cpu_models.c -@@ -360,6 +360,9 @@ static void check_unavailable_features(const S390CPUModel *max_model, - (max_model->def->gen == model->def->gen && - max_model->def->ec_ga < model->def->ec_ga)) { - list_add_feat("type", unavailable); -+ } else if (model->def->gen < 11 && kvm_enabled()) { -+ /* Older CPU models are not supported on Red Hat Enterprise Linux */ -+ list_add_feat("type", unavailable); - } - - /* detect missing features if any to properly report them */ -diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c -index eb0dbb3..3589e6e 100644 ---- a/target/s390x/kvm.c -+++ b/target/s390x/kvm.c -@@ -2712,6 +2712,14 @@ void kvm_s390_apply_cpu_model(const S390CPUModel *model, Error **errp) - error_setg(errp, "KVM doesn't support CPU models"); - return; - } -+ -+ /* Older CPU models are not supported on Red Hat Enterprise Linux */ -+ if (model->def->gen < 11) { -+ error_setg(errp, "KVM: Unsupported CPU model specified: %s", -+ MACHINE(qdev_get_machine())->cpu_model); -+ return; -+ } -+ - prop.cpuid = s390_cpuid_from_cpu_model(model); - prop.ibc = s390_ibc_from_cpu_model(model); - /* configure cpu features indicated via STFL(e) */ --- -1.8.3.1 - diff --git a/SOURCES/kvm-s390x-cpumodel-default-enable-bpb-and-ppa15-for-z196.patch b/SOURCES/kvm-s390x-cpumodel-default-enable-bpb-and-ppa15-for-z196.patch new file mode 100644 index 0000000..2ac5d99 --- /dev/null +++ b/SOURCES/kvm-s390x-cpumodel-default-enable-bpb-and-ppa15-for-z196.patch @@ -0,0 +1,62 @@ +From 11637f33d743a928b6e05f4475f3f840715f33c6 Mon Sep 17 00:00:00 2001 +From: Cornelia Huck +Date: Tue, 3 Jul 2018 10:55:10 +0200 +Subject: [PATCH 56/57] s390x/cpumodel: default enable bpb and ppa15 for z196 + and later + +RH-Author: Cornelia Huck +Message-id: <20180703105510.30555-1-cohuck@redhat.com> +Patchwork-id: 81191 +O-Subject: [RHEL-7.6 qemu-kvm-ma PATCH] s390x/cpumodel: default enable bpb and ppa15 for z196 and later +Bugzilla: 1595715 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Eduardo Habkost +RH-Acked-by: David Hildenbrand + +Most systems and host kernels provide the necessary building blocks for +bpb and ppa15. We can reverse the logic and default enable those +features, while still allowing to disable it via cpu model. + +So let us add bpb and ppa15 to z196 and later default CPU model for the +qemu rhel7.6.0 machine. (like -cpu z13). Older machine types (i.e. +s390-ccw-virtio-rhel7.5.0) will retain the old value and not provide those +bits in the default model. + +Signed-off-by: Cornelia Huck +Signed-off-by: Miroslav Rezanina +--- + hw/s390x/s390-virtio-ccw.c | 4 ++++ + target/s390x/gen-features.c | 2 ++ + 2 files changed, 6 insertions(+) + +diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c +index 64e2a3b..bf039a1 100644 +--- a/hw/s390x/s390-virtio-ccw.c ++++ b/hw/s390x/s390-virtio-ccw.c +@@ -912,6 +912,10 @@ static void ccw_machine_rhel750_instance_options(MachineState *machine) + /* before 2.12 we emulated the very first z900, and RHEL 7.5 is + based on 2.10 */ + s390_set_qemu_cpu_model(0x2064, 7, 1, qemu_cpu_feat); ++ ++ /* bpb and ppa15 were only in the full model in RHEL 7.5 */ ++ s390_cpudef_featoff_greater(11, 1, S390_FEAT_PPA15); ++ s390_cpudef_featoff_greater(11, 1, S390_FEAT_BPB); + } + + static void ccw_machine_rhel750_class_options(MachineClass *mc) +diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c +index 0cdbc15..6626b6f 100644 +--- a/target/s390x/gen-features.c ++++ b/target/s390x/gen-features.c +@@ -512,6 +512,8 @@ static uint16_t default_GEN11_GA1[] = { + S390_FEAT_IPTE_RANGE, + S390_FEAT_ACCESS_EXCEPTION_FS_INDICATION, + S390_FEAT_GROUP_MSA_EXT_4, ++ S390_FEAT_PPA15, ++ S390_FEAT_BPB, + }; + + #define default_GEN11_GA2 EmptyFeat +-- +1.8.3.1 + diff --git a/SOURCES/kvm-s390x-cpumodel-remove-ais-from-z14-default-model-als.patch b/SOURCES/kvm-s390x-cpumodel-remove-ais-from-z14-default-model-als.patch deleted file mode 100644 index 418435b..0000000 --- a/SOURCES/kvm-s390x-cpumodel-remove-ais-from-z14-default-model-als.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 7aaf777448ba232fc0dc136e1ed775f86e0e8036 Mon Sep 17 00:00:00 2001 -From: Cornelia Huck -Date: Thu, 5 Oct 2017 12:04:06 +0200 -Subject: [PATCH 12/34] s390x/cpumodel: remove ais from z14 default model-> - also for 2.10.1 - -RH-Author: Cornelia Huck -Message-id: <20171005120406.16642-3-cohuck@redhat.com> -Patchwork-id: 76819 -O-Subject: [RHV7.5 qemu-kvm-ma PATCH 2/2] s390x/cpumodel: remove ais from z14 default model-> also for 2.10.1 -Bugzilla: 1494548 -RH-Acked-by: Thomas Huth -RH-Acked-by: Jens Freimann -RH-Acked-by: Dr. David Alan Gilbert - -From: Christian Borntraeger - -We disabled ais for 2.10, so let's also remove it from the z14 -default model. - -Fixes: 3f2d07b3b01e ("s390x/ais: for 2.10 stable: disable ais facility") -CC: qemu-stable@nongnu.org -Signed-off-by: Christian Borntraeger -Message-Id: <20170927072030.35737-2-borntraeger@de.ibm.com> -Signed-off-by: Cornelia Huck -(cherry picked from commit 9dacc908462693719d84ec594e839434959cf6f1) -Signed-off-by: Miroslav Rezanina ---- - target/s390x/gen-features.c | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c -index c8dc104..68e6c31 100644 ---- a/target/s390x/gen-features.c -+++ b/target/s390x/gen-features.c -@@ -527,7 +527,6 @@ static uint16_t default_GEN13_GA1[] = { - #define default_GEN13_GA2 EmptyFeat - - static uint16_t default_GEN14_GA1[] = { -- S390_FEAT_ADAPTER_INT_SUPPRESSION, - S390_FEAT_INSTRUCTION_EXEC_PROT, - S390_FEAT_GUARDED_STORAGE, - S390_FEAT_VECTOR_PACKED_DECIMAL, --- -1.8.3.1 - diff --git a/SOURCES/kvm-s390x-cpumodels-add-z14-Model-ZR1.patch b/SOURCES/kvm-s390x-cpumodels-add-z14-Model-ZR1.patch new file mode 100644 index 0000000..a9dd5f9 --- /dev/null +++ b/SOURCES/kvm-s390x-cpumodels-add-z14-Model-ZR1.patch @@ -0,0 +1,44 @@ +From f64b0a4ca1cb685491df47d525909c9a47ecb47e Mon Sep 17 00:00:00 2001 +From: Thomas Huth +Date: Wed, 20 Jun 2018 09:50:28 +0200 +Subject: [PATCH 50/54] s390x/cpumodels: add z14 Model ZR1 + +RH-Author: Thomas Huth +Message-id: <1529488228-5109-2-git-send-email-thuth@redhat.com> +Patchwork-id: 80892 +O-Subject: [RHEL-7.6 qemu-kvm-ma PATCH 1/1] s390x/cpumodels: add z14 Model ZR1 +Bugzilla: 1592327 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Cornelia Huck +RH-Acked-by: Eduardo Habkost + +From: Christian Borntraeger + +Introduce the new z14 Model ZR1 cpu model. Mostly identical to z14, only +the cpu type differs (3906 vs. 3907) + +Signed-off-by: Christian Borntraeger +Message-Id: <20180613081819.147178-1-borntraeger@de.ibm.com> +Reviewed-by: David Hildenbrand +Signed-off-by: Cornelia Huck +(cherry picked from commit 23ad956bff98d949057156ea3f68a9763c2dda0e) +Signed-off-by: Miroslav Rezanina +--- + target/s390x/cpu_models.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c +index 70b23bf..0b5d271 100644 +--- a/target/s390x/cpu_models.c ++++ b/target/s390x/cpu_models.c +@@ -79,6 +79,7 @@ static S390CPUDef s390_cpu_defs[] = { + CPUDEF_INIT(0x2964, 13, 2, 47, 0x08000000U, "z13.2", "IBM z13 GA2"), + CPUDEF_INIT(0x2965, 13, 2, 47, 0x08000000U, "z13s", "IBM z13s GA1"), + CPUDEF_INIT(0x3906, 14, 1, 47, 0x08000000U, "z14", "IBM z14 GA1"), ++ CPUDEF_INIT(0x3907, 14, 1, 47, 0x08000000U, "z14ZR1", "IBM z14 Model ZR1 GA1"), + }; + + #define QEMU_MAX_CPU_TYPE 0x2827 +-- +1.8.3.1 + diff --git a/SOURCES/kvm-s390x-css-fix-css-migration-compat-handling.patch b/SOURCES/kvm-s390x-css-fix-css-migration-compat-handling.patch deleted file mode 100644 index eb200a9..0000000 --- a/SOURCES/kvm-s390x-css-fix-css-migration-compat-handling.patch +++ /dev/null @@ -1,73 +0,0 @@ -From c08eeabcb588c0cd8f9952e273fa6cdaea71d25c Mon Sep 17 00:00:00 2001 -From: Thomas Huth -Date: Mon, 9 Oct 2017 15:50:33 +0200 -Subject: [PATCH 30/34] s390x/css: fix css migration compat handling - -RH-Author: Thomas Huth -Message-id: <1507564234-19627-2-git-send-email-thuth@redhat.com> -Patchwork-id: 77038 -O-Subject: [RHEL-7.5 qemu-kvm-ma PATCH 1/2] s390x/css: fix css migration compat handling -Bugzilla: 1473292 -RH-Acked-by: Cornelia Huck -RH-Acked-by: Jens Freimann -RH-Acked-by: Laurent Vivier - -From: Halil Pasic - -Commit e996583eb3 ("s390x/css: activate ChannelSubSys migration", -2017-07-11) was supposed to enable css migration for virtio-ccw -machines starting 2.10, but it ended up effectively enabling it -only for 2.10 as the registration of the appropriate VMStateDescription -happens in ccw_machine_2_10_instance_options which does not get -called for machines more recent than 2_10. - -Let us move the corresponding chunk of code (which conditionally enables -the migration based on the value of the corresponding class property) to -ccw_init, which is called for each virtio-ccw machine instance. - -Signed-off-by: Halil Pasic -Reported-by: Thomas Huth -Message-Id: <20171004110109.16525-1-pasic@linux.vnet.ibm.com> -Tested-by: Christian Borntraeger -Acked-by: Christian Borntraeger -Signed-off-by: Cornelia Huck -(cherry picked from commit 489c909f097a387eb6913c89cf1851750397110c) -Signed-off-by: Miroslav Rezanina - -Conflicts: - hw/s390x/s390-virtio-ccw.c - (contextual conflict since we do not have commit with id - 70d8d9a0c9bc599d8ae99dd65ff8535adb2acdfc in downstream yet) - -Signed-off-by: Thomas Huth ---- - hw/s390x/s390-virtio-ccw.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c -index 1c7af39..1aec58c 100644 ---- a/hw/s390x/s390-virtio-ccw.c -+++ b/hw/s390x/s390-virtio-ccw.c -@@ -156,6 +156,9 @@ static void ccw_init(MachineState *machine) - ret = css_create_css_image(VIRTUAL_CSSID, true); - } - assert(ret == 0); -+ if (css_migration_enabled()) { -+ css_register_vmstate(); -+ } - - /* Create VirtIO network adapters */ - s390_create_virtio_net(BUS(css_bus), "virtio-net-ccw"); -@@ -508,9 +511,6 @@ bool css_migration_enabled(void) - - static void ccw_machine_2_10_instance_options(MachineState *machine) - { -- if (css_migration_enabled()) { -- css_register_vmstate(); -- } - } - - static void ccw_machine_2_10_class_options(MachineClass *mc) --- -1.8.3.1 - diff --git a/SOURCES/kvm-s390x-fix-storage-attributes-migration-for-non-small.patch b/SOURCES/kvm-s390x-fix-storage-attributes-migration-for-non-small.patch deleted file mode 100644 index 6e5cfd6..0000000 --- a/SOURCES/kvm-s390x-fix-storage-attributes-migration-for-non-small.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 56c0724bf309a7d6d89f2aba0d38147b1e77954f Mon Sep 17 00:00:00 2001 -From: Cornelia Huck -Date: Fri, 29 Jun 2018 12:57:01 +0200 -Subject: [PATCH 3/3] s390x: fix storage attributes migration for non-small - guests - -RH-Author: Cornelia Huck -Message-id: <20180629125701.12755-1-cohuck@redhat.com> -Patchwork-id: 81166 -O-Subject: [RHEL-7.5.z qemu-kvm-ma PATCH] s390x: fix storage attributes migration for non-small guests -Bugzilla: 1596553 -RH-Acked-by: David Hildenbrand -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Miroslav Rezanina - -From: Claudio Imbrenda - -Fix storage attribute migration so that it does not fail for guests -with more than a few GB of RAM. -With such guests, the index in the buffer would go out of bounds, -usually by large amounts, thus receiving -EFAULT from the kernel. -Migration itself would be successful, but storage attributes would then -not be migrated completely. - -This patch fixes the out of bounds access, and thus migration of all -storage attributes when the guest have large amounts of memory. - -Cc: qemu-stable@nongnu.org -Signed-off-by: Claudio Imbrenda -Fixes: 903fd80b03243476 ("s390x/migration: Storage attributes device") -Message-Id: <1516297904-18188-1-git-send-email-imbrenda@linux.vnet.ibm.com> -Reviewed-by: Christian Borntraeger -Signed-off-by: Cornelia Huck -(cherry picked from commit 46fa893355e0bd88f3c59b886f0d75cbd5f0bbbe) -Signed-off-by: Cornelia Huck -Signed-off-by: Miroslav Rezanina ---- - hw/s390x/s390-stattrib-kvm.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/hw/s390x/s390-stattrib-kvm.c b/hw/s390x/s390-stattrib-kvm.c -index bc0274d..1212c47 100644 ---- a/hw/s390x/s390-stattrib-kvm.c -+++ b/hw/s390x/s390-stattrib-kvm.c -@@ -115,7 +115,7 @@ static void kvm_s390_stattrib_synchronize(S390StAttribState *sa) - for (cx = 0; cx + len <= max; cx += len) { - clog.start_gfn = cx; - clog.count = len; -- clog.values = (uint64_t)(sas->incoming_buffer + cx * len); -+ clog.values = (uint64_t)(sas->incoming_buffer + cx); - r = kvm_vm_ioctl(kvm_state, KVM_S390_SET_CMMA_BITS, &clog); - if (r) { - error_report("KVM_S390_SET_CMMA_BITS failed: %s", strerror(-r)); -@@ -125,7 +125,7 @@ static void kvm_s390_stattrib_synchronize(S390StAttribState *sa) - if (cx < max) { - clog.start_gfn = cx; - clog.count = max - cx; -- clog.values = (uint64_t)(sas->incoming_buffer + cx * len); -+ clog.values = (uint64_t)(sas->incoming_buffer + cx); - r = kvm_vm_ioctl(kvm_state, KVM_S390_SET_CMMA_BITS, &clog); - if (r) { - error_report("KVM_S390_SET_CMMA_BITS failed: %s", strerror(-r)); --- -1.8.3.1 - diff --git a/SOURCES/kvm-s390x-ipl-The-s390-ipl-device-is-not-hot-pluggable.patch b/SOURCES/kvm-s390x-ipl-The-s390-ipl-device-is-not-hot-pluggable.patch deleted file mode 100644 index 697bf47..0000000 --- a/SOURCES/kvm-s390x-ipl-The-s390-ipl-device-is-not-hot-pluggable.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 456a0426e0db531e9545042fb20ecdb1d470f8ea Mon Sep 17 00:00:00 2001 -From: Thomas Huth -Date: Mon, 9 Oct 2017 12:32:44 +0200 -Subject: [PATCH 25/34] s390x/ipl: The s390-ipl device is not hot-pluggable - -RH-Author: Thomas Huth -Message-id: <1507552368-9245-9-git-send-email-thuth@redhat.com> -Patchwork-id: 77025 -O-Subject: [RHEL-7.5 qemu-kvm-ma PATCH 08/12] s390x/ipl: The s390-ipl device is not hot-pluggable -Bugzilla: 1492033 -RH-Acked-by: Cornelia Huck -RH-Acked-by: David Gibson -RH-Acked-by: Miroslav Rezanina - -The s390-ipl device can not be created by the user, since it is meant only -to be instantiated once internally to load the ROMs and kernel. If the user -tries to do a "device_add s390-ipl" via the monitor later, QEMU aborts with -a "ROM images must be loaded at startup" error message. - -Signed-off-by: Thomas Huth -Message-Id: <1502861458-30270-1-git-send-email-thuth@redhat.com> -Reviewed-by: David Hildenbrand -Signed-off-by: Cornelia Huck -(cherry picked from commit 0d4fa4996fc5ee56ea7d072e272b8e69948460a5) -Signed-off-by: Miroslav Rezanina ---- - hw/s390x/ipl.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c -index cc36003..0d06fc1 100644 ---- a/hw/s390x/ipl.c -+++ b/hw/s390x/ipl.c -@@ -442,6 +442,8 @@ static void s390_ipl_class_init(ObjectClass *klass, void *data) - dc->reset = s390_ipl_reset; - dc->vmsd = &vmstate_ipl; - set_bit(DEVICE_CATEGORY_MISC, dc->categories); -+ /* Reason: Loads the ROMs and thus can only be used one time - internally */ -+ dc->user_creatable = false; - } - - static const TypeInfo s390_ipl_info = { --- -1.8.3.1 - diff --git a/SOURCES/kvm-s390x-kvm-Handle-bpb-feature.patch b/SOURCES/kvm-s390x-kvm-Handle-bpb-feature.patch deleted file mode 100644 index 0f2bd5a..0000000 --- a/SOURCES/kvm-s390x-kvm-Handle-bpb-feature.patch +++ /dev/null @@ -1,178 +0,0 @@ -From 89628ec85c86fee920a518330759891dd0c01921 Mon Sep 17 00:00:00 2001 -From: Thomas Huth -Date: Tue, 23 Jan 2018 19:12:45 +0100 -Subject: [PATCH 3/8] s390x/kvm: Handle bpb feature - -RH-Author: Thomas Huth -Message-id: <1516734766-12075-3-git-send-email-thuth@redhat.com> -Patchwork-id: 78701 -O-Subject: [RHEL-7.5 qemu-kvm-ma PATCH 2/3] s390x/kvm: Handle bpb feature -Bugzilla: 1535606 -RH-Acked-by: David Hildenbrand -RH-Acked-by: Cornelia Huck -RH-Acked-by: Jens Freimann - -From: Christian Borntraeger - -We need to handle the bpb control on reset and migration. Normally -stfle.82 is transparent (and the normal guest part works without -hypervisor activity). To prevent any issues we require full -host kernel support for this feature. - -Cc: qemu-stable@nongnu.org -Signed-off-by: Christian Borntraeger -Message-Id: <20180118085628.40798-3-borntraeger@de.ibm.com> -Reviewed-by: Thomas Huth -Reviewed-by: David Hildenbrand -[CH: 'Branch Prediction Blocking' -> 'Branch prediction blocking'] -Signed-off-by: Cornelia Huck -(cherry picked from commit b073c87517d4d348c7bac0f0b35e8e83e6354d82) - -Signed-off-by: Miroslav Rezanina ---- - target/s390x/cpu.c | 1 + - target/s390x/cpu.h | 1 + - target/s390x/cpu_features.c | 1 + - target/s390x/cpu_features_def.h | 1 + - target/s390x/gen-features.c | 1 + - target/s390x/kvm.c | 14 ++++++++++++++ - target/s390x/machine.c | 17 +++++++++++++++++ - 7 files changed, 36 insertions(+) - -diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c -index 489bc25..8bd463c 100644 ---- a/target/s390x/cpu.c -+++ b/target/s390x/cpu.c -@@ -78,6 +78,7 @@ static void s390_cpu_reset(CPUState *s) - CPUS390XState *env = &cpu->env; - - env->pfault_token = -1UL; -+ env->bpbc = false; - scc->parent_reset(s); - cpu->env.sigp_order = 0; - s390_cpu_set_state(CPU_STATE_STOPPED, cpu); -diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h -index 29fdd5d..ce1f933 100644 ---- a/target/s390x/cpu.h -+++ b/target/s390x/cpu.h -@@ -96,6 +96,7 @@ typedef struct CPUS390XState { - - uint32_t fpc; /* floating-point control register */ - uint32_t cc_op; -+ bool bpbc; /* branch prediction blocking */ - - float_status fpu_status; /* passed to softfloat lib */ - -diff --git a/target/s390x/cpu_features.c b/target/s390x/cpu_features.c -index 1d3a036..d39efb0 100644 ---- a/target/s390x/cpu_features.c -+++ b/target/s390x/cpu_features.c -@@ -89,6 +89,7 @@ static const S390FeatDef s390_features[] = { - FEAT_INIT("msa4-base", S390_FEAT_TYPE_STFL, 77, "Message-security-assist-extension-4 facility (excluding subfunctions)"), - FEAT_INIT("edat2", S390_FEAT_TYPE_STFL, 78, "Enhanced-DAT facility 2"), - FEAT_INIT("dfppc", S390_FEAT_TYPE_STFL, 80, "Decimal-floating-point packed-conversion facility"), -+ FEAT_INIT("bpb", S390_FEAT_TYPE_STFL, 82, "Branch prediction blocking"), - FEAT_INIT("vx", S390_FEAT_TYPE_STFL, 129, "Vector facility"), - FEAT_INIT("iep", S390_FEAT_TYPE_STFL, 130, "Instruction-execution-protection facility"), - FEAT_INIT("sea_esop2", S390_FEAT_TYPE_STFL, 131, "Side-effect-access facility and Enhanced-suppression-on-protection facility 2"), -diff --git a/target/s390x/cpu_features_def.h b/target/s390x/cpu_features_def.h -index 4b6d4e9..4487cfd 100644 ---- a/target/s390x/cpu_features_def.h -+++ b/target/s390x/cpu_features_def.h -@@ -80,6 +80,7 @@ typedef enum { - S390_FEAT_MSA_EXT_4, - S390_FEAT_EDAT_2, - S390_FEAT_DFP_PACKED_CONVERSION, -+ S390_FEAT_BPB, - S390_FEAT_VECTOR, - S390_FEAT_INSTRUCTION_EXEC_PROT, - S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2, -diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c -index 68e6c31..13a6291 100644 ---- a/target/s390x/gen-features.c -+++ b/target/s390x/gen-features.c -@@ -352,6 +352,7 @@ static uint16_t base_GEN14_GA1[] = { - * support these features yet. - */ - static uint16_t full_GEN7_GA1[] = { -+ S390_FEAT_BPB, - S390_FEAT_SIE_F2, - S390_FEAT_SIE_SKEY, - S390_FEAT_SIE_GPERE, -diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c -index 3589e6e..871f441 100644 ---- a/target/s390x/kvm.c -+++ b/target/s390x/kvm.c -@@ -488,6 +488,11 @@ int kvm_arch_put_registers(CPUState *cs, int level) - cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_GSCB; - } - -+ if (can_sync_regs(cs, KVM_SYNC_BPBC)) { -+ cs->kvm_run->s.regs.bpbc = env->bpbc; -+ cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_BPBC; -+ } -+ - /* Finally the prefix */ - if (can_sync_regs(cs, KVM_SYNC_PREFIX)) { - cs->kvm_run->s.regs.prefix = env->psa; -@@ -598,6 +603,10 @@ int kvm_arch_get_registers(CPUState *cs) - memcpy(env->gscb, cs->kvm_run->s.regs.gscb, 32); - } - -+ if (can_sync_regs(cs, KVM_SYNC_BPBC)) { -+ env->bpbc = cs->kvm_run->s.regs.bpbc; -+ } -+ - /* pfault parameters */ - if (can_sync_regs(cs, KVM_SYNC_PFAULT)) { - env->pfault_token = cs->kvm_run->s.regs.pft; -@@ -2666,6 +2675,11 @@ void kvm_s390_get_host_cpu_model(S390CPUModel *model, Error **errp) - clear_bit(S390_FEAT_CMM_NT, model->features); - } - -+ /* bpb needs kernel support for migration, VSIE and reset */ -+ if (!kvm_check_extension(kvm_state, KVM_CAP_S390_BPB)) { -+ clear_bit(S390_FEAT_BPB, model->features); -+ } -+ - /* We emulate a zPCI bus and AEN, therefore we don't need HW support */ - set_bit(S390_FEAT_ZPCI, model->features); - set_bit(S390_FEAT_ADAPTER_EVENT_NOTIFICATION, model->features); -diff --git a/target/s390x/machine.c b/target/s390x/machine.c -index 2dcadfd..f24088b 100644 ---- a/target/s390x/machine.c -+++ b/target/s390x/machine.c -@@ -190,6 +190,22 @@ const VMStateDescription vmstate_gscb = { - } - }; - -+static bool bpbc_needed(void *opaque) -+{ -+ return s390_has_feat(S390_FEAT_BPB); -+} -+ -+const VMStateDescription vmstate_bpbc = { -+ .name = "cpu/bpbc", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .needed = bpbc_needed, -+ .fields = (VMStateField[]) { -+ VMSTATE_BOOL(env.bpbc, S390CPU), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ - const VMStateDescription vmstate_s390_cpu = { - .name = "cpu", - .post_load = cpu_post_load, -@@ -224,6 +240,7 @@ const VMStateDescription vmstate_s390_cpu = { - &vmstate_riccb, - &vmstate_exval, - &vmstate_gscb, -+ &vmstate_bpbc, - NULL - }, - }; --- -1.8.3.1 - diff --git a/SOURCES/kvm-s390x-kvm-add-etoken-facility.patch b/SOURCES/kvm-s390x-kvm-add-etoken-facility.patch new file mode 100644 index 0000000..0cb1985 --- /dev/null +++ b/SOURCES/kvm-s390x-kvm-add-etoken-facility.patch @@ -0,0 +1,196 @@ +From d5c27d4667cc1fb8065c27dc7e7d0e5d29f34e29 Mon Sep 17 00:00:00 2001 +From: Thomas Huth +Date: Tue, 28 Aug 2018 17:03:12 +0200 +Subject: [PATCH 02/29] s390x/kvm: add etoken facility + +RH-Author: Thomas Huth +Message-id: <1535475792-21136-3-git-send-email-thuth@redhat.com> +Patchwork-id: 81948 +O-Subject: [RHEL-7.6 qemu-kvm-ma PATCH 2/2] s390x/kvm: add etoken facility +Bugzilla: 1622962 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Cornelia Huck +RH-Acked-by: Jens Freimann + +From: Christian Borntraeger + +Provide the etoken facility. We need to handle cpu model, migration and +clear reset. + +Signed-off-by: Christian Borntraeger +Acked-by: Janosch Frank +Message-Id: <20180731090448.36662-3-borntraeger@de.ibm.com> +Reviewed-by: David Hildenbrand +Signed-off-by: Cornelia Huck +(cherry picked from commit 27e84d4ebd25b981ab27cb590fe06d1b0fcd06d2) +Signed-off-by: Miroslav Rezanina +--- + target/s390x/cpu.h | 3 +++ + target/s390x/cpu_features.c | 3 ++- + target/s390x/cpu_features_def.h | 3 ++- + target/s390x/gen-features.c | 3 ++- + target/s390x/kvm.c | 11 +++++++++++ + target/s390x/machine.c | 20 +++++++++++++++++++- + 6 files changed, 39 insertions(+), 4 deletions(-) + +diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h +index 3ee40f0..86d08fa 100644 +--- a/target/s390x/cpu.h ++++ b/target/s390x/cpu.h +@@ -2,6 +2,7 @@ + * S/390 virtual CPU header + * + * Copyright (c) 2009 Ulrich Hecht ++ * Copyright IBM Corp. 2012, 2018 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public +@@ -68,6 +69,8 @@ struct CPUS390XState { + uint32_t aregs[16]; /* access registers */ + uint8_t riccb[64]; /* runtime instrumentation control */ + uint64_t gscb[4]; /* guarded storage control */ ++ uint64_t etoken; /* etoken */ ++ uint64_t etoken_extension; /* etoken extension */ + + /* Fields up to this point are not cleared by initial CPU reset */ + struct {} start_initial_reset_fields; +diff --git a/target/s390x/cpu_features.c b/target/s390x/cpu_features.c +index 3b9e274..e05e6aa 100644 +--- a/target/s390x/cpu_features.c ++++ b/target/s390x/cpu_features.c +@@ -1,7 +1,7 @@ + /* + * CPU features/facilities for s390x + * +- * Copyright 2016 IBM Corp. ++ * Copyright IBM Corp. 2016, 2018 + * + * Author(s): David Hildenbrand + * +@@ -106,6 +106,7 @@ static const S390FeatDef s390_features[] = { + FEAT_INIT("irbm", S390_FEAT_TYPE_STFL, 145, "Insert-reference-bits-multiple facility"), + FEAT_INIT("msa8-base", S390_FEAT_TYPE_STFL, 146, "Message-security-assist-extension-8 facility (excluding subfunctions)"), + FEAT_INIT("cmmnt", S390_FEAT_TYPE_STFL, 147, "CMM: ESSA-enhancement (no translate) facility"), ++ FEAT_INIT("etoken", S390_FEAT_TYPE_STFL, 156, "Etoken facility"), + + /* SCLP SCCB Byte 80 - 98 (bit numbers relative to byte-80) */ + FEAT_INIT("gsls", S390_FEAT_TYPE_SCLP_CONF_CHAR, 40, "SIE: Guest-storage-limit-suppression facility"), +diff --git a/target/s390x/cpu_features_def.h b/target/s390x/cpu_features_def.h +index 7c5915c..ac2c947 100644 +--- a/target/s390x/cpu_features_def.h ++++ b/target/s390x/cpu_features_def.h +@@ -1,7 +1,7 @@ + /* + * CPU features/facilities for s390 + * +- * Copyright 2016 IBM Corp. ++ * Copyright IBM Corp. 2016, 2018 + * + * Author(s): Michael Mueller + * David Hildenbrand +@@ -93,6 +93,7 @@ typedef enum { + S390_FEAT_INSERT_REFERENCE_BITS_MULT, + S390_FEAT_MSA_EXT_8, + S390_FEAT_CMM_NT, ++ S390_FEAT_ETOKEN, + + /* Sclp Conf Char */ + S390_FEAT_SIE_GSLS, +diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c +index 6626b6f..5af042c 100644 +--- a/target/s390x/gen-features.c ++++ b/target/s390x/gen-features.c +@@ -1,7 +1,7 @@ + /* + * S390 feature list generator + * +- * Copyright 2016 IBM Corp. ++ * Copyright IBM Corp. 2016, 2018 + * + * Author(s): Michael Mueller + * David Hildenbrand +@@ -471,6 +471,7 @@ static uint16_t full_GEN14_GA1[] = { + S390_FEAT_GROUP_MSA_EXT_7, + S390_FEAT_GROUP_MSA_EXT_8, + S390_FEAT_CMM_NT, ++ S390_FEAT_ETOKEN, + S390_FEAT_HPMA2, + S390_FEAT_SIE_KSS, + S390_FEAT_GROUP_MULTIPLE_EPOCH_PTFF, +diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c +index fbccceb..ca8c32e 100644 +--- a/target/s390x/kvm.c ++++ b/target/s390x/kvm.c +@@ -494,6 +494,12 @@ int kvm_arch_put_registers(CPUState *cs, int level) + cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_BPBC; + } + ++ if (can_sync_regs(cs, KVM_SYNC_ETOKEN)) { ++ cs->kvm_run->s.regs.etoken = env->etoken; ++ cs->kvm_run->s.regs.etoken_extension = env->etoken_extension; ++ cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_ETOKEN; ++ } ++ + /* Finally the prefix */ + if (can_sync_regs(cs, KVM_SYNC_PREFIX)) { + cs->kvm_run->s.regs.prefix = env->psa; +@@ -608,6 +614,11 @@ int kvm_arch_get_registers(CPUState *cs) + env->bpbc = cs->kvm_run->s.regs.bpbc; + } + ++ if (can_sync_regs(cs, KVM_SYNC_ETOKEN)) { ++ env->etoken = cs->kvm_run->s.regs.etoken; ++ env->etoken_extension = cs->kvm_run->s.regs.etoken_extension; ++ } ++ + /* pfault parameters */ + if (can_sync_regs(cs, KVM_SYNC_PFAULT)) { + env->pfault_token = cs->kvm_run->s.regs.pft; +diff --git a/target/s390x/machine.c b/target/s390x/machine.c +index 84b4928..8421deb 100644 +--- a/target/s390x/machine.c ++++ b/target/s390x/machine.c +@@ -1,7 +1,7 @@ + /* + * S390x machine definitions and functions + * +- * Copyright IBM Corp. 2014 ++ * Copyright IBM Corp. 2014, 2018 + * + * Authors: + * Thomas Huth +@@ -210,6 +210,23 @@ const VMStateDescription vmstate_bpbc = { + } + }; + ++static bool etoken_needed(void *opaque) ++{ ++ return s390_has_feat(S390_FEAT_ETOKEN); ++} ++ ++const VMStateDescription vmstate_etoken = { ++ .name = "cpu/etoken", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .needed = etoken_needed, ++ .fields = (VMStateField[]) { ++ VMSTATE_UINT64(env.etoken, S390CPU), ++ VMSTATE_UINT64(env.etoken_extension, S390CPU), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ + const VMStateDescription vmstate_s390_cpu = { + .name = "cpu", + .post_load = cpu_post_load, +@@ -245,6 +262,7 @@ const VMStateDescription vmstate_s390_cpu = { + &vmstate_exval, + &vmstate_gscb, + &vmstate_bpbc, ++ &vmstate_etoken, + NULL + }, + }; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-s390x-kvm-provide-stfle.81.patch b/SOURCES/kvm-s390x-kvm-provide-stfle.81.patch deleted file mode 100644 index 96ccef4..0000000 --- a/SOURCES/kvm-s390x-kvm-provide-stfle.81.patch +++ /dev/null @@ -1,74 +0,0 @@ -From 775d414bd144e3562456e2caa5b246f5ef41a5fd Mon Sep 17 00:00:00 2001 -From: Thomas Huth -Date: Tue, 23 Jan 2018 19:12:46 +0100 -Subject: [PATCH 4/8] s390x/kvm: provide stfle.81 - -RH-Author: Thomas Huth -Message-id: <1516734766-12075-4-git-send-email-thuth@redhat.com> -Patchwork-id: 78702 -O-Subject: [RHEL-7.5 qemu-kvm-ma PATCH 3/3] s390x/kvm: provide stfle.81 -Bugzilla: 1535606 -RH-Acked-by: David Hildenbrand -RH-Acked-by: Cornelia Huck -RH-Acked-by: Jens Freimann - -From: Christian Borntraeger - -stfle.81 (ppa15) is a transparent facility that can be passed to the -guest without the need to implement hypervisor support. As this feature -can be provided by firmware we add it to all full models. - -Cc: qemu-stable@nongnu.org -Signed-off-by: Christian Borntraeger -Message-Id: <20180118085628.40798-4-borntraeger@de.ibm.com> -Reviewed-by: Halil Pasic -Reviewed-by: David Hildenbrand -Reviewed-by: Thomas Huth -Signed-off-by: Cornelia Huck -(cherry picked from commit 9f0d13f4f1de3cf9b70435cc4e87a301ee12471f) -Signed-off-by: Miroslav Rezanina ---- - target/s390x/cpu_features.c | 1 + - target/s390x/cpu_features_def.h | 1 + - target/s390x/gen-features.c | 1 + - 3 files changed, 3 insertions(+) - -diff --git a/target/s390x/cpu_features.c b/target/s390x/cpu_features.c -index d39efb0..5ecb2bc 100644 ---- a/target/s390x/cpu_features.c -+++ b/target/s390x/cpu_features.c -@@ -89,6 +89,7 @@ static const S390FeatDef s390_features[] = { - FEAT_INIT("msa4-base", S390_FEAT_TYPE_STFL, 77, "Message-security-assist-extension-4 facility (excluding subfunctions)"), - FEAT_INIT("edat2", S390_FEAT_TYPE_STFL, 78, "Enhanced-DAT facility 2"), - FEAT_INIT("dfppc", S390_FEAT_TYPE_STFL, 80, "Decimal-floating-point packed-conversion facility"), -+ FEAT_INIT("ppa15", S390_FEAT_TYPE_STFL, 81, "PPA15 is installed"), - FEAT_INIT("bpb", S390_FEAT_TYPE_STFL, 82, "Branch prediction blocking"), - FEAT_INIT("vx", S390_FEAT_TYPE_STFL, 129, "Vector facility"), - FEAT_INIT("iep", S390_FEAT_TYPE_STFL, 130, "Instruction-execution-protection facility"), -diff --git a/target/s390x/cpu_features_def.h b/target/s390x/cpu_features_def.h -index 4487cfd..4d93087 100644 ---- a/target/s390x/cpu_features_def.h -+++ b/target/s390x/cpu_features_def.h -@@ -80,6 +80,7 @@ typedef enum { - S390_FEAT_MSA_EXT_4, - S390_FEAT_EDAT_2, - S390_FEAT_DFP_PACKED_CONVERSION, -+ S390_FEAT_PPA15, - S390_FEAT_BPB, - S390_FEAT_VECTOR, - S390_FEAT_INSTRUCTION_EXEC_PROT, -diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c -index 13a6291..e6b4152 100644 ---- a/target/s390x/gen-features.c -+++ b/target/s390x/gen-features.c -@@ -352,6 +352,7 @@ static uint16_t base_GEN14_GA1[] = { - * support these features yet. - */ - static uint16_t full_GEN7_GA1[] = { -+ S390_FEAT_PPA15, - S390_FEAT_BPB, - S390_FEAT_SIE_F2, - S390_FEAT_SIE_SKEY, --- -1.8.3.1 - diff --git a/SOURCES/kvm-s390x-print-CPU-definitions-in-sorted-order.patch b/SOURCES/kvm-s390x-print-CPU-definitions-in-sorted-order.patch deleted file mode 100644 index 281f64c..0000000 --- a/SOURCES/kvm-s390x-print-CPU-definitions-in-sorted-order.patch +++ /dev/null @@ -1,121 +0,0 @@ -From a009d0254cdfd6deb532ef654a3f2811cb8b9c15 Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Fri, 10 Nov 2017 14:49:03 +0100 -Subject: [PATCH 6/7] s390x: print CPU definitions in sorted order - -RH-Author: David Hildenbrand -Message-id: <20171110144904.7026-2-david@redhat.com> -Patchwork-id: 77647 -O-Subject: [RHEL-7.5 qemu-kvm-ma PATCH v3 1/2] s390x: print CPU definitions in sorted order -Bugzilla: 1504138 -RH-Acked-by: Thomas Huth -RH-Acked-by: Cornelia Huck -RH-Acked-by: Eduardo Habkost - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1504138 -Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=14527097 -Upstream-status: 99aa6bf29b87052d9603c5bf5c23d0db960f30ce - -Other architectures provide nicely sorted lists, let's do it similarly on -s390x. - -While at it, clean up the code we have to touch either way. - -Acked-by: Christian Borntraeger -Signed-off-by: David Hildenbrand -Message-Id: <20170913132417.24384-16-david@redhat.com> -Signed-off-by: Cornelia Huck -(cherry picked from commit 99aa6bf29b87052d9603c5bf5c23d0db960f30ce) -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - target/s390x/cpu_models.c | 56 ++++++++++++++++++++++++++++++++++------------- - 1 file changed, 41 insertions(+), 15 deletions(-) - -diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c -index fa1338f..e055852 100644 ---- a/target/s390x/cpu_models.c -+++ b/target/s390x/cpu_models.c -@@ -267,16 +267,11 @@ const S390CPUDef *s390_find_cpu_def(uint16_t type, uint8_t gen, uint8_t ec_ga, - return last_compatible; - } - --struct S390PrintCpuListInfo { -- FILE *f; -- fprintf_function print; --}; -- --static void print_cpu_model_list(ObjectClass *klass, void *opaque) -+static void s390_print_cpu_model_list_entry(gpointer data, gpointer user_data) - { -- struct S390PrintCpuListInfo *info = opaque; -- S390CPUClass *scc = S390_CPU_CLASS(klass); -- char *name = g_strdup(object_class_get_name(klass)); -+ CPUListState *s = user_data; -+ const S390CPUClass *scc = S390_CPU_CLASS((ObjectClass *)data); -+ char *name = g_strdup(object_class_get_name((ObjectClass *)data)); - const char *details = ""; - - if (scc->is_static) { -@@ -287,21 +282,52 @@ static void print_cpu_model_list(ObjectClass *klass, void *opaque) - - /* strip off the -s390-cpu */ - g_strrstr(name, "-" TYPE_S390_CPU)[0] = 0; -- (*info->print)(info->f, "s390 %-15s %-35s %s\n", name, scc->desc, -- details); -+ (*s->cpu_fprintf)(s->file, "s390 %-15s %-35s %s\n", name, scc->desc, -+ details); - g_free(name); - } - -+static gint s390_cpu_list_compare(gconstpointer a, gconstpointer b) -+{ -+ const S390CPUClass *cc_a = S390_CPU_CLASS((ObjectClass *)a); -+ const S390CPUClass *cc_b = S390_CPU_CLASS((ObjectClass *)b); -+ const char *name_a = object_class_get_name((ObjectClass *)a); -+ const char *name_b = object_class_get_name((ObjectClass *)b); -+ -+ /* move qemu and host to the top of the list, qemu first, host second */ -+ if (name_a[0] == 'q') { -+ return -1; -+ } else if (name_b[0] == 'q') { -+ return 1; -+ } else if (name_a[0] == 'h') { -+ return -1; -+ } else if (name_b[0] == 'h') { -+ return 1; -+ } -+ -+ /* keep the same order we have in our table (sorted by release date) */ -+ if (cc_a->cpu_def != cc_b->cpu_def) { -+ return cc_a->cpu_def - cc_b->cpu_def; -+ } -+ -+ /* exact same definition - list base model first */ -+ return cc_a->is_static ? -1 : 1; -+} -+ - void s390_cpu_list(FILE *f, fprintf_function print) - { -- struct S390PrintCpuListInfo info = { -- .f = f, -- .print = print, -+ CPUListState s = { -+ .file = f, -+ .cpu_fprintf = print, - }; - S390FeatGroup group; - S390Feat feat; -+ GSList *list; - -- object_class_foreach(print_cpu_model_list, TYPE_S390_CPU, false, &info); -+ list = object_class_get_list(TYPE_S390_CPU, false); -+ list = g_slist_sort(list, s390_cpu_list_compare); -+ g_slist_foreach(list, s390_print_cpu_model_list_entry, &s); -+ g_slist_free(list); - - (*print)(f, "\nRecognized feature flags:\n"); - for (feat = 0; feat < S390_FEAT_MAX; feat++) { --- -1.8.3.1 - diff --git a/SOURCES/kvm-s390x-s390-skeys-Mark-the-storage-key-devices-with-u.patch b/SOURCES/kvm-s390x-s390-skeys-Mark-the-storage-key-devices-with-u.patch deleted file mode 100644 index 068318d..0000000 --- a/SOURCES/kvm-s390x-s390-skeys-Mark-the-storage-key-devices-with-u.patch +++ /dev/null @@ -1,79 +0,0 @@ -From b830658def8c36d5449e0b704e2f0cb26a593c1e Mon Sep 17 00:00:00 2001 -From: Thomas Huth -Date: Mon, 9 Oct 2017 12:32:42 +0200 -Subject: [PATCH 23/34] s390x/s390-skeys: Mark the storage key devices with - user_creatable = false - -RH-Author: Thomas Huth -Message-id: <1507552368-9245-7-git-send-email-thuth@redhat.com> -Patchwork-id: 77024 -O-Subject: [RHEL-7.5 qemu-kvm-ma PATCH 06/12] s390x/s390-skeys: Mark the storage key devices with user_creatable = false -Bugzilla: 1492033 -RH-Acked-by: Cornelia Huck -RH-Acked-by: David Gibson -RH-Acked-by: Miroslav Rezanina - -QEMU currently aborts if the user tries to create a skey device: - -$ s390x-softmmu/qemu-system-s390x -nographic -device s390-skeys-qemu -qemu-system-s390x: hw/s390x/s390-skeys.c:30: s390_get_skeys_device: - Assertion `ss' failed. -Aborted (core dumped) - -The storage key devices are only meant to be instantiated one time, -internally. They can not be used by the user, so mark them with -user_creatable = false. - -Signed-off-by: Thomas Huth -Message-Id: <1503569328-22197-1-git-send-email-thuth@redhat.com> -Reviewed-by: Claudio Imbrenda -Reviewed-by: Halil Pasic -Signed-off-by: Cornelia Huck -(cherry picked from commit 574ee06de9c4fe63c90be90dc9c747fc9382bb2b) -Signed-off-by: Miroslav Rezanina ---- - hw/s390x/s390-skeys-kvm.c | 4 ++++ - hw/s390x/s390-skeys.c | 4 ++++ - 2 files changed, 8 insertions(+) - -diff --git a/hw/s390x/s390-skeys-kvm.c b/hw/s390x/s390-skeys-kvm.c -index 131da56..dc54ed8 100644 ---- a/hw/s390x/s390-skeys-kvm.c -+++ b/hw/s390x/s390-skeys-kvm.c -@@ -54,10 +54,14 @@ static int kvm_s390_skeys_set(S390SKeysState *ss, uint64_t start_gfn, - static void kvm_s390_skeys_class_init(ObjectClass *oc, void *data) - { - S390SKeysClass *skeyclass = S390_SKEYS_CLASS(oc); -+ DeviceClass *dc = DEVICE_CLASS(oc); - - skeyclass->skeys_enabled = kvm_s390_skeys_enabled; - skeyclass->get_skeys = kvm_s390_skeys_get; - skeyclass->set_skeys = kvm_s390_skeys_set; -+ -+ /* Reason: Internal device (only one skeys device for the whole memory) */ -+ dc->user_creatable = false; - } - - static const TypeInfo kvm_s390_skeys_info = { -diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c -index c0de3b0..53ad5d3 100644 ---- a/hw/s390x/s390-skeys.c -+++ b/hw/s390x/s390-skeys.c -@@ -229,10 +229,14 @@ static int qemu_s390_skeys_get(S390SKeysState *ss, uint64_t start_gfn, - static void qemu_s390_skeys_class_init(ObjectClass *oc, void *data) - { - S390SKeysClass *skeyclass = S390_SKEYS_CLASS(oc); -+ DeviceClass *dc = DEVICE_CLASS(oc); - - skeyclass->skeys_enabled = qemu_s390_skeys_enabled; - skeyclass->get_skeys = qemu_s390_skeys_get; - skeyclass->set_skeys = qemu_s390_skeys_set; -+ -+ /* Reason: Internal device (only one skeys device for the whole memory) */ -+ dc->user_creatable = false; - } - - static const TypeInfo qemu_s390_skeys_info = { --- -1.8.3.1 - diff --git a/SOURCES/kvm-s390x-s390-stattrib-Mark-the-storage-attribute-as-no.patch b/SOURCES/kvm-s390x-s390-stattrib-Mark-the-storage-attribute-as-no.patch deleted file mode 100644 index 07a7598..0000000 --- a/SOURCES/kvm-s390x-s390-stattrib-Mark-the-storage-attribute-as-no.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 69504b264f7272d31814d928ffbd9d01661ec62a Mon Sep 17 00:00:00 2001 -From: Thomas Huth -Date: Mon, 9 Oct 2017 12:32:41 +0200 -Subject: [PATCH 22/34] s390x/s390-stattrib: Mark the storage attribute as not - user_creatable - -RH-Author: Thomas Huth -Message-id: <1507552368-9245-6-git-send-email-thuth@redhat.com> -Patchwork-id: 77022 -O-Subject: [RHEL-7.5 qemu-kvm-ma PATCH 05/12] s390x/s390-stattrib: Mark the storage attribute as not user_creatable -Bugzilla: 1492033 -RH-Acked-by: Cornelia Huck -RH-Acked-by: David Gibson -RH-Acked-by: Miroslav Rezanina - -The storage attribute devices are only meant to be instantiated one -time, internally. They can not be used by the user, so mark them with -user_creatable = false. - -Suggested-by: Claudio Imbrenda -Signed-off-by: Thomas Huth -Message-Id: <1503576029-24264-1-git-send-email-thuth@redhat.com> -Reviewed-by: Claudio Imbrenda -Reviewed-by: Halil Pasic -Signed-off-by: Cornelia Huck -(cherry picked from commit 3ea6d20e0baacb4a1211ed0ea57db14e2fc927ce) -Signed-off-by: Miroslav Rezanina ---- - hw/s390x/s390-stattrib-kvm.c | 4 ++++ - hw/s390x/s390-stattrib.c | 4 ++++ - 2 files changed, 8 insertions(+) - -diff --git a/hw/s390x/s390-stattrib-kvm.c b/hw/s390x/s390-stattrib-kvm.c -index ff3f89f..bc0274d 100644 ---- a/hw/s390x/s390-stattrib-kvm.c -+++ b/hw/s390x/s390-stattrib-kvm.c -@@ -163,6 +163,7 @@ static int kvm_s390_stattrib_get_active(S390StAttribState *sa) - static void kvm_s390_stattrib_class_init(ObjectClass *oc, void *data) - { - S390StAttribClass *sac = S390_STATTRIB_CLASS(oc); -+ DeviceClass *dc = DEVICE_CLASS(oc); - - sac->get_stattr = kvm_s390_stattrib_get_stattr; - sac->peek_stattr = kvm_s390_stattrib_peek_stattr; -@@ -171,6 +172,9 @@ static void kvm_s390_stattrib_class_init(ObjectClass *oc, void *data) - sac->get_dirtycount = kvm_s390_stattrib_get_dirtycount; - sac->synchronize = kvm_s390_stattrib_synchronize; - sac->get_active = kvm_s390_stattrib_get_active; -+ -+ /* Reason: Can only be instantiated one time (internally) */ -+ dc->user_creatable = false; - } - - static const TypeInfo kvm_s390_stattrib_info = { -diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c -index d14923f..f75548e 100644 ---- a/hw/s390x/s390-stattrib.c -+++ b/hw/s390x/s390-stattrib.c -@@ -306,6 +306,7 @@ static int qemu_s390_get_active(S390StAttribState *sa) - static void qemu_s390_stattrib_class_init(ObjectClass *oc, void *data) - { - S390StAttribClass *sa_cl = S390_STATTRIB_CLASS(oc); -+ DeviceClass *dc = DEVICE_CLASS(oc); - - sa_cl->synchronize = qemu_s390_synchronize_stub; - sa_cl->get_stattr = qemu_s390_get_stattr_stub; -@@ -314,6 +315,9 @@ static void qemu_s390_stattrib_class_init(ObjectClass *oc, void *data) - sa_cl->set_migrationmode = qemu_s390_set_migrationmode_stub; - sa_cl->get_dirtycount = qemu_s390_get_dirtycount_stub; - sa_cl->get_active = qemu_s390_get_active; -+ -+ /* Reason: Can only be instantiated one time (internally) */ -+ dc->user_creatable = false; - } - - static const TypeInfo qemu_s390_stattrib_info = { --- -1.8.3.1 - diff --git a/SOURCES/kvm-s390x-sclp-Mark-the-sclp-device-with-user_creatable-.patch b/SOURCES/kvm-s390x-sclp-Mark-the-sclp-device-with-user_creatable-.patch deleted file mode 100644 index b12727f..0000000 --- a/SOURCES/kvm-s390x-sclp-Mark-the-sclp-device-with-user_creatable-.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 26c80458360dfd14a97a7f5823ad578ebcdffd87 Mon Sep 17 00:00:00 2001 -From: Thomas Huth -Date: Mon, 9 Oct 2017 12:32:47 +0200 -Subject: [PATCH 28/34] s390x/sclp: Mark the sclp device with user_creatable = - false - -RH-Author: Thomas Huth -Message-id: <1507552368-9245-12-git-send-email-thuth@redhat.com> -Patchwork-id: 77029 -O-Subject: [RHEL-7.5 qemu-kvm-ma PATCH 11/12] s390x/sclp: Mark the sclp device with user_creatable = false -Bugzilla: 1492033 -RH-Acked-by: Cornelia Huck -RH-Acked-by: David Gibson -RH-Acked-by: Miroslav Rezanina - -The "sclp" device is just an internal device that can not be instantiated -by the users. If they try to use it, they only get a simple error message: - -$ qemu-system-s390x -nographic -device sclp -qemu-system-s390x: Option '-device s390-sclp-event-facility' cannot be -handled by this machine - -Since sclp_init() tries to create a TYPE_SCLP_EVENT_FACILITY which is -a non-pluggable sysbus device, there is really no way that the "sclp" -device can be used by the user, so let's set the user_creatable = false -accordingly. - -Signed-off-by: Thomas Huth -Message-Id: <1507125199-22562-1-git-send-email-thuth@redhat.com> -Reviewed-by: Claudio Imbrenda -Reviewed-by: Farhan Ali -Acked-by: Halil Pasic -Signed-off-by: Cornelia Huck -(cherry picked from commit e6cb60bf158fe7ea4505d760fdbb7abe4dbf4362) -Signed-off-by: Miroslav Rezanina ---- - hw/s390x/sclp.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c -index 9253dbb..b94ce0c 100644 ---- a/hw/s390x/sclp.c -+++ b/hw/s390x/sclp.c -@@ -584,6 +584,11 @@ static void sclp_class_init(ObjectClass *oc, void *data) - dc->realize = sclp_realize; - dc->hotpluggable = false; - set_bit(DEVICE_CATEGORY_MISC, dc->categories); -+ /* -+ * Reason: Creates TYPE_SCLP_EVENT_FACILITY in sclp_init -+ * which is a non-pluggable sysbus device -+ */ -+ dc->user_creatable = false; - - sc->read_SCP_info = read_SCP_info; - sc->read_storage_element0_info = read_storage_element0_info; --- -1.8.3.1 - diff --git a/SOURCES/kvm-s390x-sclp-fix-maxram-calculation.patch b/SOURCES/kvm-s390x-sclp-fix-maxram-calculation.patch new file mode 100644 index 0000000..fa319c5 --- /dev/null +++ b/SOURCES/kvm-s390x-sclp-fix-maxram-calculation.patch @@ -0,0 +1,51 @@ +From 48815daa02f8d90bf1f4dc10e560cdc9ca61352b Mon Sep 17 00:00:00 2001 +From: Cornelia Huck +Date: Wed, 1 Aug 2018 11:09:14 +0200 +Subject: [PATCH 14/15] s390x/sclp: fix maxram calculation + +RH-Author: Cornelia Huck +Message-id: <20180801110914.17729-1-cohuck@redhat.com> +Patchwork-id: 81564 +O-Subject: [RHEL-7.6 qemu-kvm-ma PATCH] s390x/sclp: fix maxram calculation +Bugzilla: 1595740 +RH-Acked-by: David Hildenbrand +RH-Acked-by: Thomas Huth +RH-Acked-by: Miroslav Rezanina + +From: Christian Borntraeger + +We clamp down ram_size to match the sclp increment size. We do +not do the same for maxram_size, which means for large guests +with some sizes (e.g. -m 50000) maxram_size differs from ram_size. +This can break other code (e.g. CMMA migration) which uses maxram_size +to calculate the number of pages and then throws some errors. + +Fixes: 82fab5c5b90e468f3e9d54c ("s390x/sclp: remove memory hotplug support") +Signed-off-by: Christian Borntraeger +CC: qemu-stable@nongnu.org +CC: David Hildenbrand +Message-Id: <1532959766-53343-1-git-send-email-borntraeger@de.ibm.com> +Reviewed-by: David Hildenbrand +Signed-off-by: Cornelia Huck +(cherry picked from commit 408e5ace517ff18c9c7cd918fc93358162e6e26d) +Signed-off-by: Cornelia Huck +Signed-off-by: Miroslav Rezanina +--- + hw/s390x/sclp.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c +index 047d577..2abdb62 100644 +--- a/hw/s390x/sclp.c ++++ b/hw/s390x/sclp.c +@@ -319,6 +319,7 @@ static void sclp_memory_init(SCLPDevice *sclp) + initial_mem = initial_mem >> increment_size << increment_size; + + machine->ram_size = initial_mem; ++ machine->maxram_size = initial_mem; + /* let's propagate the changed ram size into the global variable. */ + ram_size = initial_mem; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-s390x-sclp-mark-sclp-cpu-hotplug-as-non-usercreatabl.patch b/SOURCES/kvm-s390x-sclp-mark-sclp-cpu-hotplug-as-non-usercreatabl.patch deleted file mode 100644 index 2710dda..0000000 --- a/SOURCES/kvm-s390x-sclp-mark-sclp-cpu-hotplug-as-non-usercreatabl.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 3ad6366bd5d0bea256b37b0e8cdef6ff5ac2e4e2 Mon Sep 17 00:00:00 2001 -From: Thomas Huth -Date: Mon, 9 Oct 2017 12:32:46 +0200 -Subject: [PATCH 27/34] s390x/sclp: mark sclp-cpu-hotplug as non-usercreatable - -RH-Author: Thomas Huth -Message-id: <1507552368-9245-11-git-send-email-thuth@redhat.com> -Patchwork-id: 77028 -O-Subject: [RHEL-7.5 qemu-kvm-ma PATCH 10/12] s390x/sclp: mark sclp-cpu-hotplug as non-usercreatable -Bugzilla: 1492033 -RH-Acked-by: Cornelia Huck -RH-Acked-by: David Gibson -RH-Acked-by: Miroslav Rezanina - -From: Cornelia Huck - -A TYPE_SCLP_CPU_HOTPLUG device for handling cpu hotplug events -is already created by the sclp event facility. Adding a second -TYPE_SCLP_CPU_HOTPLUG device via -device sclp-cpu-hotplug creates -an ambiguity in raise_irq_cpu_hotplug(), leading to a crash once -a cpu is hotplugged. - -To fix this, disallow creating a sclp-cpu-hotplug device manually. - -Reviewed-by: Thomas Huth -Acked-by: Christian Borntraeger -Signed-off-by: Cornelia Huck -(cherry picked from commit 7aa4d85d2962a072931657bee964113727ebf0c8) -Signed-off-by: Miroslav Rezanina ---- - hw/s390x/sclpcpu.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/hw/s390x/sclpcpu.c b/hw/s390x/sclpcpu.c -index b1f3ef8..fa17cc5 100644 ---- a/hw/s390x/sclpcpu.c -+++ b/hw/s390x/sclpcpu.c -@@ -83,6 +83,12 @@ static void cpu_class_init(ObjectClass *oc, void *data) - k->get_receive_mask = receive_mask; - k->read_event_data = read_event_data; - set_bit(DEVICE_CATEGORY_MISC, dc->categories); -+ /* -+ * Reason: raise_irq_cpu_hotplug() depends on an unique -+ * TYPE_SCLP_CPU_HOTPLUG device, which is already created -+ * by the sclp event facility -+ */ -+ dc->user_creatable = false; - } - - static const TypeInfo sclp_cpu_info = { --- -1.8.3.1 - diff --git a/SOURCES/kvm-scripts-dump-guest-memory.py-add-vmcoreinfo.patch b/SOURCES/kvm-scripts-dump-guest-memory.py-add-vmcoreinfo.patch deleted file mode 100644 index fe58e14..0000000 --- a/SOURCES/kvm-scripts-dump-guest-memory.py-add-vmcoreinfo.patch +++ /dev/null @@ -1,134 +0,0 @@ -From 7d60c93dbdf3568c9b96cf6bc61af49966e1a06f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Mon, 27 Nov 2017 22:51:09 +0100 -Subject: [PATCH 11/21] scripts/dump-guest-memory.py: add vmcoreinfo -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Marc-André Lureau -Message-id: <20171127225111.24518-8-marcandre.lureau@redhat.com> -Patchwork-id: 77929 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 7/9] scripts/dump-guest-memory.py: add vmcoreinfo -Bugzilla: 1398633 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Andrew Jones -RH-Acked-by: Miroslav Rezanina - -Add a vmcoreinfo ELF note in the dump if vmcoreinfo device has the -memory location details. - -Signed-off-by: Marc-André Lureau -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin - -(cherry picked from commit d23bfa91b7789534d16ede6cb7d925bfac3f3c4c) -Signed-off-by: Marc-André Lureau -Signed-off-by: Miroslav Rezanina ---- - scripts/dump-guest-memory.py | 61 ++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 61 insertions(+) - -diff --git a/scripts/dump-guest-memory.py b/scripts/dump-guest-memory.py -index f7c6635..69dd5ef 100644 ---- a/scripts/dump-guest-memory.py -+++ b/scripts/dump-guest-memory.py -@@ -14,6 +14,7 @@ the COPYING file in the top-level directory. - """ - - import ctypes -+import struct - - UINTPTR_T = gdb.lookup_type("uintptr_t") - -@@ -45,6 +46,17 @@ EM_S390 = 22 - EM_AARCH = 183 - EM_X86_64 = 62 - -+VMCOREINFO_FORMAT_ELF = 1 -+ -+def le16_to_cpu(val): -+ return struct.unpack(" 1 << 20: -+ print('warning: invalid vmcoreinfo size') -+ return -+ # now get the full note -+ note = get_arch_note(self.endianness, -+ header.n_namesz - 1, header.n_descsz) -+ ctypes.memmove(ctypes.pointer(note), vmcoreinfo, ctypes.sizeof(note)) -+ -+ self.notes.append(note) -+ self.segments[0].p_filesz += ctypes.sizeof(note) -+ self.segments[0].p_memsz += ctypes.sizeof(note) -+ - def add_segment(self, p_type, p_paddr, p_size): - """Adds a segment to the elf.""" - -@@ -505,6 +536,35 @@ shape and this command should mostly work.""" - cur += chunk_size - left -= chunk_size - -+ def phys_memory_read(self, addr, size): -+ qemu_core = gdb.inferiors()[0] -+ for block in self.guest_phys_blocks: -+ if block["target_start"] <= addr \ -+ and addr + size <= block["target_end"]: -+ haddr = block["host_addr"] + (addr - block["target_start"]) -+ return qemu_core.read_memory(haddr, size) -+ return None -+ -+ def add_vmcoreinfo(self): -+ if not gdb.parse_and_eval("vmcoreinfo_find()") \ -+ or not gdb.parse_and_eval("vmcoreinfo_find()->has_vmcoreinfo"): -+ return -+ -+ fmt = gdb.parse_and_eval("vmcoreinfo_find()->vmcoreinfo.guest_format") -+ addr = gdb.parse_and_eval("vmcoreinfo_find()->vmcoreinfo.paddr") -+ size = gdb.parse_and_eval("vmcoreinfo_find()->vmcoreinfo.size") -+ -+ fmt = le16_to_cpu(fmt) -+ addr = le64_to_cpu(addr) -+ size = le32_to_cpu(size) -+ -+ if fmt != VMCOREINFO_FORMAT_ELF: -+ return -+ -+ vmcoreinfo = self.phys_memory_read(addr, size) -+ if vmcoreinfo: -+ self.elf.add_vmcoreinfo_note(vmcoreinfo.tobytes()) -+ - def invoke(self, args, from_tty): - """Handles command invocation from gdb.""" - -@@ -518,6 +578,7 @@ shape and this command should mostly work.""" - - self.elf = ELF(argv[1]) - self.guest_phys_blocks = get_guest_phys_blocks() -+ self.add_vmcoreinfo() - - with open(argv[0], "wb") as vmcore: - self.dump_init(vmcore) --- -1.8.3.1 - diff --git a/SOURCES/kvm-scripts-qemu.py-allow-adding-to-the-list-of-extra-ar.patch b/SOURCES/kvm-scripts-qemu.py-allow-adding-to-the-list-of-extra-ar.patch new file mode 100644 index 0000000..a6f01a6 --- /dev/null +++ b/SOURCES/kvm-scripts-qemu.py-allow-adding-to-the-list-of-extra-ar.patch @@ -0,0 +1,53 @@ +From 257036163501f7c59bd54ce6d050563780cd8a98 Mon Sep 17 00:00:00 2001 +From: Yash Mankad +Date: Tue, 17 Jul 2018 23:38:05 +0200 +Subject: [PATCH 48/89] scripts/qemu.py: allow adding to the list of extra + arguments +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Yash Mankad +Message-id: <4ba44e15a56b1119045859193f7e18d11d4a5ba4.1531870629.git.ymankad@redhat.com> +Patchwork-id: 81384 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 2/5] scripts/qemu.py: allow adding to the list of extra arguments +Bugzilla: +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: John Snow +RH-Acked-by: Eduardo Habkost + +From: Cleber Rosa + +Tests will often need to add extra arguments to QEMU command +line arguments. + +Signed-off-by: Cleber Rosa +Reviewed-by: Stefan Hajnoczi +Message-Id: <20180530184156.15634-3-crosa@redhat.com> +Reviewed-by: Philippe Mathieu-Daudé +Tested-by: Philippe Mathieu-Daudé +Signed-off-by: Eduardo Habkost +(cherry picked from commit 572a82438308216fbfc615c924b6e94e4b68dfaa) +Signed-off-by: Yash Mankad +Signed-off-by: Miroslav Rezanina +--- + scripts/qemu.py | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/scripts/qemu.py b/scripts/qemu.py +index 08a3e9a..7cd8193 100644 +--- a/scripts/qemu.py ++++ b/scripts/qemu.py +@@ -359,3 +359,9 @@ class QEMUMachine(object): + of the qemu process. + ''' + return self._iolog ++ ++ def add_args(self, *args): ++ ''' ++ Adds to the list of extra arguments to be given to the QEMU binary ++ ''' ++ self._args.extend(args) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-scripts-qemu.py-introduce-set_console-method.patch b/SOURCES/kvm-scripts-qemu.py-introduce-set_console-method.patch new file mode 100644 index 0000000..d0bce8c --- /dev/null +++ b/SOURCES/kvm-scripts-qemu.py-introduce-set_console-method.patch @@ -0,0 +1,197 @@ +From 7d56e73ebc9b816b987f26ec66101562bdd941b8 Mon Sep 17 00:00:00 2001 +From: Yash Mankad +Date: Tue, 17 Jul 2018 23:38:07 +0200 +Subject: [PATCH 50/89] scripts/qemu.py: introduce set_console() method +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Yash Mankad +Message-id: <3daef391b07eb8b66afabe66bee05749ab1a5e9a.1531870629.git.ymankad@redhat.com> +Patchwork-id: 81381 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 4/5] scripts/qemu.py: introduce set_console() method +Bugzilla: +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: John Snow +RH-Acked-by: Eduardo Habkost + +From: Cleber Rosa + +The set_console() method is intended to ease higher level use cases +that require a console device. + +The amount of intelligence is limited on purpose, requiring either the +device type explicitly, or the existence of a machine (pattern) +definition. + +Because of the console device type selection criteria (by machine +type), users should also be able to define that. It'll then be used +for both '-machine' and for the console device type selection. + +Users of the set_console() method will certainly be interested in +accessing the console device, and for that a console_socket property +has been added. + +Signed-off-by: Cleber Rosa +Message-Id: <20180530184156.15634-5-crosa@redhat.com> +Tested-by: Philippe Mathieu-Daudé +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Eduardo Habkost +(cherry picked from commit 22dea9db2baf72a79782c748c57e2d87b06234d5) +Signed-off-by: Yash Mankad +Signed-off-by: Miroslav Rezanina +--- + scripts/qemu.py | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 96 insertions(+), 1 deletion(-) + +diff --git a/scripts/qemu.py b/scripts/qemu.py +index 7cd8193..f099ce7 100644 +--- a/scripts/qemu.py ++++ b/scripts/qemu.py +@@ -17,19 +17,41 @@ import logging + import os + import subprocess + import qmp.qmp ++import re + import shutil ++import socket + import tempfile + + + LOG = logging.getLogger(__name__) + + ++#: Maps machine types to the preferred console device types ++CONSOLE_DEV_TYPES = { ++ r'^clipper$': 'isa-serial', ++ r'^malta': 'isa-serial', ++ r'^(pc.*|q35.*|isapc)$': 'isa-serial', ++ r'^(40p|powernv|prep)$': 'isa-serial', ++ r'^pseries.*': 'spapr-vty', ++ r'^s390-ccw-virtio.*': 'sclpconsole', ++ } ++ ++ + class QEMUMachineError(Exception): + """ + Exception called when an error in QEMUMachine happens. + """ + + ++class QEMUMachineAddDeviceError(QEMUMachineError): ++ """ ++ Exception raised when a request to add a device can not be fulfilled ++ ++ The failures are caused by limitations, lack of information or conflicting ++ requests on the QEMUMachine methods. This exception does not represent ++ failures reported by the QEMU binary itself. ++ """ ++ + class MonitorResponseError(qmp.qmp.QMPError): + ''' + Represents erroneous QMP monitor reply +@@ -91,6 +113,10 @@ class QEMUMachine(object): + self._test_dir = test_dir + self._temp_dir = None + self._launched = False ++ self._machine = None ++ self._console_device_type = None ++ self._console_address = None ++ self._console_socket = None + + # just in case logging wasn't configured by the main script: + logging.basicConfig() +@@ -175,9 +201,19 @@ class QEMUMachine(object): + self._monitor_address[1]) + else: + moncdev = 'socket,id=mon,path=%s' % self._vm_monitor +- return ['-chardev', moncdev, ++ args = ['-chardev', moncdev, + '-mon', 'chardev=mon,mode=control', + '-display', 'none', '-vga', 'none'] ++ if self._machine is not None: ++ args.extend(['-machine', self._machine]) ++ if self._console_device_type is not None: ++ self._console_address = os.path.join(self._temp_dir, ++ self._name + "-console.sock") ++ chardev = ('socket,id=console,path=%s,server,nowait' % ++ self._console_address) ++ device = '%s,chardev=console' % self._console_device_type ++ args.extend(['-chardev', chardev, '-device', device]) ++ return args + + def _pre_launch(self): + self._temp_dir = tempfile.mkdtemp(dir=self._test_dir) +@@ -202,6 +238,10 @@ class QEMUMachine(object): + + self._qemu_log_path = None + ++ if self._console_socket is not None: ++ self._console_socket.close() ++ self._console_socket = None ++ + if self._temp_dir is not None: + shutil.rmtree(self._temp_dir) + self._temp_dir = None +@@ -365,3 +405,58 @@ class QEMUMachine(object): + Adds to the list of extra arguments to be given to the QEMU binary + ''' + self._args.extend(args) ++ ++ def set_machine(self, machine_type): ++ ''' ++ Sets the machine type ++ ++ If set, the machine type will be added to the base arguments ++ of the resulting QEMU command line. ++ ''' ++ self._machine = machine_type ++ ++ def set_console(self, device_type=None): ++ ''' ++ Sets the device type for a console device ++ ++ If set, the console device and a backing character device will ++ be added to the base arguments of the resulting QEMU command ++ line. ++ ++ This is a convenience method that will either use the provided ++ device type, of if not given, it will used the device type set ++ on CONSOLE_DEV_TYPES. ++ ++ The actual setting of command line arguments will be be done at ++ machine launch time, as it depends on the temporary directory ++ to be created. ++ ++ @param device_type: the device type, such as "isa-serial" ++ @raises: QEMUMachineAddDeviceError if the device type is not given ++ and can not be determined. ++ ''' ++ if device_type is None: ++ if self._machine is None: ++ raise QEMUMachineAddDeviceError("Can not add a console device:" ++ " QEMU instance without a " ++ "defined machine type") ++ for regex, device in CONSOLE_DEV_TYPES.items(): ++ if re.match(regex, self._machine): ++ device_type = device ++ break ++ if device_type is None: ++ raise QEMUMachineAddDeviceError("Can not add a console device:" ++ " no matching console device " ++ "type definition") ++ self._console_device_type = device_type ++ ++ @property ++ def console_socket(self): ++ """ ++ Returns a socket connected to the console ++ """ ++ if self._console_socket is None: ++ self._console_socket = socket.socket(socket.AF_UNIX, ++ socket.SOCK_STREAM) ++ self._console_socket.connect(self._console_address) ++ return self._console_socket +-- +1.8.3.1 + diff --git a/SOURCES/kvm-scsi-Fix-onboard-HBAs-to-pick-up-drive-if-scsi.patch b/SOURCES/kvm-scsi-Fix-onboard-HBAs-to-pick-up-drive-if-scsi.patch deleted file mode 100644 index 7615297..0000000 --- a/SOURCES/kvm-scsi-Fix-onboard-HBAs-to-pick-up-drive-if-scsi.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 8198d8d36fed85743c4d2b26aa1670f5bc3a9793 Mon Sep 17 00:00:00 2001 -From: Markus Armbruster -Date: Tue, 28 Nov 2017 13:24:17 +0100 -Subject: [PATCH 16/21] scsi: Fix onboard HBAs to pick up -drive if=scsi - -RH-Author: Markus Armbruster -Message-id: <20171128132417.18247-2-armbru@redhat.com> -Patchwork-id: 77934 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 1/1] scsi: Fix onboard HBAs to pick up -drive if=scsi -Bugzilla: 1497740 -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth -RH-Acked-by: Jeffrey Cody - -Downstream commit 7977e6031 "scsi: Disable deprecated implicit SCSI -HBA creation more cleanly" regressed -drive if=scsi and its sugared -forms like -cdrom with onboard HBAs. Instead of creating SCSI devices -connected to the onboard HBA, we reject these options like this: - - $ qemu-kvm -cdrom r7.iso - qemu-kvm: -cdrom r7.iso: machine type does not support if=scsi,bus=0,unit=2 - -The culprit is scsi_bus_legacy_handle_cmdline(): commit 7977e6031 -accidentally neutered it for the non-deprecated case (onboard SCSI -HBA) in addition to the deprecated case (non-onboard SCSI HBA with -legacy magic). Fix by narrowing the neutering to the deprecated case. - -Signed-off-by: Markus Armbruster -Signed-off-by: Miroslav Rezanina ---- - hw/scsi/scsi-bus.c | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c -index 309daaa..404686a 100644 ---- a/hw/scsi/scsi-bus.c -+++ b/hw/scsi/scsi-bus.c -@@ -265,8 +265,6 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk, - - void scsi_bus_legacy_handle_cmdline(SCSIBus *bus, bool deprecated) - { --#if 0 /* Disabled for Red Hat Enterprise Linux */ -- - Location loc; - DriveInfo *dinfo; - int unit; -@@ -279,6 +277,7 @@ void scsi_bus_legacy_handle_cmdline(SCSIBus *bus, bool deprecated) - } - qemu_opts_loc_restore(dinfo->opts); - if (deprecated) { -+#if 0 /* Disabled for Red Hat Enterprise Linux */ - /* Handling -drive not claimed by machine initialization */ - if (blk_get_attached_dev(blk_by_legacy_dinfo(dinfo))) { - continue; /* claimed */ -@@ -288,12 +287,14 @@ void scsi_bus_legacy_handle_cmdline(SCSIBus *bus, bool deprecated) - " machine type", - bus->busnr, unit); - } -+#else -+ continue; -+#endif - } - scsi_bus_legacy_add_drive(bus, blk_by_legacy_dinfo(dinfo), - unit, false, -1, NULL, &error_fatal); - } - loc_pop(&loc); --#endif - } - - #if 0 /* Disabled for Red Hat Enterprise Linux */ --- -1.8.3.1 - diff --git a/SOURCES/kvm-scsi-Improve-scsi_sense_to_errno.patch b/SOURCES/kvm-scsi-Improve-scsi_sense_to_errno.patch deleted file mode 100644 index 30d1be7..0000000 --- a/SOURCES/kvm-scsi-Improve-scsi_sense_to_errno.patch +++ /dev/null @@ -1,74 +0,0 @@ -From bc3855000036c3abe2a440d3cb65a9fbd90745fb Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Sat, 2 Dec 2017 12:19:41 +0100 -Subject: [PATCH 15/36] scsi: Improve scsi_sense_to_errno - -RH-Author: Paolo Bonzini -Message-id: <20171202121953.13317-6-pbonzini@redhat.com> -Patchwork-id: 78077 -O-Subject: [RHEL7.4 qemu-kvm-rhev PATCH 05/17] scsi: Improve scsi_sense_to_errno -Bugzilla: 1464908 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: John Snow - -From: Fam Zheng - -Tweak the errno mapping to return more accurate/appropriate values. - -Signed-off-by: Fam Zheng -Message-Id: <20170821141008.19383-3-famz@redhat.com> -Signed-off-by: Paolo Bonzini -(cherry picked from commit 5efa3c04483d408a03ff5f018842501a2048a51b) -Signed-off-by: Miroslav Rezanina ---- - util/scsi.c | 16 ++++++++++++---- - 1 file changed, 12 insertions(+), 4 deletions(-) - -diff --git a/util/scsi.c b/util/scsi.c -index a671079..472eb5b 100644 ---- a/util/scsi.c -+++ b/util/scsi.c -@@ -18,13 +18,16 @@ - int scsi_sense_to_errno(int key, int asc, int ascq) - { - switch (key) { -- case 0x02: /* NOT READY */ -- return EBUSY; -- case 0x07: /* DATA PROTECTION */ -- return EACCES; -+ case 0x00: /* NO SENSE */ -+ case 0x01: /* RECOVERED ERROR */ -+ case 0x06: /* UNIT ATTENTION */ -+ /* These sense keys are not errors */ -+ return 0; - case 0x0b: /* COMMAND ABORTED */ - return ECANCELED; -+ case 0x02: /* NOT READY */ - case 0x05: /* ILLEGAL REQUEST */ -+ case 0x07: /* DATA PROTECTION */ - /* Parse ASCQ */ - break; - default: -@@ -37,6 +40,7 @@ int scsi_sense_to_errno(int key, int asc, int ascq) - case 0x2600: /* INVALID FIELD IN PARAMETER LIST */ - return EINVAL; - case 0x2100: /* LBA OUT OF RANGE */ -+ case 0x2707: /* SPACE ALLOC FAILED */ - return ENOSPC; - case 0x2500: /* LOGICAL UNIT NOT SUPPORTED */ - return ENOTSUP; -@@ -46,6 +50,10 @@ int scsi_sense_to_errno(int key, int asc, int ascq) - return ENOMEDIUM; - case 0x2700: /* WRITE PROTECTED */ - return EACCES; -+ case 0x0401: /* NOT READY, IN PROGRESS OF BECOMING READY */ -+ return EAGAIN; -+ case 0x0402: /* NOT READY, INITIALIZING COMMAND REQUIRED */ -+ return ENOTCONN; - default: - return EIO; - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-scsi-Introduce-scsi_sense_buf_to_errno.patch b/SOURCES/kvm-scsi-Introduce-scsi_sense_buf_to_errno.patch deleted file mode 100644 index 17986f2..0000000 --- a/SOURCES/kvm-scsi-Introduce-scsi_sense_buf_to_errno.patch +++ /dev/null @@ -1,81 +0,0 @@ -From f635140407bf6d024045ad18e7a1f8f802690b36 Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Sat, 2 Dec 2017 12:19:42 +0100 -Subject: [PATCH 16/36] scsi: Introduce scsi_sense_buf_to_errno - -RH-Author: Paolo Bonzini -Message-id: <20171202121953.13317-7-pbonzini@redhat.com> -Patchwork-id: 78082 -O-Subject: [RHEL7.4 qemu-kvm-rhev PATCH 06/17] scsi: Introduce scsi_sense_buf_to_errno -Bugzilla: 1464908 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: John Snow - -From: Fam Zheng - -This recognizes the "fixed" and "descriptor" format sense data, extracts -the sense key/asc/ascq fields then converts them to an errno. - -Signed-off-by: Fam Zheng -Message-Id: <20170821141008.19383-4-famz@redhat.com> -Signed-off-by: Paolo Bonzini -(cherry picked from commit a485b23425c755867d6caa6ab590be4e0473e35a) -Signed-off-by: Miroslav Rezanina ---- - include/scsi/scsi.h | 1 + - util/scsi.c | 30 ++++++++++++++++++++++++++++++ - 2 files changed, 31 insertions(+) - -diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h -index f894ace..fe33038 100644 ---- a/include/scsi/scsi.h -+++ b/include/scsi/scsi.h -@@ -15,5 +15,6 @@ - #define QEMU_SCSI_H - - int scsi_sense_to_errno(int key, int asc, int ascq); -+int scsi_sense_buf_to_errno(const uint8_t *sense, size_t sense_size); - - #endif -diff --git a/util/scsi.c b/util/scsi.c -index 472eb5b..472293d 100644 ---- a/util/scsi.c -+++ b/util/scsi.c -@@ -58,3 +58,33 @@ int scsi_sense_to_errno(int key, int asc, int ascq) - return EIO; - } - } -+ -+int scsi_sense_buf_to_errno(const uint8_t *sense, size_t sense_size) -+{ -+ int key, asc, ascq; -+ if (sense_size < 1) { -+ return EIO; -+ } -+ switch (sense[0]) { -+ case 0x70: /* Fixed format sense data. */ -+ if (sense_size < 14) { -+ return EIO; -+ } -+ key = sense[2] & 0xF; -+ asc = sense[12]; -+ ascq = sense[13]; -+ break; -+ case 0x72: /* Descriptor format sense data. */ -+ if (sense_size < 4) { -+ return EIO; -+ } -+ key = sense[1] & 0xF; -+ asc = sense[2]; -+ ascq = sense[3]; -+ break; -+ default: -+ return EIO; -+ break; -+ } -+ return scsi_sense_to_errno(key, asc, ascq); -+} --- -1.8.3.1 - diff --git a/SOURCES/kvm-scsi-Refactor-scsi-sense-interpreting-code.patch b/SOURCES/kvm-scsi-Refactor-scsi-sense-interpreting-code.patch deleted file mode 100644 index a607b02..0000000 --- a/SOURCES/kvm-scsi-Refactor-scsi-sense-interpreting-code.patch +++ /dev/null @@ -1,207 +0,0 @@ -From 4f71eecd159d2ab9e66e1f6115a0490676f76e8e Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Sat, 2 Dec 2017 12:19:40 +0100 -Subject: [PATCH 14/36] scsi: Refactor scsi sense interpreting code - -RH-Author: Paolo Bonzini -Message-id: <20171202121953.13317-5-pbonzini@redhat.com> -Patchwork-id: 78073 -O-Subject: [RHEL7.4 qemu-kvm-rhev PATCH 04/17] scsi: Refactor scsi sense interpreting code -Bugzilla: 1464908 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: John Snow - -From: Fam Zheng - -So that it can be reused outside of iscsi.c. - -Also update MAINTAINERS to include the new files in SCSI section. - -Signed-off-by: Fam Zheng -Message-Id: <20170821141008.19383-2-famz@redhat.com> -Signed-off-by: Paolo Bonzini -(cherry picked from commit 2875135807771a0d07ba1c878c20b757ed7adffb) -Signed-off-by: Miroslav Rezanina ---- - MAINTAINERS | 2 ++ - block/iscsi.c | 45 ++++----------------------------------------- - include/scsi/scsi.h | 19 +++++++++++++++++++ - util/Makefile.objs | 1 + - util/scsi.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ - 5 files changed, 78 insertions(+), 41 deletions(-) - create mode 100644 include/scsi/scsi.h - create mode 100644 util/scsi.c - -diff --git a/MAINTAINERS b/MAINTAINERS -index ccee28b..2a4e503 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -969,7 +969,9 @@ SCSI - M: Paolo Bonzini - S: Supported - F: include/hw/scsi/* -+F: include/scsi/* - F: hw/scsi/* -+F: util/scsi* - F: tests/virtio-scsi-test.c - T: git git://github.com/bonzini/qemu.git scsi-next - -diff --git a/block/iscsi.c b/block/iscsi.c -index d557c99..4bed63c 100644 ---- a/block/iscsi.c -+++ b/block/iscsi.c -@@ -40,6 +40,7 @@ - #include "qmp-commands.h" - #include "qapi/qmp/qstring.h" - #include "crypto/secret.h" -+#include "scsi/scsi.h" - - #include - #include -@@ -209,47 +210,9 @@ static inline unsigned exp_random(double mean) - - static int iscsi_translate_sense(struct scsi_sense *sense) - { -- int ret; -- -- switch (sense->key) { -- case SCSI_SENSE_NOT_READY: -- return -EBUSY; -- case SCSI_SENSE_DATA_PROTECTION: -- return -EACCES; -- case SCSI_SENSE_COMMAND_ABORTED: -- return -ECANCELED; -- case SCSI_SENSE_ILLEGAL_REQUEST: -- /* Parse ASCQ */ -- break; -- default: -- return -EIO; -- } -- switch (sense->ascq) { -- case SCSI_SENSE_ASCQ_PARAMETER_LIST_LENGTH_ERROR: -- case SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE: -- case SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB: -- case SCSI_SENSE_ASCQ_INVALID_FIELD_IN_PARAMETER_LIST: -- ret = -EINVAL; -- break; -- case SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE: -- ret = -ENOSPC; -- break; -- case SCSI_SENSE_ASCQ_LOGICAL_UNIT_NOT_SUPPORTED: -- ret = -ENOTSUP; -- break; -- case SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT: -- case SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_CLOSED: -- case SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_OPEN: -- ret = -ENOMEDIUM; -- break; -- case SCSI_SENSE_ASCQ_WRITE_PROTECTED: -- ret = -EACCES; -- break; -- default: -- ret = -EIO; -- break; -- } -- return ret; -+ return - scsi_sense_to_errno(sense->key, -+ (sense->ascq & 0xFF00) >> 8, -+ sense->ascq & 0xFF); - } - - /* Called (via iscsi_service) with QemuMutex held. */ -diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h -new file mode 100644 -index 0000000..f894ace ---- /dev/null -+++ b/include/scsi/scsi.h -@@ -0,0 +1,19 @@ -+/* -+ * SCSI helpers -+ * -+ * Copyright 2017 Red Hat, Inc. -+ * -+ * Authors: -+ * Fam Zheng -+ * -+ * 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. -+ */ -+#ifndef QEMU_SCSI_H -+#define QEMU_SCSI_H -+ -+int scsi_sense_to_errno(int key, int asc, int ascq); -+ -+#endif -diff --git a/util/Makefile.objs b/util/Makefile.objs -index 50a55ec..c9e6c49 100644 ---- a/util/Makefile.objs -+++ b/util/Makefile.objs -@@ -45,3 +45,4 @@ util-obj-y += qht.o - util-obj-y += range.o - util-obj-y += stats64.o - util-obj-y += systemd.o -+util-obj-y += scsi.o -diff --git a/util/scsi.c b/util/scsi.c -new file mode 100644 -index 0000000..a671079 ---- /dev/null -+++ b/util/scsi.c -@@ -0,0 +1,52 @@ -+/* -+ * SCSI helpers -+ * -+ * Copyright 2017 Red Hat, Inc. -+ * -+ * Authors: -+ * Fam Zheng -+ * -+ * 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. -+ */ -+ -+#include "qemu/osdep.h" -+#include "scsi/scsi.h" -+ -+int scsi_sense_to_errno(int key, int asc, int ascq) -+{ -+ switch (key) { -+ case 0x02: /* NOT READY */ -+ return EBUSY; -+ case 0x07: /* DATA PROTECTION */ -+ return EACCES; -+ case 0x0b: /* COMMAND ABORTED */ -+ return ECANCELED; -+ case 0x05: /* ILLEGAL REQUEST */ -+ /* Parse ASCQ */ -+ break; -+ default: -+ return EIO; -+ } -+ switch ((asc << 8) | ascq) { -+ case 0x1a00: /* PARAMETER LIST LENGTH ERROR */ -+ case 0x2000: /* INVALID OPERATION CODE */ -+ case 0x2400: /* INVALID FIELD IN CDB */ -+ case 0x2600: /* INVALID FIELD IN PARAMETER LIST */ -+ return EINVAL; -+ case 0x2100: /* LBA OUT OF RANGE */ -+ return ENOSPC; -+ case 0x2500: /* LOGICAL UNIT NOT SUPPORTED */ -+ return ENOTSUP; -+ case 0x3a00: /* MEDIUM NOT PRESENT */ -+ case 0x3a01: /* MEDIUM NOT PRESENT TRAY CLOSED */ -+ case 0x3a02: /* MEDIUM NOT PRESENT TRAY OPEN */ -+ return ENOMEDIUM; -+ case 0x2700: /* WRITE PROTECTED */ -+ return EACCES; -+ default: -+ return EIO; -+ } -+} --- -1.8.3.1 - diff --git a/SOURCES/kvm-scsi-add-multipath-support-to-qemu-pr-helper.patch b/SOURCES/kvm-scsi-add-multipath-support-to-qemu-pr-helper.patch deleted file mode 100644 index 7780492..0000000 --- a/SOURCES/kvm-scsi-add-multipath-support-to-qemu-pr-helper.patch +++ /dev/null @@ -1,675 +0,0 @@ -From d9ebb2728bc92d055f178f1c45f82979c542a9aa Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Sat, 2 Dec 2017 12:19:50 +0100 -Subject: [PATCH 24/36] scsi: add multipath support to qemu-pr-helper - -RH-Author: Paolo Bonzini -Message-id: <20171202121953.13317-15-pbonzini@redhat.com> -Patchwork-id: 78083 -O-Subject: [RHEL7.4 qemu-kvm-rhev PATCH 14/17] scsi: add multipath support to qemu-pr-helper -Bugzilla: 1464908 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: John Snow - -Proper support of persistent reservation for multipath devices requires -communication with the multipath daemon, so that the reservation is -registered and applied when a path comes up. The device mapper -utilities provide a library to do so; this patch makes qemu-pr-helper.c -detect multipath devices and, when one is found, delegate the operation -to libmpathpersist. - -Signed-off-by: Paolo Bonzini -(cherry picked from commit fe8fc5ae5c808e037fa4746cbfeb3c07ffe0af81) - -[RHEL: do not use {0} because GCC does not like it; will be changed - upstream, but squash it in here so that all commits compile - Paolo] - -Signed-off-by: Miroslav Rezanina ---- - Makefile | 3 + - configure | 46 +++++++ - docs/pr-manager.rst | 27 ++++ - include/scsi/utils.h | 4 + - scsi/qemu-pr-helper.c | 346 +++++++++++++++++++++++++++++++++++++++++++++++++- - scsi/utils.c | 10 ++ - 6 files changed, 433 insertions(+), 3 deletions(-) - -diff --git a/Makefile b/Makefile -index 3e76953..ae48405 100644 ---- a/Makefile -+++ b/Makefile -@@ -387,6 +387,9 @@ fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/9p-marshal - fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap - - scsi/qemu-pr-helper$(EXESUF): scsi/qemu-pr-helper.o scsi/utils.o $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS) -+ifdef CONFIG_MPATH -+scsi/qemu-pr-helper$(EXESUF): LIBS += -ludev -lmultipath -lmpathpersist -+endif - - qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool - $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$@") -diff --git a/configure b/configure -index 2df1b42..97ee507 100755 ---- a/configure -+++ b/configure -@@ -291,6 +291,7 @@ pixman="" - sdl="" - sdlabi="" - virtfs="" -+mpath="" - vnc="yes" - sparse="no" - vde="" -@@ -956,6 +957,10 @@ for opt do - ;; - --enable-virtfs) virtfs="yes" - ;; -+ --disable-mpath) mpath="no" -+ ;; -+ --enable-mpath) mpath="yes" -+ ;; - --disable-vnc) vnc="no" - ;; - --enable-vnc) vnc="yes" -@@ -1510,6 +1515,7 @@ disabled with --disable-FEATURE, default is enabled if available: - vnc-png PNG compression for VNC server - cocoa Cocoa UI (Mac OS X only) - virtfs VirtFS -+ mpath Multipath persistent reservation passthrough - xen xen backend driver support - xen-pci-passthrough - brlapi BrlAPI (Braile) -@@ -3358,6 +3364,30 @@ else - fi - - ########################################## -+# libmpathpersist probe -+ -+if test "$mpath" != "no" ; then -+ cat > $TMPC < -+#include -+unsigned mpath_mx_alloc_len = 1024; -+int logsink; -+int main(void) { -+ struct udev *udev = udev_new(); -+ mpath_lib_init(udev); -+ return 0; -+} -+EOF -+ if compile_prog "" "-ludev -lmultipath -lmpathpersist" ; then -+ mpathpersist=yes -+ else -+ mpathpersist=no -+ fi -+else -+ mpathpersist=no -+fi -+ -+########################################## - # libcap probe - - if test "$cap" != "no" ; then -@@ -5075,12 +5105,24 @@ if test "$softmmu" = yes ; then - fi - virtfs=no - fi -+ if test "$mpath" != no && test "$mpathpersist" = yes ; then -+ mpath=yes -+ else -+ if test "$mpath" = yes; then -+ error_exit "Multipath requires libmpathpersist devel" -+ fi -+ mpath=no -+ fi - tools="$tools scsi/qemu-pr-helper\$(EXESUF)" - else - if test "$virtfs" = yes; then - error_exit "VirtFS is supported only on Linux" - fi - virtfs=no -+ if test "$mpath" = yes; then -+ error_exit "Multipath is supported only on Linux" -+ fi -+ mpath=no - fi - fi - -@@ -5327,6 +5369,7 @@ echo "Audio drivers $audio_drv_list" - echo "Block whitelist (rw) $block_drv_rw_whitelist" - echo "Block whitelist (ro) $block_drv_ro_whitelist" - echo "VirtFS support $virtfs" -+echo "Multipath support $mpath" - echo "VNC support $vnc" - if test "$vnc" = "yes" ; then - echo "VNC SASL support $vnc_sasl" -@@ -5777,6 +5820,9 @@ fi - if test "$virtfs" = "yes" ; then - echo "CONFIG_VIRTFS=y" >> $config_host_mak - fi -+if test "$mpath" = "yes" ; then -+ echo "CONFIG_MPATH=y" >> $config_host_mak -+fi - if test "$vhost_scsi" = "yes" ; then - echo "CONFIG_VHOST_SCSI=y" >> $config_host_mak - fi -diff --git a/docs/pr-manager.rst b/docs/pr-manager.rst -index 7107e59..9b1de19 100644 ---- a/docs/pr-manager.rst -+++ b/docs/pr-manager.rst -@@ -60,6 +60,7 @@ system service and supports the following option: - - -d, --daemon run in the background - -q, --quiet decrease verbosity -+-v, --verbose increase verbosity - -f, --pidfile=path PID file when running as a daemon - -k, --socket=path path to the socket - -T, --trace=trace-opts tracing options -@@ -82,3 +83,29 @@ its operation. To do this, add the following options: - - -u, --user=user user to drop privileges to - -g, --group=group group to drop privileges to -+ -+--------------------------------------------- -+Multipath devices and persistent reservations -+--------------------------------------------- -+ -+Proper support of persistent reservation for multipath devices requires -+communication with the multipath daemon, so that the reservation is -+registered and applied when a path is newly discovered or becomes online -+again. :command:`qemu-pr-helper` can do this if the ``libmpathpersist`` -+library was available on the system at build time. -+ -+As of August 2017, a reservation key must be specified in ``multipath.conf`` -+for ``multipathd`` to check for persistent reservation for newly -+discovered paths or reinstated paths. The attribute can be added -+to the ``defaults`` section or the ``multipaths`` section; for example:: -+ -+ multipaths { -+ multipath { -+ wwid XXXXXXXXXXXXXXXX -+ alias yellow -+ reservation_key 0x123abc -+ } -+ } -+ -+Linking :program:`qemu-pr-helper` to ``libmpathpersist`` does not impede -+its usage on regular SCSI devices. -diff --git a/include/scsi/utils.h b/include/scsi/utils.h -index d301b31..00a4bdb 100644 ---- a/include/scsi/utils.h -+++ b/include/scsi/utils.h -@@ -72,10 +72,14 @@ extern const struct SCSISense sense_code_IO_ERROR; - extern const struct SCSISense sense_code_I_T_NEXUS_LOSS; - /* Command aborted, Logical Unit failure */ - extern const struct SCSISense sense_code_LUN_FAILURE; -+/* Command aborted, LUN Communication failure */ -+extern const struct SCSISense sense_code_LUN_COMM_FAILURE; - /* Command aborted, Overlapped Commands Attempted */ - extern const struct SCSISense sense_code_OVERLAPPED_COMMANDS; - /* LUN not ready, Capacity data has changed */ - extern const struct SCSISense sense_code_CAPACITY_CHANGED; -+/* Unit attention, SCSI bus reset */ -+extern const struct SCSISense sense_code_SCSI_BUS_RESET; - /* LUN not ready, Medium not present */ - extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM; - /* Unit attention, Power on, reset or bus device reset occurred */ -diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c -index f46266f..42bc2cf 100644 ---- a/scsi/qemu-pr-helper.c -+++ b/scsi/qemu-pr-helper.c -@@ -30,6 +30,12 @@ - #include - #include - -+#ifdef CONFIG_MPATH -+#include -+#include -+#include -+#endif -+ - #include "qapi/error.h" - #include "qemu-common.h" - #include "qemu/cutils.h" -@@ -60,6 +66,7 @@ static enum { RUNNING, TERMINATE, TERMINATING } state; - static QIOChannelSocket *server_ioc; - static int server_watch; - static int num_active_sockets = 1; -+static int noisy; - static int verbose; - - #ifdef CONFIG_LIBCAP -@@ -204,9 +211,316 @@ static int do_sgio(int fd, const uint8_t *cdb, uint8_t *sense, - return r; - } - -+/* Device mapper interface */ -+ -+#ifdef CONFIG_MPATH -+#define CONTROL_PATH "/dev/mapper/control" -+ -+typedef struct DMData { -+ struct dm_ioctl dm; -+ uint8_t data[1024]; -+} DMData; -+ -+static int control_fd; -+ -+static void *dm_ioctl(int ioc, struct dm_ioctl *dm) -+{ -+ static DMData d; -+ memcpy(&d.dm, dm, sizeof(d.dm)); -+ QEMU_BUILD_BUG_ON(sizeof(d.data) < sizeof(struct dm_target_spec)); -+ -+ d.dm.version[0] = DM_VERSION_MAJOR; -+ d.dm.version[1] = 0; -+ d.dm.version[2] = 0; -+ d.dm.data_size = 1024; -+ d.dm.data_start = offsetof(DMData, data); -+ if (ioctl(control_fd, ioc, &d) < 0) { -+ return NULL; -+ } -+ memcpy(dm, &d.dm, sizeof(d.dm)); -+ return &d.data; -+} -+ -+static void *dm_dev_ioctl(int fd, int ioc, struct dm_ioctl *dm) -+{ -+ struct stat st; -+ int r; -+ -+ r = fstat(fd, &st); -+ if (r < 0) { -+ perror("fstat"); -+ exit(1); -+ } -+ -+ dm->dev = st.st_rdev; -+ return dm_ioctl(ioc, dm); -+} -+ -+static void dm_init(void) -+{ -+ control_fd = open(CONTROL_PATH, O_RDWR); -+ if (control_fd < 0) { -+ perror("Cannot open " CONTROL_PATH); -+ exit(1); -+ } -+ struct dm_ioctl dm = {}; -+ if (!dm_ioctl(DM_VERSION, &dm)) { -+ perror("ioctl"); -+ exit(1); -+ } -+ if (dm.version[0] != DM_VERSION_MAJOR) { -+ fprintf(stderr, "Unsupported device mapper interface"); -+ exit(1); -+ } -+} -+ -+/* Variables required by libmultipath and libmpathpersist. */ -+QEMU_BUILD_BUG_ON(PR_HELPER_DATA_SIZE > MPATH_MAX_PARAM_LEN); -+unsigned mpath_mx_alloc_len = PR_HELPER_DATA_SIZE; -+int logsink; -+ -+static void multipath_pr_init(void) -+{ -+ static struct udev *udev; -+ -+ udev = udev_new(); -+ mpath_lib_init(udev); -+} -+ -+static int is_mpath(int fd) -+{ -+ struct dm_ioctl dm = { .flags = DM_NOFLUSH_FLAG }; -+ struct dm_target_spec *tgt; -+ -+ tgt = dm_dev_ioctl(fd, DM_TABLE_STATUS, &dm); -+ if (!tgt) { -+ if (errno == ENXIO) { -+ return 0; -+ } -+ perror("ioctl"); -+ exit(EXIT_FAILURE); -+ } -+ return !strncmp(tgt->target_type, "multipath", DM_MAX_TYPE_NAME); -+} -+ -+static int mpath_reconstruct_sense(int fd, int r, uint8_t *sense) -+{ -+ switch (r) { -+ case MPATH_PR_SUCCESS: -+ return GOOD; -+ case MPATH_PR_SENSE_NOT_READY: -+ case MPATH_PR_SENSE_MEDIUM_ERROR: -+ case MPATH_PR_SENSE_HARDWARE_ERROR: -+ case MPATH_PR_SENSE_ABORTED_COMMAND: -+ { -+ /* libmpathpersist ate the exact sense. Try to find it by -+ * issuing TEST UNIT READY. -+ */ -+ uint8_t cdb[6] = { TEST_UNIT_READY }; -+ int sz = 0; -+ return do_sgio(fd, cdb, sense, NULL, &sz, SG_DXFER_NONE); -+ } -+ -+ case MPATH_PR_SENSE_UNIT_ATTENTION: -+ /* Congratulations libmpathpersist, you ruined the Unit Attention... -+ * Return a heavyweight one. -+ */ -+ scsi_build_sense(sense, SENSE_CODE(SCSI_BUS_RESET)); -+ return CHECK_CONDITION; -+ case MPATH_PR_SENSE_INVALID_OP: -+ /* Only one valid sense. */ -+ scsi_build_sense(sense, SENSE_CODE(INVALID_OPCODE)); -+ return CHECK_CONDITION; -+ case MPATH_PR_ILLEGAL_REQ: -+ /* Guess. */ -+ scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM)); -+ return CHECK_CONDITION; -+ case MPATH_PR_NO_SENSE: -+ scsi_build_sense(sense, SENSE_CODE(NO_SENSE)); -+ return CHECK_CONDITION; -+ -+ case MPATH_PR_RESERV_CONFLICT: -+ return RESERVATION_CONFLICT; -+ -+ case MPATH_PR_OTHER: -+ default: -+ scsi_build_sense(sense, SENSE_CODE(LUN_COMM_FAILURE)); -+ return CHECK_CONDITION; -+ } -+} -+ -+static int multipath_pr_in(int fd, const uint8_t *cdb, uint8_t *sense, -+ uint8_t *data, int sz) -+{ -+ int rq_servact = cdb[1]; -+ struct prin_resp resp; -+ size_t written; -+ int r; -+ -+ switch (rq_servact) { -+ case MPATH_PRIN_RKEY_SA: -+ case MPATH_PRIN_RRES_SA: -+ case MPATH_PRIN_RCAP_SA: -+ break; -+ case MPATH_PRIN_RFSTAT_SA: -+ /* Nobody implements it anyway, so bail out. */ -+ default: -+ /* Cannot parse any other output. */ -+ scsi_build_sense(sense, SENSE_CODE(INVALID_FIELD)); -+ return CHECK_CONDITION; -+ } -+ -+ r = mpath_persistent_reserve_in(fd, rq_servact, &resp, noisy, verbose); -+ if (r == MPATH_PR_SUCCESS) { -+ switch (rq_servact) { -+ case MPATH_PRIN_RKEY_SA: -+ case MPATH_PRIN_RRES_SA: { -+ struct prin_readdescr *out = &resp.prin_descriptor.prin_readkeys; -+ assert(sz >= 8); -+ written = MIN(out->additional_length + 8, sz); -+ stl_be_p(&data[0], out->prgeneration); -+ stl_be_p(&data[4], out->additional_length); -+ memcpy(&data[8], out->key_list, written - 8); -+ break; -+ } -+ case MPATH_PRIN_RCAP_SA: { -+ struct prin_capdescr *out = &resp.prin_descriptor.prin_readcap; -+ assert(sz >= 6); -+ written = 6; -+ stw_be_p(&data[0], out->length); -+ data[2] = out->flags[0]; -+ data[3] = out->flags[1]; -+ stw_be_p(&data[4], out->pr_type_mask); -+ break; -+ } -+ default: -+ scsi_build_sense(sense, SENSE_CODE(INVALID_OPCODE)); -+ return CHECK_CONDITION; -+ } -+ assert(written <= sz); -+ memset(data + written, 0, sz - written); -+ } -+ -+ return mpath_reconstruct_sense(fd, r, sense); -+} -+ -+static int multipath_pr_out(int fd, const uint8_t *cdb, uint8_t *sense, -+ const uint8_t *param, int sz) -+{ -+ int rq_servact = cdb[1]; -+ int rq_scope = cdb[2] >> 4; -+ int rq_type = cdb[2] & 0xf; -+ struct prout_param_descriptor paramp; -+ char transportids[PR_HELPER_DATA_SIZE]; -+ int r; -+ -+ switch (rq_servact) { -+ case MPATH_PROUT_REG_SA: -+ case MPATH_PROUT_RES_SA: -+ case MPATH_PROUT_REL_SA: -+ case MPATH_PROUT_CLEAR_SA: -+ case MPATH_PROUT_PREE_SA: -+ case MPATH_PROUT_PREE_AB_SA: -+ case MPATH_PROUT_REG_IGN_SA: -+ break; -+ case MPATH_PROUT_REG_MOV_SA: -+ /* Not supported by struct prout_param_descriptor. */ -+ default: -+ /* Cannot parse any other input. */ -+ scsi_build_sense(sense, SENSE_CODE(INVALID_FIELD)); -+ return CHECK_CONDITION; -+ } -+ -+ /* Convert input data, especially transport IDs, to the structs -+ * used by libmpathpersist (which, of course, will immediately -+ * do the opposite). -+ */ -+ memset(¶mp, 0, sizeof(paramp)); -+ memcpy(¶mp.key, ¶m[0], 8); -+ memcpy(¶mp.sa_key, ¶m[8], 8); -+ paramp.sa_flags = param[10]; -+ if (sz > PR_OUT_FIXED_PARAM_SIZE) { -+ size_t transportid_len; -+ int i, j; -+ if (sz < PR_OUT_FIXED_PARAM_SIZE + 4) { -+ scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM_LEN)); -+ return CHECK_CONDITION; -+ } -+ transportid_len = ldl_be_p(¶m[24]) + PR_OUT_FIXED_PARAM_SIZE + 4; -+ if (transportid_len > sz) { -+ scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM)); -+ return CHECK_CONDITION; -+ } -+ for (i = PR_OUT_FIXED_PARAM_SIZE + 4, j = 0; i < transportid_len; ) { -+ struct transportid *id = (struct transportid *) &transportids[j]; -+ int len; -+ -+ id->format_code = param[i] & 0xc0; -+ id->protocol_id = param[i] & 0x0f; -+ switch (param[i] & 0xcf) { -+ case 0: -+ /* FC transport. */ -+ if (i + 24 > transportid_len) { -+ goto illegal_req; -+ } -+ memcpy(id->n_port_name, ¶m[i + 8], 8); -+ j += offsetof(struct transportid, n_port_name[8]); -+ i += 24; -+ break; -+ case 3: -+ case 0x43: -+ /* iSCSI transport. */ -+ len = lduw_be_p(¶m[i + 2]); -+ if (len > 252 || (len & 3) || i + len + 4 > transportid_len) { -+ /* For format code 00, the standard says the maximum is 223 -+ * plus the NUL terminator. For format code 01 there is no -+ * maximum length, but libmpathpersist ignores the first -+ * byte of id->iscsi_name so our maximum is 252. -+ */ -+ goto illegal_req; -+ } -+ if (memchr(¶m[i + 4], 0, len) == NULL) { -+ goto illegal_req; -+ } -+ memcpy(id->iscsi_name, ¶m[i + 2], len + 2); -+ j += offsetof(struct transportid, iscsi_name[len + 2]); -+ i += len + 4; -+ break; -+ case 6: -+ /* SAS transport. */ -+ if (i + 24 > transportid_len) { -+ goto illegal_req; -+ } -+ memcpy(id->sas_address, ¶m[i + 4], 8); -+ j += offsetof(struct transportid, sas_address[8]); -+ i += 24; -+ break; -+ default: -+ illegal_req: -+ scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM)); -+ return CHECK_CONDITION; -+ } -+ -+ paramp.trnptid_list[paramp.num_transportid++] = id; -+ } -+ } -+ -+ r = mpath_persistent_reserve_out(fd, rq_servact, rq_scope, rq_type, -+ ¶mp, noisy, verbose); -+ return mpath_reconstruct_sense(fd, r, sense); -+} -+#endif -+ - static int do_pr_in(int fd, const uint8_t *cdb, uint8_t *sense, - uint8_t *data, int *resp_sz) - { -+#ifdef CONFIG_MPATH -+ if (is_mpath(fd)) { -+ /* multipath_pr_in fills the whole input buffer. */ -+ return multipath_pr_in(fd, cdb, sense, data, *resp_sz); -+ } -+#endif -+ - return do_sgio(fd, cdb, sense, data, resp_sz, - SG_DXFER_FROM_DEV); - } -@@ -214,7 +528,14 @@ static int do_pr_in(int fd, const uint8_t *cdb, uint8_t *sense, - static int do_pr_out(int fd, const uint8_t *cdb, uint8_t *sense, - const uint8_t *param, int sz) - { -- int resp_sz = sz; -+ int resp_sz; -+#ifdef CONFIG_MPATH -+ if (is_mpath(fd)) { -+ return multipath_pr_out(fd, cdb, sense, param, sz); -+ } -+#endif -+ -+ resp_sz = sz; - return do_sgio(fd, cdb, sense, (uint8_t *)param, &resp_sz, - SG_DXFER_TO_DEV); - } -@@ -525,6 +846,14 @@ static int drop_privileges(void) - return -1; - } - -+#ifdef CONFIG_MPATH -+ /* For /dev/mapper/control ioctls */ -+ if (capng_update(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED, -+ CAP_SYS_ADMIN) < 0) { -+ return -1; -+ } -+#endif -+ - /* Change user/group id, retaining the capabilities. Because file descriptors - * are passed via SCM_RIGHTS, we don't need supplementary groups (and in - * fact the helper can run as "nobody"). -@@ -541,7 +870,7 @@ static int drop_privileges(void) - - int main(int argc, char **argv) - { -- const char *sopt = "hVk:fdT:u:g:q"; -+ const char *sopt = "hVk:fdT:u:g:vq"; - struct option lopt[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, -@@ -551,10 +880,12 @@ int main(int argc, char **argv) - { "trace", required_argument, NULL, 'T' }, - { "user", required_argument, NULL, 'u' }, - { "group", required_argument, NULL, 'g' }, -+ { "verbose", no_argument, NULL, 'v' }, - { "quiet", no_argument, NULL, 'q' }, - { NULL, 0, NULL, 0 } - }; - int opt_ind = 0; -+ int loglevel = 1; - int quiet = 0; - int ch; - Error *local_err = NULL; -@@ -631,6 +962,9 @@ int main(int argc, char **argv) - case 'q': - quiet = 1; - break; -+ case 'v': -+ ++loglevel; -+ break; - case 'T': - g_free(trace_file); - trace_file = trace_opt_parse(optarg); -@@ -650,7 +984,8 @@ int main(int argc, char **argv) - } - - /* set verbosity */ -- verbose = !quiet; -+ noisy = !quiet && (loglevel >= 3); -+ verbose = quiet ? 0 : MIN(loglevel, 3); - - if (!trace_init_backends()) { - exit(EXIT_FAILURE); -@@ -658,6 +993,11 @@ int main(int argc, char **argv) - trace_init_file(trace_file); - qemu_set_log(LOG_TRACE); - -+#ifdef CONFIG_MPATH -+ dm_init(); -+ multipath_pr_init(); -+#endif -+ - socket_activation = check_socket_activation(); - if (socket_activation == 0) { - SocketAddress saddr; -diff --git a/scsi/utils.c b/scsi/utils.c -index fab60bd..5684951 100644 ---- a/scsi/utils.c -+++ b/scsi/utils.c -@@ -206,6 +206,11 @@ const struct SCSISense sense_code_OVERLAPPED_COMMANDS = { - .key = ABORTED_COMMAND, .asc = 0x4e, .ascq = 0x00 - }; - -+/* Command aborted, LUN Communication Failure */ -+const struct SCSISense sense_code_LUN_COMM_FAILURE = { -+ .key = ABORTED_COMMAND, .asc = 0x08, .ascq = 0x00 -+}; -+ - /* Unit attention, Capacity data has changed */ - const struct SCSISense sense_code_CAPACITY_CHANGED = { - .key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09 -@@ -216,6 +221,11 @@ const struct SCSISense sense_code_RESET = { - .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00 - }; - -+/* Unit attention, SCSI bus reset */ -+const struct SCSISense sense_code_SCSI_BUS_RESET = { -+ .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x02 -+}; -+ - /* Unit attention, No medium */ - const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = { - .key = UNIT_ATTENTION, .asc = 0x3a, .ascq = 0x00 --- -1.8.3.1 - diff --git a/SOURCES/kvm-scsi-add-persistent-reservation-manager-using-qemu-p.patch b/SOURCES/kvm-scsi-add-persistent-reservation-manager-using-qemu-p.patch deleted file mode 100644 index b9e6cf6..0000000 --- a/SOURCES/kvm-scsi-add-persistent-reservation-manager-using-qemu-p.patch +++ /dev/null @@ -1,346 +0,0 @@ -From 65c8aa05dcaaad802c92a55c9352305c3de39de0 Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Sat, 2 Dec 2017 12:19:51 +0100 -Subject: [PATCH 25/36] scsi: add persistent reservation manager using - qemu-pr-helper - -RH-Author: Paolo Bonzini -Message-id: <20171202121953.13317-16-pbonzini@redhat.com> -Patchwork-id: 78084 -O-Subject: [RHEL7.4 qemu-kvm-rhev PATCH 15/17] scsi: add persistent reservation manager using qemu-pr-helper -Bugzilla: 1464908 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: John Snow - -This adds a concrete subclass of pr-manager that talks to qemu-pr-helper. - -Signed-off-by: Paolo Bonzini -(cherry picked from commit 9bad2a6b9d0aeb2dcf91a07652cc63bbb6e73141) -Signed-off-by: Miroslav Rezanina ---- - scsi/Makefile.objs | 2 +- - scsi/pr-manager-helper.c | 302 +++++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 303 insertions(+), 1 deletion(-) - create mode 100644 scsi/pr-manager-helper.c - -diff --git a/scsi/Makefile.objs b/scsi/Makefile.objs -index 5496d2a..4d25e47 100644 ---- a/scsi/Makefile.objs -+++ b/scsi/Makefile.objs -@@ -1,3 +1,3 @@ - block-obj-y += utils.o - --block-obj-$(CONFIG_LINUX) += pr-manager.o -+block-obj-$(CONFIG_LINUX) += pr-manager.o pr-manager-helper.o -diff --git a/scsi/pr-manager-helper.c b/scsi/pr-manager-helper.c -new file mode 100644 -index 0000000..82ff6b6 ---- /dev/null -+++ b/scsi/pr-manager-helper.c -@@ -0,0 +1,302 @@ -+/* -+ * Persistent reservation manager that talks to qemu-pr-helper -+ * -+ * Copyright (c) 2017 Red Hat, Inc. -+ * -+ * Author: Paolo Bonzini -+ * -+ * This code is licensed under the LGPL v2.1 or later. -+ * -+ */ -+ -+#include "qemu/osdep.h" -+#include "qapi/error.h" -+#include "scsi/constants.h" -+#include "scsi/pr-manager.h" -+#include "scsi/utils.h" -+#include "io/channel.h" -+#include "io/channel-socket.h" -+#include "pr-helper.h" -+ -+#include -+ -+#define PR_MAX_RECONNECT_ATTEMPTS 5 -+ -+#define TYPE_PR_MANAGER_HELPER "pr-manager-helper" -+ -+#define PR_MANAGER_HELPER(obj) \ -+ OBJECT_CHECK(PRManagerHelper, (obj), \ -+ TYPE_PR_MANAGER_HELPER) -+ -+typedef struct PRManagerHelper { -+ /* */ -+ PRManager parent; -+ -+ char *path; -+ -+ QemuMutex lock; -+ QIOChannel *ioc; -+} PRManagerHelper; -+ -+/* Called with lock held. */ -+static int pr_manager_helper_read(PRManagerHelper *pr_mgr, -+ void *buf, int sz, Error **errp) -+{ -+ ssize_t r = qio_channel_read_all(pr_mgr->ioc, buf, sz, errp); -+ -+ if (r < 0) { -+ object_unref(OBJECT(pr_mgr->ioc)); -+ pr_mgr->ioc = NULL; -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+/* Called with lock held. */ -+static int pr_manager_helper_write(PRManagerHelper *pr_mgr, -+ int fd, -+ const void *buf, int sz, Error **errp) -+{ -+ size_t nfds = (fd != -1); -+ while (sz > 0) { -+ struct iovec iov; -+ ssize_t n_written; -+ -+ iov.iov_base = (void *)buf; -+ iov.iov_len = sz; -+ n_written = qio_channel_writev_full(QIO_CHANNEL(pr_mgr->ioc), &iov, 1, -+ nfds ? &fd : NULL, nfds, errp); -+ -+ if (n_written <= 0) { -+ assert(n_written != QIO_CHANNEL_ERR_BLOCK); -+ object_unref(OBJECT(pr_mgr->ioc)); -+ return n_written < 0 ? -EINVAL : 0; -+ } -+ -+ nfds = 0; -+ buf += n_written; -+ sz -= n_written; -+ } -+ -+ return 0; -+} -+ -+/* Called with lock held. */ -+static int pr_manager_helper_initialize(PRManagerHelper *pr_mgr, -+ Error **errp) -+{ -+ char *path = g_strdup(pr_mgr->path); -+ SocketAddress saddr = { -+ .type = SOCKET_ADDRESS_TYPE_UNIX, -+ .u.q_unix.path = path -+ }; -+ QIOChannelSocket *sioc = qio_channel_socket_new(); -+ Error *local_err = NULL; -+ -+ uint32_t flags; -+ int r; -+ -+ assert(!pr_mgr->ioc); -+ qio_channel_set_name(QIO_CHANNEL(sioc), "pr-manager-helper"); -+ qio_channel_socket_connect_sync(sioc, -+ &saddr, -+ &local_err); -+ g_free(path); -+ if (local_err) { -+ object_unref(OBJECT(sioc)); -+ error_propagate(errp, local_err); -+ return -ENOTCONN; -+ } -+ -+ qio_channel_set_delay(QIO_CHANNEL(sioc), false); -+ pr_mgr->ioc = QIO_CHANNEL(sioc); -+ -+ /* A simple feature negotation protocol, even though there is -+ * no optional feature right now. -+ */ -+ r = pr_manager_helper_read(pr_mgr, &flags, sizeof(flags), errp); -+ if (r < 0) { -+ goto out_close; -+ } -+ -+ flags = 0; -+ r = pr_manager_helper_write(pr_mgr, -1, &flags, sizeof(flags), errp); -+ if (r < 0) { -+ goto out_close; -+ } -+ -+ return 0; -+ -+out_close: -+ object_unref(OBJECT(pr_mgr->ioc)); -+ pr_mgr->ioc = NULL; -+ return r; -+} -+ -+static int pr_manager_helper_run(PRManager *p, -+ int fd, struct sg_io_hdr *io_hdr) -+{ -+ PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(p); -+ -+ uint32_t len; -+ PRHelperResponse resp; -+ int ret; -+ int expected_dir; -+ int attempts; -+ uint8_t cdb[PR_HELPER_CDB_SIZE] = { 0 }; -+ -+ if (!io_hdr->cmd_len || io_hdr->cmd_len > PR_HELPER_CDB_SIZE) { -+ return -EINVAL; -+ } -+ -+ memcpy(cdb, io_hdr->cmdp, io_hdr->cmd_len); -+ assert(cdb[0] == PERSISTENT_RESERVE_OUT || cdb[0] == PERSISTENT_RESERVE_IN); -+ expected_dir = -+ (cdb[0] == PERSISTENT_RESERVE_OUT ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV); -+ if (io_hdr->dxfer_direction != expected_dir) { -+ return -EINVAL; -+ } -+ -+ len = scsi_cdb_xfer(cdb); -+ if (io_hdr->dxfer_len < len || len > PR_HELPER_DATA_SIZE) { -+ return -EINVAL; -+ } -+ -+ qemu_mutex_lock(&pr_mgr->lock); -+ -+ /* Try to reconnect while sending the CDB. */ -+ for (attempts = 0; attempts < PR_MAX_RECONNECT_ATTEMPTS; attempts++) { -+ if (!pr_mgr->ioc) { -+ ret = pr_manager_helper_initialize(pr_mgr, NULL); -+ if (ret < 0) { -+ qemu_mutex_unlock(&pr_mgr->lock); -+ g_usleep(G_USEC_PER_SEC); -+ qemu_mutex_lock(&pr_mgr->lock); -+ continue; -+ } -+ } -+ -+ ret = pr_manager_helper_write(pr_mgr, fd, cdb, ARRAY_SIZE(cdb), NULL); -+ if (ret >= 0) { -+ break; -+ } -+ } -+ if (ret < 0) { -+ goto out; -+ } -+ -+ /* After sending the CDB, any communications failure causes the -+ * command to fail. The failure is transient, retrying the command -+ * will invoke pr_manager_helper_initialize again. -+ */ -+ if (expected_dir == SG_DXFER_TO_DEV) { -+ io_hdr->resid = io_hdr->dxfer_len - len; -+ ret = pr_manager_helper_write(pr_mgr, -1, io_hdr->dxferp, len, NULL); -+ if (ret < 0) { -+ goto out; -+ } -+ } -+ ret = pr_manager_helper_read(pr_mgr, &resp, sizeof(resp), NULL); -+ if (ret < 0) { -+ goto out; -+ } -+ -+ resp.result = be32_to_cpu(resp.result); -+ resp.sz = be32_to_cpu(resp.sz); -+ if (io_hdr->dxfer_direction == SG_DXFER_FROM_DEV) { -+ assert(resp.sz <= io_hdr->dxfer_len); -+ ret = pr_manager_helper_read(pr_mgr, io_hdr->dxferp, resp.sz, NULL); -+ if (ret < 0) { -+ goto out; -+ } -+ io_hdr->resid = io_hdr->dxfer_len - resp.sz; -+ } else { -+ assert(resp.sz == 0); -+ } -+ -+ io_hdr->status = resp.result; -+ if (resp.result == CHECK_CONDITION) { -+ io_hdr->driver_status = SG_ERR_DRIVER_SENSE; -+ io_hdr->sb_len_wr = MIN(io_hdr->mx_sb_len, PR_HELPER_SENSE_SIZE); -+ memcpy(io_hdr->sbp, resp.sense, io_hdr->sb_len_wr); -+ } -+ -+out: -+ if (ret < 0) { -+ int sense_len = scsi_build_sense(io_hdr->sbp, -+ SENSE_CODE(LUN_COMM_FAILURE)); -+ io_hdr->driver_status = SG_ERR_DRIVER_SENSE; -+ io_hdr->sb_len_wr = MIN(io_hdr->mx_sb_len, sense_len); -+ io_hdr->status = CHECK_CONDITION; -+ } -+ qemu_mutex_unlock(&pr_mgr->lock); -+ return ret; -+} -+ -+static void pr_manager_helper_complete(UserCreatable *uc, Error **errp) -+{ -+ PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(uc); -+ -+ qemu_mutex_lock(&pr_mgr->lock); -+ pr_manager_helper_initialize(pr_mgr, errp); -+ qemu_mutex_unlock(&pr_mgr->lock); -+} -+ -+static char *get_path(Object *obj, Error **errp) -+{ -+ PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(obj); -+ -+ return g_strdup(pr_mgr->path); -+} -+ -+static void set_path(Object *obj, const char *str, Error **errp) -+{ -+ PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(obj); -+ -+ g_free(pr_mgr->path); -+ pr_mgr->path = g_strdup(str); -+} -+ -+static void pr_manager_helper_instance_finalize(Object *obj) -+{ -+ PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(obj); -+ -+ object_unref(OBJECT(pr_mgr->ioc)); -+ qemu_mutex_destroy(&pr_mgr->lock); -+} -+ -+static void pr_manager_helper_instance_init(Object *obj) -+{ -+ PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(obj); -+ -+ qemu_mutex_init(&pr_mgr->lock); -+} -+ -+static void pr_manager_helper_class_init(ObjectClass *klass, -+ void *class_data G_GNUC_UNUSED) -+{ -+ PRManagerClass *prmgr_klass = PR_MANAGER_CLASS(klass); -+ UserCreatableClass *uc_klass = USER_CREATABLE_CLASS(klass); -+ -+ object_class_property_add_str(klass, "path", get_path, set_path, -+ &error_abort); -+ uc_klass->complete = pr_manager_helper_complete; -+ prmgr_klass->run = pr_manager_helper_run; -+} -+ -+static const TypeInfo pr_manager_helper_info = { -+ .parent = TYPE_PR_MANAGER, -+ .name = TYPE_PR_MANAGER_HELPER, -+ .instance_size = sizeof(PRManagerHelper), -+ .instance_init = pr_manager_helper_instance_init, -+ .instance_finalize = pr_manager_helper_instance_finalize, -+ .class_init = pr_manager_helper_class_init, -+}; -+ -+static void pr_manager_helper_register_types(void) -+{ -+ type_register_static(&pr_manager_helper_info); -+} -+ -+type_init(pr_manager_helper_register_types); --- -1.8.3.1 - diff --git a/SOURCES/kvm-scsi-block-Add-share-rw-option.patch b/SOURCES/kvm-scsi-block-Add-share-rw-option.patch deleted file mode 100644 index 0be10b5..0000000 --- a/SOURCES/kvm-scsi-block-Add-share-rw-option.patch +++ /dev/null @@ -1,44 +0,0 @@ -From cd8403ec12e9ee21ebe61894e3a57e806c190956 Mon Sep 17 00:00:00 2001 -From: Fam Zheng -Date: Wed, 17 Jan 2018 06:08:33 +0100 -Subject: [PATCH 03/21] scsi-block: Add share-rw option - -RH-Author: Fam Zheng -Message-id: <20180117060834.17481-2-famz@redhat.com> -Patchwork-id: 78653 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 1/2] scsi-block: Add share-rw option -Bugzilla: 1518482 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: John Snow -RH-Acked-by: Jeffrey Cody - -Scsi-block doesn't use the DEFINE_BLOCK_PROPERTIES() macro so it didn't -gain the share-rw back when it was added to all other storage devices. -This option is meaningful here, and need to be used when attaching a -shared storage to guest. - -Signed-off-by: Fam Zheng -Message-Id: <20171205071928.30242-1-famz@redhat.com> -Signed-off-by: Paolo Bonzini -(cherry picked from commit 07488549f884a658689370b9ef878dc50eced83e) -Signed-off-by: Fam Zheng -Signed-off-by: Miroslav Rezanina ---- - hw/scsi/scsi-disk.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c -index 8a63377..c676355 100644 ---- a/hw/scsi/scsi-disk.c -+++ b/hw/scsi/scsi-disk.c -@@ -2992,6 +2992,7 @@ static const TypeInfo scsi_cd_info = { - #ifdef __linux__ - static Property scsi_block_properties[] = { - DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.conf.blk), -+ DEFINE_PROP_BOOL("share-rw", SCSIDiskState, qdev.conf.share_rw, false), - DEFINE_PROP_UINT16("rotation_rate", SCSIDiskState, rotation_rate, 0), - DEFINE_PROP_END_OF_LIST(), - }; --- -1.8.3.1 - diff --git a/SOURCES/kvm-scsi-build-qemu-pr-helper.patch b/SOURCES/kvm-scsi-build-qemu-pr-helper.patch deleted file mode 100644 index f175fe5..0000000 --- a/SOURCES/kvm-scsi-build-qemu-pr-helper.patch +++ /dev/null @@ -1,1024 +0,0 @@ -From c3ce9144a1f76102f51bef7909eac5b2ba4bd777 Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Sat, 2 Dec 2017 12:19:49 +0100 -Subject: [PATCH 23/36] scsi: build qemu-pr-helper - -RH-Author: Paolo Bonzini -Message-id: <20171202121953.13317-14-pbonzini@redhat.com> -Patchwork-id: 78089 -O-Subject: [RHEL7.4 qemu-kvm-rhev PATCH 13/17] scsi: build qemu-pr-helper -Bugzilla: 1464908 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: John Snow - -Introduce a privileged helper to run persistent reservation commands. -This lets virtual machines send persistent reservations without using -CAP_SYS_RAWIO or out-of-tree patches. The helper uses Unix permissions -and SCM_RIGHTS to restrict access to processes that can access its socket -and prove that they have an open file descriptor for a raw SCSI device. - -The next patch will also correct the usage of persistent reservations -with multipath devices. - -It would also be possible to support for Linux's IOC_PR_* ioctls in -the future, to support NVMe devices. For now, however, only SCSI is -supported. - -Signed-off-by: Paolo Bonzini -(cherry picked from commit b855f8d175a0a26c9798cbc5962bb8c0d9538231) -Signed-off-by: Miroslav Rezanina ---- - Makefile | 4 +- - configure | 14 +- - docs/interop/pr-helper.rst | 83 +++++ - docs/pr-manager.rst | 33 ++ - scsi/pr-helper.h | 41 +++ - scsi/qemu-pr-helper.c | 735 +++++++++++++++++++++++++++++++++++++++++++++ - 6 files changed, 905 insertions(+), 5 deletions(-) - create mode 100644 docs/interop/pr-helper.rst - create mode 100644 scsi/pr-helper.h - create mode 100644 scsi/qemu-pr-helper.c - -diff --git a/Makefile b/Makefile -index 1a773a8..3e76953 100644 ---- a/Makefile -+++ b/Makefile -@@ -386,6 +386,8 @@ qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o $(COMMON_LDADDS) - fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/9p-marshal.o fsdev/9p-iov-marshal.o $(COMMON_LDADDS) - fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap - -+scsi/qemu-pr-helper$(EXESUF): scsi/qemu-pr-helper.o scsi/utils.o $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS) -+ - qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool - $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$@") - -@@ -493,7 +495,7 @@ clean: - rm -f *.msi - find . \( -name '*.so' -o -name '*.dll' -o -name '*.mo' -o -name '*.[oda]' \) -type f -exec rm {} + - rm -f $(filter-out %.tlb,$(TOOLS)) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~ -- rm -f fsdev/*.pod -+ rm -f fsdev/*.pod scsi/*.pod - rm -f qemu-img-cmds.h - rm -f ui/shader/*-vert.h ui/shader/*-frag.h - @# May not be present in GENERATED_FILES -diff --git a/configure b/configure -index 644e52d..2df1b42 100755 ---- a/configure -+++ b/configure -@@ -5065,16 +5065,22 @@ if test "$want_tools" = "yes" ; then - fi - fi - if test "$softmmu" = yes ; then -- if test "$virtfs" != no ; then -- if test "$cap" = yes && test "$linux" = yes && test "$attr" = yes ; then -+ if test "$linux" = yes; then -+ if test "$virtfs" != no && test "$cap" = yes && test "$attr" = yes ; then - virtfs=yes - tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)" - else - if test "$virtfs" = yes; then -- error_exit "VirtFS is supported only on Linux and requires libcap devel and libattr devel" -+ error_exit "VirtFS requires libcap devel and libattr devel" - fi - virtfs=no - fi -+ tools="$tools scsi/qemu-pr-helper\$(EXESUF)" -+ else -+ if test "$virtfs" = yes; then -+ error_exit "VirtFS is supported only on Linux" -+ fi -+ virtfs=no - fi - fi - -@@ -6562,7 +6568,7 @@ fi - - # build tree in object directory in case the source is not in the current directory - DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos tests/qapi-schema tests/tcg/xtensa tests/qemu-iotests" --DIRS="$DIRS docs docs/interop fsdev" -+DIRS="$DIRS docs docs/interop fsdev scsi" - DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas pc-bios/s390-ccw" - DIRS="$DIRS roms/seabios roms/vgabios" - DIRS="$DIRS qapi-generated" -diff --git a/docs/interop/pr-helper.rst b/docs/interop/pr-helper.rst -new file mode 100644 -index 0000000..9f76d5b ---- /dev/null -+++ b/docs/interop/pr-helper.rst -@@ -0,0 +1,83 @@ -+.. -+ -+====================================== -+Persistent reservation helper protocol -+====================================== -+ -+QEMU's SCSI passthrough devices, ``scsi-block`` and ``scsi-generic``, -+can delegate implementation of persistent reservations to an external -+(and typically privileged) program. Persistent Reservations allow -+restricting access to block devices to specific initiators in a shared -+storage setup. -+ -+For a more detailed reference please refer the the SCSI Primary -+Commands standard, specifically the section on Reservations and the -+"PERSISTENT RESERVE IN" and "PERSISTENT RESERVE OUT" commands. -+ -+This document describes the socket protocol used between QEMU's -+``pr-manager-helper`` object and the external program. -+ -+.. contents:: -+ -+Connection and initialization -+----------------------------- -+ -+All data transmitted on the socket is big-endian. -+ -+After connecting to the helper program's socket, the helper starts a simple -+feature negotiation process by writing four bytes corresponding to -+the features it exposes (``supported_features``). QEMU reads it, -+then writes four bytes corresponding to the desired features of the -+helper program (``requested_features``). -+ -+If a bit is 1 in ``requested_features`` and 0 in ``supported_features``, -+the corresponding feature is not supported by the helper and the connection -+is closed. On the other hand, it is acceptable for a bit to be 0 in -+``requested_features`` and 1 in ``supported_features``; in this case, -+the helper will not enable the feature. -+ -+Right now no feature is defined, so the two parties always write four -+zero bytes. -+ -+Command format -+-------------- -+ -+It is invalid to send multiple commands concurrently on the same -+socket. It is however possible to connect multiple sockets to the -+helper and send multiple commands to the helper for one or more -+file descriptors. -+ -+A command consists of a request and a response. A request consists -+of a 16-byte SCSI CDB. A file descriptor must be passed to the helper -+together with the SCSI CDB using ancillary data. -+ -+The CDB has the following limitations: -+ -+- the command (stored in the first byte) must be one of 0x5E -+ (PERSISTENT RESERVE IN) or 0x5F (PERSISTENT RESERVE OUT). -+ -+- the allocation length (stored in bytes 7-8 of the CDB for PERSISTENT -+ RESERVE IN) or parameter list length (stored in bytes 5-8 of the CDB -+ for PERSISTENT RESERVE OUT) is limited to 8 KiB. -+ -+For PERSISTENT RESERVE OUT, the parameter list is sent right after the -+CDB. The length of the parameter list is taken from the CDB itself. -+ -+The helper's reply has the following structure: -+ -+- 4 bytes for the SCSI status -+ -+- 4 bytes for the payload size (nonzero only for PERSISTENT RESERVE IN -+ and only if the SCSI status is 0x00, i.e. GOOD) -+ -+- 96 bytes for the SCSI sense data -+ -+- if the size is nonzero, the payload follows -+ -+The sense data is always sent to keep the protocol simple, even though -+it is only valid if the SCSI status is CHECK CONDITION (0x02). -+ -+The payload size is always less than or equal to the allocation length -+specified in the CDB for the PERSISTENT RESERVE IN command. -+ -+If the protocol is violated, the helper closes the socket. -diff --git a/docs/pr-manager.rst b/docs/pr-manager.rst -index b6089fb..7107e59 100644 ---- a/docs/pr-manager.rst -+++ b/docs/pr-manager.rst -@@ -49,3 +49,36 @@ Alternatively, using ``-blockdev``:: - -object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock - -blockdev node-name=hd,driver=raw,file.driver=host_device,file.filename=/dev/sdb,file.pr-manager=helper0 - -device scsi-block,drive=hd -+ -+---------------------------------- -+Invoking :program:`qemu-pr-helper` -+---------------------------------- -+ -+QEMU provides an implementation of the persistent reservation helper, -+called :program:`qemu-pr-helper`. The helper should be started as a -+system service and supports the following option: -+ -+-d, --daemon run in the background -+-q, --quiet decrease verbosity -+-f, --pidfile=path PID file when running as a daemon -+-k, --socket=path path to the socket -+-T, --trace=trace-opts tracing options -+ -+By default, the socket and PID file are placed in the runtime state -+directory, for example :file:`/var/run/qemu-pr-helper.sock` and -+:file:`/var/run/qemu-pr-helper.pid`. The PID file is not created -+unless :option:`-d` is passed too. -+ -+:program:`qemu-pr-helper` can also use the systemd socket activation -+protocol. In this case, the systemd socket unit should specify a -+Unix stream socket, like this:: -+ -+ [Socket] -+ ListenStream=/var/run/qemu-pr-helper.sock -+ -+After connecting to the socket, :program:`qemu-pr-helper`` can optionally drop -+root privileges, except for those capabilities that are needed for -+its operation. To do this, add the following options: -+ -+-u, --user=user user to drop privileges to -+-g, --group=group group to drop privileges to -diff --git a/scsi/pr-helper.h b/scsi/pr-helper.h -new file mode 100644 -index 0000000..96c50a9 ---- /dev/null -+++ b/scsi/pr-helper.h -@@ -0,0 +1,41 @@ -+/* Definitions for QEMU's persistent reservation helper daemon -+ * -+ * Copyright (C) 2017 Red Hat, Inc. -+ * -+ * Author: -+ * Paolo Bonzini -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to -+ * deal in the Software without restriction, including without limitation the -+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -+ * sell copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -+ * IN THE SOFTWARE. -+ */ -+#ifndef QEMU_PR_HELPER_H -+#define QEMU_PR_HELPER_H 1 -+ -+#include -+ -+#define PR_HELPER_CDB_SIZE 16 -+#define PR_HELPER_SENSE_SIZE 96 -+#define PR_HELPER_DATA_SIZE 8192 -+ -+typedef struct PRHelperResponse { -+ int32_t result; -+ int32_t sz; -+ uint8_t sense[PR_HELPER_SENSE_SIZE]; -+} PRHelperResponse; -+ -+#endif -diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c -new file mode 100644 -index 0000000..f46266f ---- /dev/null -+++ b/scsi/qemu-pr-helper.c -@@ -0,0 +1,735 @@ -+/* -+ * Privileged helper to handle persistent reservation commands for QEMU -+ * -+ * Copyright (C) 2017 Red Hat, Inc. -+ * -+ * Author: Paolo Bonzini -+ * -+ * 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; under version 2 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 . -+ */ -+ -+#include "qemu/osdep.h" -+#include -+#include -+#include -+#include -+ -+#ifdef CONFIG_LIBCAP -+#include -+#endif -+#include -+#include -+ -+#include "qapi/error.h" -+#include "qemu-common.h" -+#include "qemu/cutils.h" -+#include "qemu/main-loop.h" -+#include "qemu/error-report.h" -+#include "qemu/config-file.h" -+#include "qemu/bswap.h" -+#include "qemu/log.h" -+#include "qemu/systemd.h" -+#include "qapi/util.h" -+#include "qapi/qmp/qstring.h" -+#include "io/channel-socket.h" -+#include "trace/control.h" -+#include "qemu-version.h" -+ -+#include "block/aio.h" -+#include "block/thread-pool.h" -+ -+#include "scsi/constants.h" -+#include "scsi/utils.h" -+#include "pr-helper.h" -+ -+#define PR_OUT_FIXED_PARAM_SIZE 24 -+ -+static char *socket_path; -+static char *pidfile; -+static enum { RUNNING, TERMINATE, TERMINATING } state; -+static QIOChannelSocket *server_ioc; -+static int server_watch; -+static int num_active_sockets = 1; -+static int verbose; -+ -+#ifdef CONFIG_LIBCAP -+static int uid = -1; -+static int gid = -1; -+#endif -+ -+static void usage(const char *name) -+{ -+ (printf) ( -+"Usage: %s [OPTIONS] FILE\n" -+"Persistent Reservation helper program for QEMU\n" -+"\n" -+" -h, --help display this help and exit\n" -+" -V, --version output version information and exit\n" -+"\n" -+" -d, --daemon run in the background\n" -+" -f, --pidfile=PATH PID file when running as a daemon\n" -+" (default '%s')\n" -+" -k, --socket=PATH path to the unix socket\n" -+" (default '%s')\n" -+" -T, --trace [[enable=]][,events=][,file=]\n" -+" specify tracing options\n" -+#ifdef CONFIG_LIBCAP -+" -u, --user=USER user to drop privileges to\n" -+" -g, --group=GROUP group to drop privileges to\n" -+#endif -+"\n" -+QEMU_HELP_BOTTOM "\n" -+ , name, pidfile, socket_path); -+} -+ -+static void version(const char *name) -+{ -+ printf( -+"%s " QEMU_VERSION QEMU_PKGVERSION "\n" -+"Written by Paolo Bonzini.\n" -+"\n" -+QEMU_COPYRIGHT "\n" -+"This is free software; see the source for copying conditions. There is NO\n" -+"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" -+ , name); -+} -+ -+static void write_pidfile(void) -+{ -+ int pidfd; -+ char pidstr[32]; -+ -+ pidfd = qemu_open(pidfile, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR); -+ if (pidfd == -1) { -+ error_report("Cannot open pid file, %s", strerror(errno)); -+ exit(EXIT_FAILURE); -+ } -+ -+ if (lockf(pidfd, F_TLOCK, 0)) { -+ error_report("Cannot lock pid file, %s", strerror(errno)); -+ goto fail; -+ } -+ if (ftruncate(pidfd, 0)) { -+ error_report("Failed to truncate pid file"); -+ goto fail; -+ } -+ -+ snprintf(pidstr, sizeof(pidstr), "%d\n", getpid()); -+ if (write(pidfd, pidstr, strlen(pidstr)) != strlen(pidstr)) { -+ error_report("Failed to write pid file"); -+ goto fail; -+ } -+ return; -+ -+fail: -+ unlink(pidfile); -+ close(pidfd); -+ exit(EXIT_FAILURE); -+} -+ -+/* SG_IO support */ -+ -+typedef struct PRHelperSGIOData { -+ int fd; -+ const uint8_t *cdb; -+ uint8_t *sense; -+ uint8_t *buf; -+ int sz; /* input/output */ -+ int dir; -+} PRHelperSGIOData; -+ -+static int do_sgio_worker(void *opaque) -+{ -+ PRHelperSGIOData *data = opaque; -+ struct sg_io_hdr io_hdr; -+ int ret; -+ int status; -+ SCSISense sense_code; -+ -+ memset(data->sense, 0, PR_HELPER_SENSE_SIZE); -+ memset(&io_hdr, 0, sizeof(io_hdr)); -+ io_hdr.interface_id = 'S'; -+ io_hdr.cmd_len = PR_HELPER_CDB_SIZE; -+ io_hdr.cmdp = (uint8_t *)data->cdb; -+ io_hdr.sbp = data->sense; -+ io_hdr.mx_sb_len = PR_HELPER_SENSE_SIZE; -+ io_hdr.timeout = 1; -+ io_hdr.dxfer_direction = data->dir; -+ io_hdr.dxferp = (char *)data->buf; -+ io_hdr.dxfer_len = data->sz; -+ ret = ioctl(data->fd, SG_IO, &io_hdr); -+ status = sg_io_sense_from_errno(ret < 0 ? errno : 0, &io_hdr, -+ &sense_code); -+ if (status == GOOD) { -+ data->sz -= io_hdr.resid; -+ } else { -+ data->sz = 0; -+ } -+ -+ if (status == CHECK_CONDITION && -+ !(io_hdr.driver_status & SG_ERR_DRIVER_SENSE)) { -+ scsi_build_sense(data->sense, sense_code); -+ } -+ -+ return status; -+} -+ -+static int do_sgio(int fd, const uint8_t *cdb, uint8_t *sense, -+ uint8_t *buf, int *sz, int dir) -+{ -+ ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context()); -+ int r; -+ -+ PRHelperSGIOData data = { -+ .fd = fd, -+ .cdb = cdb, -+ .sense = sense, -+ .buf = buf, -+ .sz = *sz, -+ .dir = dir, -+ }; -+ -+ r = thread_pool_submit_co(pool, do_sgio_worker, &data); -+ *sz = data.sz; -+ return r; -+} -+ -+static int do_pr_in(int fd, const uint8_t *cdb, uint8_t *sense, -+ uint8_t *data, int *resp_sz) -+{ -+ return do_sgio(fd, cdb, sense, data, resp_sz, -+ SG_DXFER_FROM_DEV); -+} -+ -+static int do_pr_out(int fd, const uint8_t *cdb, uint8_t *sense, -+ const uint8_t *param, int sz) -+{ -+ int resp_sz = sz; -+ return do_sgio(fd, cdb, sense, (uint8_t *)param, &resp_sz, -+ SG_DXFER_TO_DEV); -+} -+ -+/* Client */ -+ -+typedef struct PRHelperClient { -+ QIOChannelSocket *ioc; -+ Coroutine *co; -+ int fd; -+ uint8_t data[PR_HELPER_DATA_SIZE]; -+} PRHelperClient; -+ -+typedef struct PRHelperRequest { -+ int fd; -+ size_t sz; -+ uint8_t cdb[PR_HELPER_CDB_SIZE]; -+} PRHelperRequest; -+ -+static int coroutine_fn prh_read(PRHelperClient *client, void *buf, int sz, -+ Error **errp) -+{ -+ int ret = 0; -+ -+ while (sz > 0) { -+ int *fds = NULL; -+ size_t nfds = 0; -+ int i; -+ struct iovec iov; -+ ssize_t n_read; -+ -+ iov.iov_base = buf; -+ iov.iov_len = sz; -+ n_read = qio_channel_readv_full(QIO_CHANNEL(client->ioc), &iov, 1, -+ &fds, &nfds, errp); -+ -+ if (n_read == QIO_CHANNEL_ERR_BLOCK) { -+ qio_channel_yield(QIO_CHANNEL(client->ioc), G_IO_IN); -+ continue; -+ } -+ if (n_read <= 0) { -+ ret = n_read ? n_read : -1; -+ goto err; -+ } -+ -+ /* Stash one file descriptor per request. */ -+ if (nfds) { -+ bool too_many = false; -+ for (i = 0; i < nfds; i++) { -+ if (client->fd == -1) { -+ client->fd = fds[i]; -+ } else { -+ close(fds[i]); -+ too_many = true; -+ } -+ } -+ g_free(fds); -+ if (too_many) { -+ ret = -1; -+ goto err; -+ } -+ } -+ -+ buf += n_read; -+ sz -= n_read; -+ } -+ -+ return 0; -+ -+err: -+ if (client->fd != -1) { -+ close(client->fd); -+ client->fd = -1; -+ } -+ return ret; -+} -+ -+static int coroutine_fn prh_read_request(PRHelperClient *client, -+ PRHelperRequest *req, -+ PRHelperResponse *resp, Error **errp) -+{ -+ uint32_t sz; -+ -+ if (prh_read(client, req->cdb, sizeof(req->cdb), NULL) < 0) { -+ return -1; -+ } -+ -+ if (client->fd == -1) { -+ error_setg(errp, "No file descriptor in request."); -+ return -1; -+ } -+ -+ if (req->cdb[0] != PERSISTENT_RESERVE_OUT && -+ req->cdb[0] != PERSISTENT_RESERVE_IN) { -+ error_setg(errp, "Invalid CDB, closing socket."); -+ goto out_close; -+ } -+ -+ sz = scsi_cdb_xfer(req->cdb); -+ if (sz > sizeof(client->data)) { -+ goto out_close; -+ } -+ -+ if (req->cdb[0] == PERSISTENT_RESERVE_OUT) { -+ if (qio_channel_read_all(QIO_CHANNEL(client->ioc), -+ (char *)client->data, sz, -+ errp) < 0) { -+ goto out_close; -+ } -+ if ((fcntl(client->fd, F_GETFL) & O_ACCMODE) == O_RDONLY) { -+ scsi_build_sense(resp->sense, SENSE_CODE(INVALID_OPCODE)); -+ sz = 0; -+ } else if (sz < PR_OUT_FIXED_PARAM_SIZE) { -+ /* Illegal request, Parameter list length error. This isn't fatal; -+ * we have read the data, send an error without closing the socket. -+ */ -+ scsi_build_sense(resp->sense, SENSE_CODE(INVALID_PARAM_LEN)); -+ sz = 0; -+ } -+ if (sz == 0) { -+ resp->result = CHECK_CONDITION; -+ close(client->fd); -+ client->fd = -1; -+ } -+ } -+ -+ req->fd = client->fd; -+ req->sz = sz; -+ client->fd = -1; -+ return sz; -+ -+out_close: -+ close(client->fd); -+ client->fd = -1; -+ return -1; -+} -+ -+static int coroutine_fn prh_write_response(PRHelperClient *client, -+ PRHelperRequest *req, -+ PRHelperResponse *resp, Error **errp) -+{ -+ ssize_t r; -+ size_t sz; -+ -+ if (req->cdb[0] == PERSISTENT_RESERVE_IN && resp->result == GOOD) { -+ assert(resp->sz <= req->sz && resp->sz <= sizeof(client->data)); -+ } else { -+ assert(resp->sz == 0); -+ } -+ -+ sz = resp->sz; -+ -+ resp->result = cpu_to_be32(resp->result); -+ resp->sz = cpu_to_be32(resp->sz); -+ r = qio_channel_write_all(QIO_CHANNEL(client->ioc), -+ (char *) resp, sizeof(*resp), errp); -+ if (r < 0) { -+ return r; -+ } -+ -+ r = qio_channel_write_all(QIO_CHANNEL(client->ioc), -+ (char *) client->data, -+ sz, errp); -+ return r < 0 ? r : 0; -+} -+ -+static void coroutine_fn prh_co_entry(void *opaque) -+{ -+ PRHelperClient *client = opaque; -+ Error *local_err = NULL; -+ uint32_t flags; -+ int r; -+ -+ qio_channel_set_blocking(QIO_CHANNEL(client->ioc), -+ false, NULL); -+ qio_channel_attach_aio_context(QIO_CHANNEL(client->ioc), -+ qemu_get_aio_context()); -+ -+ /* A very simple negotiation for future extensibility. No features -+ * are defined so write 0. -+ */ -+ flags = cpu_to_be32(0); -+ r = qio_channel_write_all(QIO_CHANNEL(client->ioc), -+ (char *) &flags, sizeof(flags), NULL); -+ if (r < 0) { -+ goto out; -+ } -+ -+ r = qio_channel_read_all(QIO_CHANNEL(client->ioc), -+ (char *) &flags, sizeof(flags), NULL); -+ if (be32_to_cpu(flags) != 0 || r < 0) { -+ goto out; -+ } -+ -+ while (atomic_read(&state) == RUNNING) { -+ PRHelperRequest req; -+ PRHelperResponse resp; -+ int sz; -+ -+ sz = prh_read_request(client, &req, &resp, &local_err); -+ if (sz < 0) { -+ break; -+ } -+ -+ if (sz > 0) { -+ num_active_sockets++; -+ if (req.cdb[0] == PERSISTENT_RESERVE_OUT) { -+ r = do_pr_out(req.fd, req.cdb, resp.sense, -+ client->data, sz); -+ resp.sz = 0; -+ } else { -+ resp.sz = sizeof(client->data); -+ r = do_pr_in(req.fd, req.cdb, resp.sense, -+ client->data, &resp.sz); -+ resp.sz = MIN(resp.sz, sz); -+ } -+ num_active_sockets--; -+ close(req.fd); -+ if (r == -1) { -+ break; -+ } -+ resp.result = r; -+ } -+ -+ if (prh_write_response(client, &req, &resp, &local_err) < 0) { -+ break; -+ } -+ } -+ -+ if (local_err) { -+ if (verbose == 0) { -+ error_free(local_err); -+ } else { -+ error_report_err(local_err); -+ } -+ } -+ -+out: -+ qio_channel_detach_aio_context(QIO_CHANNEL(client->ioc)); -+ object_unref(OBJECT(client->ioc)); -+ g_free(client); -+} -+ -+static gboolean accept_client(QIOChannel *ioc, GIOCondition cond, gpointer opaque) -+{ -+ QIOChannelSocket *cioc; -+ PRHelperClient *prh; -+ -+ cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc), -+ NULL); -+ if (!cioc) { -+ return TRUE; -+ } -+ -+ prh = g_new(PRHelperClient, 1); -+ prh->ioc = cioc; -+ prh->fd = -1; -+ prh->co = qemu_coroutine_create(prh_co_entry, prh); -+ qemu_coroutine_enter(prh->co); -+ -+ return TRUE; -+} -+ -+ -+/* -+ * Check socket parameters compatibility when socket activation is used. -+ */ -+static const char *socket_activation_validate_opts(void) -+{ -+ if (socket_path != NULL) { -+ return "Unix socket can't be set when using socket activation"; -+ } -+ -+ return NULL; -+} -+ -+static void compute_default_paths(void) -+{ -+ if (!socket_path) { -+ socket_path = qemu_get_local_state_pathname("run/qemu-pr-helper.sock"); -+ } -+} -+ -+static void termsig_handler(int signum) -+{ -+ atomic_cmpxchg(&state, RUNNING, TERMINATE); -+ qemu_notify_event(); -+} -+ -+static void close_server_socket(void) -+{ -+ assert(server_ioc); -+ -+ g_source_remove(server_watch); -+ server_watch = -1; -+ object_unref(OBJECT(server_ioc)); -+ num_active_sockets--; -+} -+ -+#ifdef CONFIG_LIBCAP -+static int drop_privileges(void) -+{ -+ /* clear all capabilities */ -+ capng_clear(CAPNG_SELECT_BOTH); -+ -+ if (capng_update(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED, -+ CAP_SYS_RAWIO) < 0) { -+ return -1; -+ } -+ -+ /* Change user/group id, retaining the capabilities. Because file descriptors -+ * are passed via SCM_RIGHTS, we don't need supplementary groups (and in -+ * fact the helper can run as "nobody"). -+ */ -+ if (capng_change_id(uid != -1 ? uid : getuid(), -+ gid != -1 ? gid : getgid(), -+ CAPNG_DROP_SUPP_GRP | CAPNG_CLEAR_BOUNDING)) { -+ return -1; -+ } -+ -+ return 0; -+} -+#endif -+ -+int main(int argc, char **argv) -+{ -+ const char *sopt = "hVk:fdT:u:g:q"; -+ struct option lopt[] = { -+ { "help", no_argument, NULL, 'h' }, -+ { "version", no_argument, NULL, 'V' }, -+ { "socket", required_argument, NULL, 'k' }, -+ { "pidfile", no_argument, NULL, 'f' }, -+ { "daemon", no_argument, NULL, 'd' }, -+ { "trace", required_argument, NULL, 'T' }, -+ { "user", required_argument, NULL, 'u' }, -+ { "group", required_argument, NULL, 'g' }, -+ { "quiet", no_argument, NULL, 'q' }, -+ { NULL, 0, NULL, 0 } -+ }; -+ int opt_ind = 0; -+ int quiet = 0; -+ int ch; -+ Error *local_err = NULL; -+ char *trace_file = NULL; -+ bool daemonize = false; -+ unsigned socket_activation; -+ -+ struct sigaction sa_sigterm; -+ memset(&sa_sigterm, 0, sizeof(sa_sigterm)); -+ sa_sigterm.sa_handler = termsig_handler; -+ sigaction(SIGTERM, &sa_sigterm, NULL); -+ sigaction(SIGINT, &sa_sigterm, NULL); -+ sigaction(SIGHUP, &sa_sigterm, NULL); -+ -+ signal(SIGPIPE, SIG_IGN); -+ -+ module_call_init(MODULE_INIT_TRACE); -+ module_call_init(MODULE_INIT_QOM); -+ qemu_add_opts(&qemu_trace_opts); -+ qemu_init_exec_dir(argv[0]); -+ -+ pidfile = qemu_get_local_state_pathname("run/qemu-pr-helper.pid"); -+ -+ while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) { -+ switch (ch) { -+ case 'k': -+ socket_path = optarg; -+ if (socket_path[0] != '/') { -+ error_report("socket path must be absolute"); -+ exit(EXIT_FAILURE); -+ } -+ break; -+ case 'f': -+ pidfile = optarg; -+ break; -+#ifdef CONFIG_LIBCAP -+ case 'u': { -+ unsigned long res; -+ struct passwd *userinfo = getpwnam(optarg); -+ if (userinfo) { -+ uid = userinfo->pw_uid; -+ } else if (qemu_strtoul(optarg, NULL, 10, &res) == 0 && -+ (uid_t)res == res) { -+ uid = res; -+ } else { -+ error_report("invalid user '%s'", optarg); -+ exit(EXIT_FAILURE); -+ } -+ break; -+ } -+ case 'g': { -+ unsigned long res; -+ struct group *groupinfo = getgrnam(optarg); -+ if (groupinfo) { -+ gid = groupinfo->gr_gid; -+ } else if (qemu_strtoul(optarg, NULL, 10, &res) == 0 && -+ (gid_t)res == res) { -+ gid = res; -+ } else { -+ error_report("invalid group '%s'", optarg); -+ exit(EXIT_FAILURE); -+ } -+ break; -+ } -+#else -+ case 'u': -+ case 'g': -+ error_report("-%c not supported by this %s", ch, argv[0]); -+ exit(1); -+#endif -+ case 'd': -+ daemonize = true; -+ break; -+ case 'q': -+ quiet = 1; -+ break; -+ case 'T': -+ g_free(trace_file); -+ trace_file = trace_opt_parse(optarg); -+ break; -+ case 'V': -+ version(argv[0]); -+ exit(EXIT_SUCCESS); -+ break; -+ case 'h': -+ usage(argv[0]); -+ exit(EXIT_SUCCESS); -+ break; -+ case '?': -+ error_report("Try `%s --help' for more information.", argv[0]); -+ exit(EXIT_FAILURE); -+ } -+ } -+ -+ /* set verbosity */ -+ verbose = !quiet; -+ -+ if (!trace_init_backends()) { -+ exit(EXIT_FAILURE); -+ } -+ trace_init_file(trace_file); -+ qemu_set_log(LOG_TRACE); -+ -+ socket_activation = check_socket_activation(); -+ if (socket_activation == 0) { -+ SocketAddress saddr; -+ compute_default_paths(); -+ saddr = (SocketAddress){ -+ .type = SOCKET_ADDRESS_TYPE_UNIX, -+ .u.q_unix.path = g_strdup(socket_path) -+ }; -+ server_ioc = qio_channel_socket_new(); -+ if (qio_channel_socket_listen_sync(server_ioc, &saddr, &local_err) < 0) { -+ object_unref(OBJECT(server_ioc)); -+ error_report_err(local_err); -+ return 1; -+ } -+ g_free(saddr.u.q_unix.path); -+ } else { -+ /* Using socket activation - check user didn't use -p etc. */ -+ const char *err_msg = socket_activation_validate_opts(); -+ if (err_msg != NULL) { -+ error_report("%s", err_msg); -+ exit(EXIT_FAILURE); -+ } -+ -+ /* Can only listen on a single socket. */ -+ if (socket_activation > 1) { -+ error_report("%s does not support socket activation with LISTEN_FDS > 1", -+ argv[0]); -+ exit(EXIT_FAILURE); -+ } -+ server_ioc = qio_channel_socket_new_fd(FIRST_SOCKET_ACTIVATION_FD, -+ &local_err); -+ if (server_ioc == NULL) { -+ error_report("Failed to use socket activation: %s", -+ error_get_pretty(local_err)); -+ exit(EXIT_FAILURE); -+ } -+ socket_path = NULL; -+ } -+ -+ if (qemu_init_main_loop(&local_err)) { -+ error_report_err(local_err); -+ exit(EXIT_FAILURE); -+ } -+ -+ server_watch = qio_channel_add_watch(QIO_CHANNEL(server_ioc), -+ G_IO_IN, -+ accept_client, -+ NULL, NULL); -+ -+#ifdef CONFIG_LIBCAP -+ if (drop_privileges() < 0) { -+ error_report("Failed to drop privileges: %s", strerror(errno)); -+ exit(EXIT_FAILURE); -+ } -+#endif -+ -+ if (daemonize) { -+ if (daemon(0, 0) < 0) { -+ error_report("Failed to daemonize: %s", strerror(errno)); -+ exit(EXIT_FAILURE); -+ } -+ write_pidfile(); -+ } -+ -+ state = RUNNING; -+ do { -+ main_loop_wait(false); -+ if (state == TERMINATE) { -+ state = TERMINATING; -+ close_server_socket(); -+ } -+ } while (num_active_sockets > 0); -+ -+ exit(EXIT_SUCCESS); -+} --- -1.8.3.1 - diff --git a/SOURCES/kvm-scsi-bus-correct-responses-for-INQUIRY-and-REQUEST-S.patch b/SOURCES/kvm-scsi-bus-correct-responses-for-INQUIRY-and-REQUEST-S.patch deleted file mode 100644 index 2eb1c37..0000000 --- a/SOURCES/kvm-scsi-bus-correct-responses-for-INQUIRY-and-REQUEST-S.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 23f2b51d8b3d7734718eb2f9b109cb9090f1484e Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Sat, 2 Dec 2017 12:19:39 +0100 -Subject: [PATCH 13/36] scsi-bus: correct responses for INQUIRY and REQUEST - SENSE - -RH-Author: Paolo Bonzini -Message-id: <20171202121953.13317-4-pbonzini@redhat.com> -Patchwork-id: 78085 -O-Subject: [RHEL7.4 qemu-kvm-rhev PATCH 03/17] scsi-bus: correct responses for INQUIRY and REQUEST SENSE -Bugzilla: 1464908 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: John Snow - -From: Hannes Reinecke - -According to SPC-3 INQUIRY and REQUEST SENSE should return GOOD -even on unsupported LUNS. - -Signed-off-by: Hannes Reinecke -Message-Id: <1503049022-14749-1-git-send-email-hare@suse.de> -Reported-by: Laszlo Ersek -Fixes: ded6ddc5a7b95217557fa360913d1213e12d4a6d -Cc: qemu-stable@nongnu.org -Signed-off-by: Hannes Reinecke -Signed-off-by: Paolo Bonzini -(cherry picked from commit b07fbce6349c7b84642e7ed56c7a1ac3c1caca61) -Signed-off-by: Miroslav Rezanina ---- - hw/scsi/scsi-bus.c | 29 +++++++++++++++++++++++++---- - 1 file changed, 25 insertions(+), 4 deletions(-) - -diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c -index 404686a..55aa5a7 100644 ---- a/hw/scsi/scsi-bus.c -+++ b/hw/scsi/scsi-bus.c -@@ -524,8 +524,10 @@ static size_t scsi_sense_len(SCSIRequest *req) - static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf) - { - SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req); -+ int fixed_sense = (req->cmd.buf[1] & 1) == 0; - -- if (req->lun != 0) { -+ if (req->lun != 0 && -+ buf[0] != INQUIRY && buf[0] != REQUEST_SENSE) { - scsi_req_build_sense(req, SENSE_CODE(LUN_NOT_SUPPORTED)); - scsi_req_complete(req, CHECK_CONDITION); - return 0; -@@ -543,9 +545,28 @@ static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf) - break; - case REQUEST_SENSE: - scsi_target_alloc_buf(&r->req, scsi_sense_len(req)); -- r->len = scsi_device_get_sense(r->req.dev, r->buf, -- MIN(req->cmd.xfer, r->buf_len), -- (req->cmd.buf[1] & 1) == 0); -+ if (req->lun != 0) { -+ const struct SCSISense sense = SENSE_CODE(LUN_NOT_SUPPORTED); -+ -+ if (fixed_sense) { -+ r->buf[0] = 0x70; -+ r->buf[2] = sense.key; -+ r->buf[10] = 10; -+ r->buf[12] = sense.asc; -+ r->buf[13] = sense.ascq; -+ r->len = MIN(req->cmd.xfer, SCSI_SENSE_LEN); -+ } else { -+ r->buf[0] = 0x72; -+ r->buf[1] = sense.key; -+ r->buf[2] = sense.asc; -+ r->buf[3] = sense.ascq; -+ r->len = 8; -+ } -+ } else { -+ r->len = scsi_device_get_sense(r->req.dev, r->buf, -+ MIN(req->cmd.xfer, r->buf_len), -+ fixed_sense); -+ } - if (r->req.dev->sense_is_ua) { - scsi_device_unit_attention_reported(req->dev); - r->req.dev->sense_len = 0; --- -1.8.3.1 - diff --git a/SOURCES/kvm-scsi-disk-allow-customizing-the-SCSI-version.patch b/SOURCES/kvm-scsi-disk-allow-customizing-the-SCSI-version.patch deleted file mode 100644 index 8ef8ebd..0000000 --- a/SOURCES/kvm-scsi-disk-allow-customizing-the-SCSI-version.patch +++ /dev/null @@ -1,168 +0,0 @@ -From f4684bd23bf0cd262d0d355a33bae1e9edd0fb5a Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Mon, 25 Jun 2018 04:18:23 +0200 -Subject: [PATCH 1/3] scsi-disk: allow customizing the SCSI version - -RH-Author: David Gibson -Message-id: <20180625041824.5072-2-dgibson@redhat.com> -Patchwork-id: 81032 -O-Subject: [RHEL-7.5.z qemu-kvm-ma PATCH 1/2] scsi-disk: allow customizing the SCSI version -Bugzilla: 1593193 -RH-Acked-by: Laurent Vivier -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Laszlo Ersek - -From: Paolo Bonzini - -We would like to have different behavior for passthrough devices -depending on the SCSI version they expose. To prepare for that, -allow the user of emulated devices to specify the desired SCSI -level, and adjust the emulation according to the property value. -The next patch will set the level for scsi-block and scsi-generic -devices. - -Based on a patch by Daniel Henrique Barboza -. - -Signed-off-by: Paolo Bonzini -(cherry picked from commit 2343be0d7ee8a6e02c2bf99d0243492085c8d399) - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - hw/scsi/scsi-disk.c | 29 ++++++++++++++++++++++++----- - hw/scsi/scsi-generic.c | 1 + - include/hw/scsi/scsi.h | 2 ++ - 3 files changed, 27 insertions(+), 5 deletions(-) - -diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c -index 25cbd7b..f906ffb 100644 ---- a/hw/scsi/scsi-disk.c -+++ b/hw/scsi/scsi-disk.c -@@ -800,7 +800,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) - * block characteristics VPD page by default. Not all of SPC-3 - * is actually implemented, but we're good enough. - */ -- outbuf[2] = 5; -+ outbuf[2] = s->qdev.default_scsi_version; - outbuf[3] = 2 | 0x10; /* Format 2, HiSup */ - - if (buflen > 36) { -@@ -2168,7 +2168,11 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf) - case READ_12: - case READ_16: - DPRINTF("Read (sector %" PRId64 ", count %u)\n", r->req.cmd.lba, len); -- if (r->req.cmd.buf[1] & 0xe0) { -+ /* Protection information is not supported. For SCSI versions 2 and -+ * older (as determined by snooping the guest's INQUIRY commands), -+ * there is no RD/WR/VRPROTECT, so skip this check in these versions. -+ */ -+ if (s->qdev.scsi_version > 2 && (r->req.cmd.buf[1] & 0xe0)) { - goto illegal_request; - } - if (!check_lba_range(s, r->req.cmd.lba, len)) { -@@ -2199,7 +2203,7 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf) - * As far as DMA is concerned, we can treat it the same as a write; - * scsi_block_do_sgio will send VERIFY commands. - */ -- if (r->req.cmd.buf[1] & 0xe0) { -+ if (s->qdev.scsi_version > 2 && (r->req.cmd.buf[1] & 0xe0)) { - goto illegal_request; - } - if (!check_lba_range(s, r->req.cmd.lba, len)) { -@@ -2245,6 +2249,8 @@ static void scsi_disk_reset(DeviceState *dev) - /* reset tray statuses */ - s->tray_locked = 0; - s->tray_open = 0; -+ -+ s->qdev.scsi_version = s->qdev.default_scsi_version; - } - - static void scsi_disk_resize_cb(void *opaque) -@@ -2785,6 +2791,8 @@ static bool scsi_block_is_passthrough(SCSIDiskState *s, uint8_t *buf) - static int32_t scsi_block_dma_command(SCSIRequest *req, uint8_t *buf) - { - SCSIBlockReq *r = (SCSIBlockReq *)req; -+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); -+ - r->cmd = req->cmd.buf[0]; - switch (r->cmd >> 5) { - case 0: -@@ -2810,8 +2818,11 @@ static int32_t scsi_block_dma_command(SCSIRequest *req, uint8_t *buf) - abort(); - } - -- if (r->cdb1 & 0xe0) { -- /* Protection information is not supported. */ -+ /* Protection information is not supported. For SCSI versions 2 and -+ * older (as determined by snooping the guest's INQUIRY commands), -+ * there is no RD/WR/VRPROTECT, so skip this check in these versions. -+ */ -+ if (s->qdev.scsi_version > 2 && (req->cmd.buf[1] & 0xe0)) { - scsi_check_condition(&r->req, SENSE_CODE(INVALID_FIELD)); - return 0; - } -@@ -2923,6 +2934,8 @@ static Property scsi_hd_properties[] = { - DEFINE_PROP_UINT64("max_io_size", SCSIDiskState, max_io_size, - DEFAULT_MAX_IO_SIZE), - DEFINE_PROP_UINT16("rotation_rate", SCSIDiskState, rotation_rate, 0), -+ DEFINE_PROP_INT32("scsi_version", SCSIDiskState, qdev.default_scsi_version, -+ 5), - DEFINE_BLOCK_CHS_PROPERTIES(SCSIDiskState, qdev.conf), - DEFINE_PROP_END_OF_LIST(), - }; -@@ -2968,6 +2981,8 @@ static Property scsi_cd_properties[] = { - DEFINE_PROP_UINT16("port_index", SCSIDiskState, port_index, 0), - DEFINE_PROP_UINT64("max_io_size", SCSIDiskState, max_io_size, - DEFAULT_MAX_IO_SIZE), -+ DEFINE_PROP_INT32("scsi_version", SCSIDiskState, qdev.default_scsi_version, -+ 5), - DEFINE_PROP_END_OF_LIST(), - }; - -@@ -2995,6 +3010,8 @@ static Property scsi_block_properties[] = { - DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.conf.blk), - DEFINE_PROP_BOOL("share-rw", SCSIDiskState, qdev.conf.share_rw, false), - DEFINE_PROP_UINT16("rotation_rate", SCSIDiskState, rotation_rate, 0), -+ DEFINE_PROP_INT32("scsi_version", SCSIDiskState, qdev.default_scsi_version, -+ 5), - DEFINE_PROP_END_OF_LIST(), - }; - -@@ -3035,6 +3052,8 @@ static Property scsi_disk_properties[] = { - DEFAULT_MAX_UNMAP_SIZE), - DEFINE_PROP_UINT64("max_io_size", SCSIDiskState, max_io_size, - DEFAULT_MAX_IO_SIZE), -+ DEFINE_PROP_INT32("scsi_version", SCSIDiskState, qdev.default_scsi_version, -+ 5), - DEFINE_PROP_END_OF_LIST(), - }; - -diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c -index ba70c0d..fe11efe 100644 ---- a/hw/scsi/scsi-generic.c -+++ b/hw/scsi/scsi-generic.c -@@ -474,6 +474,7 @@ static void scsi_generic_reset(DeviceState *dev) - { - SCSIDevice *s = SCSI_DEVICE(dev); - -+ s->scsi_version = s->default_scsi_version; - scsi_device_purge_requests(s, SENSE_CODE(RESET)); - } - -diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h -index 802a647..73ff391 100644 ---- a/include/hw/scsi/scsi.h -+++ b/include/hw/scsi/scsi.h -@@ -85,6 +85,8 @@ struct SCSIDevice - uint64_t max_lba; - uint64_t wwn; - uint64_t port_wwn; -+ int scsi_version; -+ int default_scsi_version; - }; - - extern const VMStateDescription vmstate_scsi_device; --- -1.8.3.1 - diff --git a/SOURCES/kvm-scsi-disk-release-AioContext-in-unaligned-WRITE-SAME.patch b/SOURCES/kvm-scsi-disk-release-AioContext-in-unaligned-WRITE-SAME.patch deleted file mode 100644 index 10c93f9..0000000 --- a/SOURCES/kvm-scsi-disk-release-AioContext-in-unaligned-WRITE-SAME.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 81bdf75b893c852a9daae615b4ab41106eb364db Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Thu, 18 Jan 2018 12:12:04 +0100 -Subject: [PATCH 06/21] scsi-disk: release AioContext in unaligned WRITE SAME - case - -RH-Author: Stefan Hajnoczi -Message-id: <20180118121204.17287-2-stefanha@redhat.com> -Patchwork-id: 78663 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 1/1] scsi-disk: release AioContext in unaligned WRITE SAME case -Bugzilla: 1526423 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Jeffrey Cody -RH-Acked-by: John Snow -RH-Acked-by: Laszlo Ersek - -scsi_write_same_complete() can retry the write if the request was -unaligned. Make sure to release the AioContext when that code path is -taken! - -This patch fixes a hang when QEMU terminates after an unaligned WRITE -SAME request has been processed with dataplane. The hang occurs because -iothread_stop_all() cannot acquire the AioContext lock that was leaked -by the IOThread in scsi_write_same_complete(). - -Fixes: b9e413dd37 ("block: explicitly acquire aiocontext in aio callbacks that need it"). -Cc: Paolo Bonzini -Cc: qemu-stable@nongnu.org -Reported-by: Cong Li -Signed-off-by: Stefan Hajnoczi -Message-Id: <20180104142502.15175-1-stefanha@redhat.com> -Signed-off-by: Paolo Bonzini -(cherry picked from commit 24355b79bdaf6ab12f7c610b032fc35ec045cd55) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - hw/scsi/scsi-disk.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c -index c676355..25cbd7b 100644 ---- a/hw/scsi/scsi-disk.c -+++ b/hw/scsi/scsi-disk.c -@@ -1747,6 +1747,7 @@ static void scsi_write_same_complete(void *opaque, int ret) - data->sector << BDRV_SECTOR_BITS, - &data->qiov, 0, - scsi_write_same_complete, data); -+ aio_context_release(blk_get_aio_context(s->qdev.conf.blk)); - return; - } - --- -1.8.3.1 - diff --git a/SOURCES/kvm-scsi-disk-support-reporting-of-rotation-rate.patch b/SOURCES/kvm-scsi-disk-support-reporting-of-rotation-rate.patch deleted file mode 100644 index 90ef5bc..0000000 --- a/SOURCES/kvm-scsi-disk-support-reporting-of-rotation-rate.patch +++ /dev/null @@ -1,100 +0,0 @@ -From 23c1feb875805a4c324c51c3916b249da0edbe02 Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Wed, 29 Nov 2017 14:26:04 +0100 -Subject: [PATCH 18/21] scsi-disk: support reporting of rotation rate - -RH-Author: Daniel P. Berrange -Message-id: <20171129142606.15965-2-berrange@redhat.com> -Patchwork-id: 77961 -O-Subject: [PATCH RHV-7.5 qemu-kvm-rhev 1/3] scsi-disk: support reporting of rotation rate -Bugzilla: 1498042 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: John Snow -RH-Acked-by: Stefan Hajnoczi - -The Linux kernel will query the SCSI "Block device characteristics" -VPD to determine the rotations per minute of the disk. If this has -the value 1, it is taken to be an SSD and so Linux sets the -'rotational' flag to 0 for the I/O queue and will stop using that -disk as a source of random entropy. Other operating systems may -also take into account rotation rate when setting up default -behaviour. - -Mgmt apps should be able to set the rotation rate for virtualized -block devices, based on characteristics of the host storage in use, -so that the guest OS gets sensible behaviour out of the box. This -patch thus adds a 'rotation-rate' parameter for 'scsi-hd' and -'scsi-block' device types. For the latter, this parameter will be -ignored unless the host device has TYPE_DISK. - -Signed-off-by: Daniel P. Berrange -Message-Id: <20171004114008.14849-2-berrange@redhat.com> -Signed-off-by: Paolo Bonzini -(cherry picked from commit 070f80095ad5b1143b50d2faffd2b1a84292e00d) -Signed-off-by: Miroslav Rezanina ---- - hw/scsi/scsi-disk.c | 20 ++++++++++++++++++++ - 1 file changed, 20 insertions(+) - -diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c -index 5f1e5e8..21d6b4e 100644 ---- a/hw/scsi/scsi-disk.c -+++ b/hw/scsi/scsi-disk.c -@@ -104,6 +104,14 @@ typedef struct SCSIDiskState - char *product; - bool tray_open; - bool tray_locked; -+ /* -+ * 0x0000 - rotation rate not reported -+ * 0x0001 - non-rotating medium (SSD) -+ * 0x0002-0x0400 - reserved -+ * 0x0401-0xffe - rotations per minute -+ * 0xffff - reserved -+ */ -+ uint16_t rotation_rate; - } SCSIDiskState; - - static int scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed); -@@ -597,6 +605,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) - outbuf[buflen++] = 0x83; // device identification - if (s->qdev.type == TYPE_DISK) { - outbuf[buflen++] = 0xb0; // block limits -+ outbuf[buflen++] = 0xb1; /* block device characteristics */ - outbuf[buflen++] = 0xb2; // thin provisioning - } - break; -@@ -739,6 +748,15 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) - outbuf[43] = max_io_sectors & 0xff; - break; - } -+ case 0xb1: /* block device characteristics */ -+ { -+ buflen = 8; -+ outbuf[4] = (s->rotation_rate >> 8) & 0xff; -+ outbuf[5] = s->rotation_rate & 0xff; -+ outbuf[6] = 0; -+ outbuf[7] = 0; -+ break; -+ } - case 0xb2: /* thin provisioning */ - { - buflen = 8; -@@ -2903,6 +2921,7 @@ static Property scsi_hd_properties[] = { - DEFAULT_MAX_UNMAP_SIZE), - DEFINE_PROP_UINT64("max_io_size", SCSIDiskState, max_io_size, - DEFAULT_MAX_IO_SIZE), -+ DEFINE_PROP_UINT16("rotation_rate", SCSIDiskState, rotation_rate, 0), - DEFINE_BLOCK_CHS_PROPERTIES(SCSIDiskState, qdev.conf), - DEFINE_PROP_END_OF_LIST(), - }; -@@ -2973,6 +2992,7 @@ static const TypeInfo scsi_cd_info = { - #ifdef __linux__ - static Property scsi_block_properties[] = { - DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.conf.blk), -+ DEFINE_PROP_UINT16("rotation_rate", SCSIDiskState, rotation_rate, 0), - DEFINE_PROP_END_OF_LIST(), - }; - --- -1.8.3.1 - diff --git a/SOURCES/kvm-scsi-file-posix-add-support-for-persistent-reservati.patch b/SOURCES/kvm-scsi-file-posix-add-support-for-persistent-reservati.patch deleted file mode 100644 index 30f3912..0000000 --- a/SOURCES/kvm-scsi-file-posix-add-support-for-persistent-reservati.patch +++ /dev/null @@ -1,451 +0,0 @@ -From f9b538c808178d27af2d4726a8f4b36a305b072b Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Sat, 2 Dec 2017 12:19:48 +0100 -Subject: [PATCH 22/36] scsi, file-posix: add support for persistent - reservation management - -RH-Author: Paolo Bonzini -Message-id: <20171202121953.13317-13-pbonzini@redhat.com> -Patchwork-id: 78087 -O-Subject: [RHEL7.4 qemu-kvm-rhev PATCH 12/17] scsi, file-posix: add support for persistent reservation management -Bugzilla: 1464908 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: John Snow - -It is a common requirement for virtual machine to send persistent -reservations, but this currently requires either running QEMU with -CAP_SYS_RAWIO, or using out-of-tree patches that let an unprivileged -QEMU bypass Linux's filter on SG_IO commands. - -As an alternative mechanism, the next patches will introduce a -privileged helper to run persistent reservation commands without -expanding QEMU's attack surface unnecessarily. - -The helper is invoked through a "pr-manager" QOM object, to which -file-posix.c passes SG_IO requests for PERSISTENT RESERVE OUT and -PERSISTENT RESERVE IN commands. For example: - - $ qemu-system-x86_64 - -device virtio-scsi \ - -object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock - -drive if=none,id=hd,driver=raw,file.filename=/dev/sdb,file.pr-manager=helper0 - -device scsi-block,drive=hd - -or: - - $ qemu-system-x86_64 - -device virtio-scsi \ - -object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock - -blockdev node-name=hd,driver=raw,file.driver=host_device,file.filename=/dev/sdb,file.pr-manager=helper0 - -device scsi-block,drive=hd - -Multiple pr-manager implementations are conceivable and possible, though -only one is implemented right now. For example, a pr-manager could: - -- talk directly to the multipath daemon from a privileged QEMU - (i.e. QEMU links to libmpathpersist); this makes reservation work - properly with multipath, but still requires CAP_SYS_RAWIO - -- use the Linux IOC_PR_* ioctls (they require CAP_SYS_ADMIN though) - -- more interestingly, implement reservations directly in QEMU - through file system locks or a shared database (e.g. sqlite) - -Signed-off-by: Paolo Bonzini -(cherry picked from commit 7c9e527659c67d4d7b41d9504f93d2d7ee482488) -Signed-off-by: Miroslav Rezanina ---- - Makefile.objs | 1 + - block/file-posix.c | 30 +++++++++++++ - docs/pr-manager.rst | 51 ++++++++++++++++++++++ - include/scsi/pr-manager.h | 56 ++++++++++++++++++++++++ - qapi/block-core.json | 4 ++ - scsi/Makefile.objs | 2 + - scsi/pr-manager.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++ - scsi/trace-events | 3 ++ - vl.c | 3 +- - 9 files changed, 258 insertions(+), 1 deletion(-) - create mode 100644 docs/pr-manager.rst - create mode 100644 include/scsi/pr-manager.h - create mode 100644 scsi/pr-manager.c - create mode 100644 scsi/trace-events - -diff --git a/Makefile.objs b/Makefile.objs -index f68aa3b..64bebd0 100644 ---- a/Makefile.objs -+++ b/Makefile.objs -@@ -168,6 +168,7 @@ trace-events-subdirs += qapi - trace-events-subdirs += accel/tcg - trace-events-subdirs += accel/kvm - trace-events-subdirs += nbd -+trace-events-subdirs += scsi - - trace-events-files = $(SRC_PATH)/trace-events $(trace-events-subdirs:%=$(SRC_PATH)/%/trace-events) - -diff --git a/block/file-posix.c b/block/file-posix.c -index cb3bfce..9cacf06 100644 ---- a/block/file-posix.c -+++ b/block/file-posix.c -@@ -34,6 +34,9 @@ - #include "qapi/util.h" - #include "qapi/qmp/qstring.h" - -+#include "scsi/pr-manager.h" -+#include "scsi/constants.h" -+ - #if defined(__APPLE__) && (__MACH__) - #include - #include -@@ -156,6 +159,8 @@ typedef struct BDRVRawState { - bool page_cache_inconsistent:1; - bool has_fallocate; - bool needs_alignment; -+ -+ PRManager *pr_mgr; - } BDRVRawState; - - typedef struct BDRVRawReopenState { -@@ -403,6 +408,11 @@ static QemuOptsList raw_runtime_opts = { - .type = QEMU_OPT_STRING, - .help = "file locking mode (on/off/auto, default: auto)", - }, -+ { -+ .name = "pr-manager", -+ .type = QEMU_OPT_STRING, -+ .help = "id of persistent reservation manager object (default: none)", -+ }, - { /* end of list */ } - }, - }; -@@ -414,6 +424,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, - QemuOpts *opts; - Error *local_err = NULL; - const char *filename = NULL; -+ const char *str; - BlockdevAioOptions aio, aio_default; - int fd, ret; - struct stat st; -@@ -475,6 +486,16 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, - abort(); - } - -+ str = qemu_opt_get(opts, "pr-manager"); -+ if (str) { -+ s->pr_mgr = pr_manager_lookup(str, &local_err); -+ if (local_err) { -+ error_propagate(errp, local_err); -+ ret = -EINVAL; -+ goto fail; -+ } -+ } -+ - s->open_flags = open_flags; - raw_parse_flags(bdrv_flags, &s->open_flags); - -@@ -2597,6 +2618,15 @@ static BlockAIOCB *hdev_aio_ioctl(BlockDriverState *bs, - if (fd_open(bs) < 0) - return NULL; - -+ if (req == SG_IO && s->pr_mgr) { -+ struct sg_io_hdr *io_hdr = buf; -+ if (io_hdr->cmdp[0] == PERSISTENT_RESERVE_OUT || -+ io_hdr->cmdp[0] == PERSISTENT_RESERVE_IN) { -+ return pr_manager_execute(s->pr_mgr, bdrv_get_aio_context(bs), -+ s->fd, io_hdr, cb, opaque); -+ } -+ } -+ - acb = g_new(RawPosixAIOData, 1); - acb->bs = bs; - acb->aio_type = QEMU_AIO_IOCTL; -diff --git a/docs/pr-manager.rst b/docs/pr-manager.rst -new file mode 100644 -index 0000000..b6089fb ---- /dev/null -+++ b/docs/pr-manager.rst -@@ -0,0 +1,51 @@ -+====================================== -+Persistent reservation managers -+====================================== -+ -+SCSI persistent Reservations allow restricting access to block devices -+to specific initiators in a shared storage setup. When implementing -+clustering of virtual machines, it is a common requirement for virtual -+machines to send persistent reservation SCSI commands. However, -+the operating system restricts sending these commands to unprivileged -+programs because incorrect usage can disrupt regular operation of the -+storage fabric. -+ -+For this reason, QEMU's SCSI passthrough devices, ``scsi-block`` -+and ``scsi-generic`` (both are only available on Linux) can delegate -+implementation of persistent reservations to a separate object, -+the "persistent reservation manager". Only PERSISTENT RESERVE OUT and -+PERSISTENT RESERVE IN commands are passed to the persistent reservation -+manager object; other commands are processed by QEMU as usual. -+ -+----------------------------------------- -+Defining a persistent reservation manager -+----------------------------------------- -+ -+A persistent reservation manager is an instance of a subclass of the -+"pr-manager" QOM class. -+ -+Right now only one subclass is defined, ``pr-manager-helper``, which -+forwards the commands to an external privileged helper program -+over Unix sockets. The helper program only allows sending persistent -+reservation commands to devices for which QEMU has a file descriptor, -+so that QEMU will not be able to effect persistent reservations -+unless it has access to both the socket and the device. -+ -+``pr-manager-helper`` has a single string property, ``path``, which -+accepts the path to the helper program's Unix socket. For example, -+the following command line defines a ``pr-manager-helper`` object and -+attaches it to a SCSI passthrough device:: -+ -+ $ qemu-system-x86_64 -+ -device virtio-scsi \ -+ -object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock -+ -drive if=none,id=hd,driver=raw,file.filename=/dev/sdb,file.pr-manager=helper0 -+ -device scsi-block,drive=hd -+ -+Alternatively, using ``-blockdev``:: -+ -+ $ qemu-system-x86_64 -+ -device virtio-scsi \ -+ -object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock -+ -blockdev node-name=hd,driver=raw,file.driver=host_device,file.filename=/dev/sdb,file.pr-manager=helper0 -+ -device scsi-block,drive=hd -diff --git a/include/scsi/pr-manager.h b/include/scsi/pr-manager.h -new file mode 100644 -index 0000000..b2b37d6 ---- /dev/null -+++ b/include/scsi/pr-manager.h -@@ -0,0 +1,56 @@ -+#ifndef PR_MANAGER_H -+#define PR_MANAGER_H -+ -+#include "qom/object.h" -+#include "qapi/qmp/qdict.h" -+#include "qapi/visitor.h" -+#include "qom/object_interfaces.h" -+#include "block/aio.h" -+ -+#define TYPE_PR_MANAGER "pr-manager" -+ -+#define PR_MANAGER_CLASS(klass) \ -+ OBJECT_CLASS_CHECK(PRManagerClass, (klass), TYPE_PR_MANAGER) -+#define PR_MANAGER_GET_CLASS(obj) \ -+ OBJECT_GET_CLASS(PRManagerClass, (obj), TYPE_PR_MANAGER) -+#define PR_MANAGER(obj) \ -+ OBJECT_CHECK(PRManager, (obj), TYPE_PR_MANAGER) -+ -+struct sg_io_hdr; -+ -+typedef struct PRManager { -+ /* */ -+ Object parent; -+} PRManager; -+ -+/** -+ * PRManagerClass: -+ * @parent_class: the base class -+ * @run: callback invoked in thread pool context -+ */ -+typedef struct PRManagerClass { -+ /* */ -+ ObjectClass parent_class; -+ -+ /* */ -+ int (*run)(PRManager *pr_mgr, int fd, struct sg_io_hdr *hdr); -+} PRManagerClass; -+ -+BlockAIOCB *pr_manager_execute(PRManager *pr_mgr, -+ AioContext *ctx, int fd, -+ struct sg_io_hdr *hdr, -+ BlockCompletionFunc *complete, -+ void *opaque); -+ -+#ifdef CONFIG_LINUX -+PRManager *pr_manager_lookup(const char *id, Error **errp); -+#else -+static inline PRManager *pr_manager_lookup(const char *id, Error **errp) -+{ -+ /* The classes do not exist at all! */ -+ error_setg(errp, "No persistent reservation manager with id '%s'", id); -+ return NULL; -+} -+#endif -+ -+#endif -diff --git a/qapi/block-core.json b/qapi/block-core.json -index 8f5f105..15fc08f 100644 ---- a/qapi/block-core.json -+++ b/qapi/block-core.json -@@ -2191,6 +2191,9 @@ - # Driver specific block device options for the file backend. - # - # @filename: path to the image file -+# @pr-manager: the id for the object that will handle persistent reservations -+# for this device (default: none, forward the commands via SG_IO; -+# since 2.11) - # @aio: AIO backend (default: threads) (since: 2.8) - # @locking: whether to enable file locking. If set to 'auto', only enable - # when Open File Descriptor (OFD) locking API is available -@@ -2200,6 +2203,7 @@ - ## - { 'struct': 'BlockdevOptionsFile', - 'data': { 'filename': 'str', -+ '*pr-manager': 'str', - '*locking': 'OnOffAuto', - '*aio': 'BlockdevAioOptions' } } - -diff --git a/scsi/Makefile.objs b/scsi/Makefile.objs -index 31b82a5..5496d2a 100644 ---- a/scsi/Makefile.objs -+++ b/scsi/Makefile.objs -@@ -1 +1,3 @@ - block-obj-y += utils.o -+ -+block-obj-$(CONFIG_LINUX) += pr-manager.o -diff --git a/scsi/pr-manager.c b/scsi/pr-manager.c -new file mode 100644 -index 0000000..87c45db ---- /dev/null -+++ b/scsi/pr-manager.c -@@ -0,0 +1,109 @@ -+/* -+ * Persistent reservation manager abstract class -+ * -+ * Copyright (c) 2017 Red Hat, Inc. -+ * -+ * Author: Paolo Bonzini -+ * -+ * This code is licensed under the LGPL. -+ * -+ */ -+ -+#include "qemu/osdep.h" -+#include -+ -+#include "qapi/error.h" -+#include "block/aio.h" -+#include "block/thread-pool.h" -+#include "scsi/pr-manager.h" -+#include "trace.h" -+ -+typedef struct PRManagerData { -+ PRManager *pr_mgr; -+ struct sg_io_hdr *hdr; -+ int fd; -+} PRManagerData; -+ -+static int pr_manager_worker(void *opaque) -+{ -+ PRManagerData *data = opaque; -+ PRManager *pr_mgr = data->pr_mgr; -+ PRManagerClass *pr_mgr_class = -+ PR_MANAGER_GET_CLASS(pr_mgr); -+ struct sg_io_hdr *hdr = data->hdr; -+ int fd = data->fd; -+ int r; -+ -+ g_free(data); -+ trace_pr_manager_run(fd, hdr->cmdp[0], hdr->cmdp[1]); -+ -+ /* The reference was taken in pr_manager_execute. */ -+ r = pr_mgr_class->run(pr_mgr, fd, hdr); -+ object_unref(OBJECT(pr_mgr)); -+ return r; -+} -+ -+ -+BlockAIOCB *pr_manager_execute(PRManager *pr_mgr, -+ AioContext *ctx, int fd, -+ struct sg_io_hdr *hdr, -+ BlockCompletionFunc *complete, -+ void *opaque) -+{ -+ PRManagerData *data = g_new(PRManagerData, 1); -+ ThreadPool *pool = aio_get_thread_pool(ctx); -+ -+ trace_pr_manager_execute(fd, hdr->cmdp[0], hdr->cmdp[1], opaque); -+ data->pr_mgr = pr_mgr; -+ data->fd = fd; -+ data->hdr = hdr; -+ -+ /* The matching object_unref is in pr_manager_worker. */ -+ object_ref(OBJECT(pr_mgr)); -+ return thread_pool_submit_aio(pool, pr_manager_worker, -+ data, complete, opaque); -+} -+ -+static const TypeInfo pr_manager_info = { -+ .parent = TYPE_OBJECT, -+ .name = TYPE_PR_MANAGER, -+ .class_size = sizeof(PRManagerClass), -+ .abstract = true, -+ .interfaces = (InterfaceInfo[]) { -+ { TYPE_USER_CREATABLE }, -+ { } -+ } -+}; -+ -+PRManager *pr_manager_lookup(const char *id, Error **errp) -+{ -+ Object *obj; -+ PRManager *pr_mgr; -+ -+ obj = object_resolve_path_component(object_get_objects_root(), id); -+ if (!obj) { -+ error_setg(errp, "No persistent reservation manager with id '%s'", id); -+ return NULL; -+ } -+ -+ pr_mgr = (PRManager *) -+ object_dynamic_cast(obj, -+ TYPE_PR_MANAGER); -+ if (!pr_mgr) { -+ error_setg(errp, -+ "Object with id '%s' is not a persistent reservation manager", -+ id); -+ return NULL; -+ } -+ -+ return pr_mgr; -+} -+ -+static void -+pr_manager_register_types(void) -+{ -+ type_register_static(&pr_manager_info); -+} -+ -+ -+type_init(pr_manager_register_types); -diff --git a/scsi/trace-events b/scsi/trace-events -new file mode 100644 -index 0000000..45f5b6e ---- /dev/null -+++ b/scsi/trace-events -@@ -0,0 +1,3 @@ -+# scsi/pr-manager.c -+pr_manager_execute(int fd, int cmd, int sa, void *opaque) "fd=%d cmd=0x%02x service action=0x%02x opaque=%p" -+pr_manager_run(int fd, int cmd, int sa) "fd=%d cmd=0x%02x service action=0x%02x" -diff --git a/vl.c b/vl.c -index 55949e6..bef5ae3 100644 ---- a/vl.c -+++ b/vl.c -@@ -2820,7 +2820,8 @@ static int machine_set_property(void *opaque, - */ - static bool object_create_initial(const char *type) - { -- if (g_str_equal(type, "rng-egd")) { -+ if (g_str_equal(type, "rng-egd") || -+ g_str_has_prefix(type, "pr-manager-")) { - return false; - } - --- -1.8.3.1 - diff --git a/SOURCES/kvm-scsi-generic-Add-share-rw-option.patch b/SOURCES/kvm-scsi-generic-Add-share-rw-option.patch deleted file mode 100644 index 8f8b1c8..0000000 --- a/SOURCES/kvm-scsi-generic-Add-share-rw-option.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 7d6eed4b197081fa324e42f7624d6ab0a27bab6d Mon Sep 17 00:00:00 2001 -From: Fam Zheng -Date: Wed, 17 Jan 2018 06:08:34 +0100 -Subject: [PATCH 04/21] scsi-generic: Add share-rw option - -RH-Author: Fam Zheng -Message-id: <20180117060834.17481-3-famz@redhat.com> -Patchwork-id: 78652 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 2/2] scsi-generic: Add share-rw option -Bugzilla: 1518482 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: John Snow -RH-Acked-by: Jeffrey Cody - -Add the property to the device model, then parse it by calling -blkconf_apply_backend_options(). - -In addition to blk_set_perm(), the called function also handles error -options and wce. For error options we've already checked that the -default values are used, for wce we don't have the option either so it -is always the default (true). In other words there is no change of -behavior in these regards. - -Signed-off-by: Fam Zheng -Message-Id: <20171205151553.7834-1-famz@redhat.com> -Signed-off-by: Paolo Bonzini -(cherry picked from commit d9bcd6f7f23a13ea627d8edb85c0706525da0b75) -Signed-off-by: Fam Zheng -Signed-off-by: Miroslav Rezanina ---- - hw/scsi/scsi-generic.c | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c -index bd0d9ff..ba70c0d 100644 ---- a/hw/scsi/scsi-generic.c -+++ b/hw/scsi/scsi-generic.c -@@ -482,6 +482,7 @@ static void scsi_generic_realize(SCSIDevice *s, Error **errp) - int rc; - int sg_version; - struct sg_scsi_id scsiid; -+ Error *local_err = NULL; - - if (!s->conf.blk) { - error_setg(errp, "drive property not set"); -@@ -515,6 +516,13 @@ static void scsi_generic_realize(SCSIDevice *s, Error **errp) - error_setg(errp, "SG_GET_SCSI_ID ioctl failed"); - return; - } -+ blkconf_apply_backend_options(&s->conf, -+ blk_is_read_only(s->conf.blk), -+ true, &local_err); -+ if (local_err) { -+ error_propagate(errp, local_err); -+ return; -+ } - - /* define device state */ - s->type = scsiid.scsi_type; -@@ -565,6 +573,7 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun, - - static Property scsi_generic_properties[] = { - DEFINE_PROP_DRIVE("drive", SCSIDevice, conf.blk), -+ DEFINE_PROP_BOOL("share-rw", SCSIDevice, conf.share_rw, false), - DEFINE_PROP_END_OF_LIST(), - }; - --- -1.8.3.1 - diff --git a/SOURCES/kvm-scsi-introduce-scsi_build_sense.patch b/SOURCES/kvm-scsi-introduce-scsi_build_sense.patch deleted file mode 100644 index ebb3f11..0000000 --- a/SOURCES/kvm-scsi-introduce-scsi_build_sense.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 671df2c5697b3509eb8a9e16e3b2ccc51f9719d7 Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Sat, 2 Dec 2017 12:19:45 +0100 -Subject: [PATCH 19/36] scsi: introduce scsi_build_sense -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Paolo Bonzini -Message-id: <20171202121953.13317-10-pbonzini@redhat.com> -Patchwork-id: 78078 -O-Subject: [RHEL7.4 qemu-kvm-rhev PATCH 09/17] scsi: introduce scsi_build_sense -Bugzilla: 1464908 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: John Snow - -Move more knowledge of sense data format out of hw/scsi/scsi-bus.c -for reusability. - -Reviewed-by: Philippe Mathieu-Daudé -Reviewed-by: Stefan Hajnoczi -Signed-off-by: Paolo Bonzini -(cherry picked from commit a3760467c6b0ff5d1ff952fdc8cec69c65e19499) -Signed-off-by: Miroslav Rezanina ---- - hw/scsi/scsi-bus.c | 8 +------- - include/scsi/utils.h | 2 ++ - scsi/utils.c | 11 +++++++++++ - 3 files changed, 14 insertions(+), 7 deletions(-) - -diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c -index 635cdf6..f77e576 100644 ---- a/hw/scsi/scsi-bus.c -+++ b/hw/scsi/scsi-bus.c -@@ -826,13 +826,7 @@ void scsi_req_build_sense(SCSIRequest *req, SCSISense sense) - { - trace_scsi_req_build_sense(req->dev->id, req->lun, req->tag, - sense.key, sense.asc, sense.ascq); -- memset(req->sense, 0, 18); -- req->sense[0] = 0x70; -- req->sense[2] = sense.key; -- req->sense[7] = 10; -- req->sense[12] = sense.asc; -- req->sense[13] = sense.ascq; -- req->sense_len = 18; -+ req->sense_len = scsi_build_sense(req->sense, sense); - } - - static void scsi_req_enqueue_internal(SCSIRequest *req) -diff --git a/include/scsi/utils.h b/include/scsi/utils.h -index 90bf4dc..b49392d 100644 ---- a/include/scsi/utils.h -+++ b/include/scsi/utils.h -@@ -30,6 +30,8 @@ typedef struct SCSISense { - uint8_t ascq; - } SCSISense; - -+int scsi_build_sense(uint8_t *buf, SCSISense sense); -+ - /* - * Predefined sense codes - */ -diff --git a/scsi/utils.c b/scsi/utils.c -index 2327e06..89d9167 100644 ---- a/scsi/utils.c -+++ b/scsi/utils.c -@@ -96,6 +96,17 @@ int scsi_cdb_length(uint8_t *buf) - return cdb_len; - } - -+int scsi_build_sense(uint8_t *buf, SCSISense sense) -+{ -+ memset(buf, 0, 18); -+ buf[0] = 0x70; -+ buf[2] = sense.key; -+ buf[7] = 10; -+ buf[12] = sense.asc; -+ buf[13] = sense.ascq; -+ return 18; -+} -+ - /* - * Predefined sense codes - */ --- -1.8.3.1 - diff --git a/SOURCES/kvm-scsi-introduce-sg_io_sense_from_errno.patch b/SOURCES/kvm-scsi-introduce-sg_io_sense_from_errno.patch deleted file mode 100644 index 3c55e1c..0000000 --- a/SOURCES/kvm-scsi-introduce-sg_io_sense_from_errno.patch +++ /dev/null @@ -1,148 +0,0 @@ -From b1aa9df721c90e02c917eba8f753fa50d3c1e952 Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Sat, 2 Dec 2017 12:19:46 +0100 -Subject: [PATCH 20/36] scsi: introduce sg_io_sense_from_errno - -RH-Author: Paolo Bonzini -Message-id: <20171202121953.13317-11-pbonzini@redhat.com> -Patchwork-id: 78080 -O-Subject: [RHEL7.4 qemu-kvm-rhev PATCH 10/17] scsi: introduce sg_io_sense_from_errno -Bugzilla: 1464908 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: John Snow - -Move more knowledge of SG_IO out of hw/scsi/scsi-generic.c, for -reusability. - -Reviewed-by: Stefan Hajnoczi -Signed-off-by: Paolo Bonzini -(cherry picked from commit 1ead6b4e242e59711976cdf2502dd5c7cd5d340a) -Signed-off-by: Miroslav Rezanina ---- - hw/scsi/scsi-generic.c | 40 +++++++--------------------------------- - include/scsi/utils.h | 3 +++ - scsi/utils.c | 35 +++++++++++++++++++++++++++++++++++ - 3 files changed, 45 insertions(+), 33 deletions(-) - -diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c -index 7a8f500..04c687e 100644 ---- a/hw/scsi/scsi-generic.c -+++ b/hw/scsi/scsi-generic.c -@@ -81,6 +81,7 @@ static void scsi_free_request(SCSIRequest *req) - static void scsi_command_complete_noio(SCSIGenericReq *r, int ret) - { - int status; -+ SCSISense sense; - - assert(r->req.aiocb == NULL); - -@@ -88,42 +89,15 @@ static void scsi_command_complete_noio(SCSIGenericReq *r, int ret) - scsi_req_cancel_complete(&r->req); - goto done; - } -- if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) { -- r->req.sense_len = r->io_header.sb_len_wr; -- } -- -- if (ret != 0) { -- switch (ret) { -- case -EDOM: -- status = TASK_SET_FULL; -- break; -- case -ENOMEM: -- status = CHECK_CONDITION; -- scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE)); -- break; -- default: -- status = CHECK_CONDITION; -- scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR)); -- break; -- } -- } else { -- if (r->io_header.host_status == SG_ERR_DID_NO_CONNECT || -- r->io_header.host_status == SG_ERR_DID_BUS_BUSY || -- r->io_header.host_status == SG_ERR_DID_TIME_OUT || -- (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT)) { -- status = BUSY; -- BADF("Driver Timeout\n"); -- } else if (r->io_header.host_status) { -- status = CHECK_CONDITION; -- scsi_req_build_sense(&r->req, SENSE_CODE(I_T_NEXUS_LOSS)); -- } else if (r->io_header.status) { -- status = r->io_header.status; -- } else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) { -- status = CHECK_CONDITION; -+ status = sg_io_sense_from_errno(-ret, &r->io_header, &sense); -+ if (status == CHECK_CONDITION) { -+ if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) { -+ r->req.sense_len = r->io_header.sb_len_wr; - } else { -- status = GOOD; -+ scsi_req_build_sense(&r->req, sense); - } - } -+ - DPRINTF("Command complete 0x%p tag=0x%x status=%d\n", - r, r->req.tag, status); - -diff --git a/include/scsi/utils.h b/include/scsi/utils.h -index b49392d..d301b31 100644 ---- a/include/scsi/utils.h -+++ b/include/scsi/utils.h -@@ -116,6 +116,9 @@ int scsi_cdb_length(uint8_t *buf); - #define SG_ERR_DID_TIME_OUT 0x03 - - #define SG_ERR_DRIVER_SENSE 0x08 -+ -+int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr, -+ SCSISense *sense); - #endif - - #endif -diff --git a/scsi/utils.c b/scsi/utils.c -index 89d9167..6ee9f40 100644 ---- a/scsi/utils.c -+++ b/scsi/utils.c -@@ -501,3 +501,38 @@ const char *scsi_command_name(uint8_t cmd) - } - return names[cmd]; - } -+ -+#ifdef CONFIG_LINUX -+int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr, -+ SCSISense *sense) -+{ -+ if (errno_value != 0) { -+ switch (errno_value) { -+ case EDOM: -+ return TASK_SET_FULL; -+ case ENOMEM: -+ *sense = SENSE_CODE(TARGET_FAILURE); -+ return CHECK_CONDITION; -+ default: -+ *sense = SENSE_CODE(IO_ERROR); -+ return CHECK_CONDITION; -+ } -+ } else { -+ if (io_hdr->host_status == SG_ERR_DID_NO_CONNECT || -+ io_hdr->host_status == SG_ERR_DID_BUS_BUSY || -+ io_hdr->host_status == SG_ERR_DID_TIME_OUT || -+ (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT)) { -+ return BUSY; -+ } else if (io_hdr->host_status) { -+ *sense = SENSE_CODE(I_T_NEXUS_LOSS); -+ return CHECK_CONDITION; -+ } else if (io_hdr->status) { -+ return io_hdr->status; -+ } else if (io_hdr->driver_status & SG_ERR_DRIVER_SENSE) { -+ return CHECK_CONDITION; -+ } else { -+ return GOOD; -+ } -+ } -+} -+#endif --- -1.8.3.1 - diff --git a/SOURCES/kvm-scsi-move-block-scsi.h-to-include-scsi-constants.h.patch b/SOURCES/kvm-scsi-move-block-scsi.h-to-include-scsi-constants.h.patch deleted file mode 100644 index 560469b..0000000 --- a/SOURCES/kvm-scsi-move-block-scsi.h-to-include-scsi-constants.h.patch +++ /dev/null @@ -1,899 +0,0 @@ -From a97cc2e8341bf5d50e9282946bcdf26b43ebc34c Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Sat, 2 Dec 2017 12:19:47 +0100 -Subject: [PATCH 21/36] scsi: move block/scsi.h to include/scsi/constants.h -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Paolo Bonzini -Message-id: <20171202121953.13317-12-pbonzini@redhat.com> -Patchwork-id: 78086 -O-Subject: [RHEL7.4 qemu-kvm-rhev PATCH 11/17] scsi: move block/scsi.h to include/scsi/constants.h -Bugzilla: 1464908 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: John Snow - -Complete the transition by renaming this header, which was -shared by block/iscsi.c and the SCSI emulation code. - -Reviewed-by: Philippe Mathieu-Daudé -Reviewed-by: Stefan Hajnoczi -Signed-off-by: Paolo Bonzini -(cherry picked from commit 08e2c9f19ce791b3a0fb6adbf962ab4902ec5a7b) -Signed-off-by: Miroslav Rezanina ---- - block/iscsi.c | 2 +- - hw/block/virtio-blk.c | 2 +- - hw/scsi/megasas.c | 2 +- - hw/scsi/mptendian.c | 2 +- - hw/scsi/mptsas.c | 2 +- - hw/scsi/scsi-bus.c | 2 +- - hw/scsi/scsi-disk.c | 2 +- - hw/scsi/scsi-generic.c | 2 +- - hw/scsi/spapr_vscsi.c | 2 +- - hw/scsi/virtio-scsi-dataplane.c | 2 +- - hw/scsi/virtio-scsi.c | 2 +- - hw/scsi/vmw_pvscsi.c | 2 +- - hw/usb/dev-uas.c | 2 +- - include/block/scsi.h | 314 ---------------------------------------- - include/hw/ide/internal.h | 2 +- - include/scsi/constants.h | 314 ++++++++++++++++++++++++++++++++++++++++ - scsi/utils.c | 2 +- - tests/virtio-scsi-test.c | 2 +- - 18 files changed, 330 insertions(+), 330 deletions(-) - delete mode 100644 include/block/scsi.h - create mode 100644 include/scsi/constants.h - -diff --git a/block/iscsi.c b/block/iscsi.c -index 40adc3c..c4586be 100644 ---- a/block/iscsi.c -+++ b/block/iscsi.c -@@ -34,7 +34,7 @@ - #include "qemu/bitops.h" - #include "qemu/bitmap.h" - #include "block/block_int.h" --#include "block/scsi.h" -+#include "scsi/constants.h" - #include "qemu/iov.h" - #include "qemu/uuid.h" - #include "qmp-commands.h" -diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c -index a16ac75..05d1440 100644 ---- a/hw/block/virtio-blk.c -+++ b/hw/block/virtio-blk.c -@@ -22,7 +22,7 @@ - #include "sysemu/blockdev.h" - #include "hw/virtio/virtio-blk.h" - #include "dataplane/virtio-blk.h" --#include "block/scsi.h" -+#include "scsi/constants.h" - #ifdef __linux__ - # include - #endif -diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c -index 4ae10e3..d5eae62 100644 ---- a/hw/scsi/megasas.c -+++ b/hw/scsi/megasas.c -@@ -27,7 +27,7 @@ - #include "hw/pci/msix.h" - #include "qemu/iov.h" - #include "hw/scsi/scsi.h" --#include "block/scsi.h" -+#include "scsi/constants.h" - #include "trace.h" - #include "qapi/error.h" - #include "mfi.h" -diff --git a/hw/scsi/mptendian.c b/hw/scsi/mptendian.c -index b7fe2a2..3415229 100644 ---- a/hw/scsi/mptendian.c -+++ b/hw/scsi/mptendian.c -@@ -28,7 +28,7 @@ - #include "hw/pci/msi.h" - #include "qemu/iov.h" - #include "hw/scsi/scsi.h" --#include "block/scsi.h" -+#include "scsi/constants.h" - #include "trace.h" - - #include "mptsas.h" -diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c -index f807dc6..2f2c1b1 100644 ---- a/hw/scsi/mptsas.c -+++ b/hw/scsi/mptsas.c -@@ -30,7 +30,7 @@ - #include "hw/pci/msi.h" - #include "qemu/iov.h" - #include "hw/scsi/scsi.h" --#include "block/scsi.h" -+#include "scsi/constants.h" - #include "trace.h" - #include "qapi/error.h" - #include "mptsas.h" -diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c -index f77e576..97c9525 100644 ---- a/hw/scsi/scsi-bus.c -+++ b/hw/scsi/scsi-bus.c -@@ -3,7 +3,7 @@ - #include "qapi/error.h" - #include "qemu/error-report.h" - #include "hw/scsi/scsi.h" --#include "block/scsi.h" -+#include "scsi/constants.h" - #include "hw/qdev.h" - #include "sysemu/block-backend.h" - #include "sysemu/blockdev.h" -diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c -index b7714e3..8a63377 100644 ---- a/hw/scsi/scsi-disk.c -+++ b/hw/scsi/scsi-disk.c -@@ -32,7 +32,7 @@ do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0) - #include "qapi/error.h" - #include "qemu/error-report.h" - #include "hw/scsi/scsi.h" --#include "block/scsi.h" -+#include "scsi/constants.h" - #include "sysemu/sysemu.h" - #include "sysemu/block-backend.h" - #include "sysemu/blockdev.h" -diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c -index 04c687e..bd0d9ff 100644 ---- a/hw/scsi/scsi-generic.c -+++ b/hw/scsi/scsi-generic.c -@@ -34,7 +34,7 @@ do { printf("scsi-generic: " fmt , ## __VA_ARGS__); } while (0) - do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0) - - #include --#include "block/scsi.h" -+#include "scsi/constants.h" - - #ifndef MAX_UINT - #define MAX_UINT ((unsigned int)-1) -diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c -index 92a3de3..5a7ca06 100644 ---- a/hw/scsi/spapr_vscsi.c -+++ b/hw/scsi/spapr_vscsi.c -@@ -36,7 +36,7 @@ - #include "cpu.h" - #include "hw/hw.h" - #include "hw/scsi/scsi.h" --#include "block/scsi.h" -+#include "scsi/constants.h" - #include "srp.h" - #include "hw/qdev.h" - #include "hw/ppc/spapr.h" -diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c -index 944ea4e..add4b3f 100644 ---- a/hw/scsi/virtio-scsi-dataplane.c -+++ b/hw/scsi/virtio-scsi-dataplane.c -@@ -17,7 +17,7 @@ - #include "qemu/error-report.h" - #include "sysemu/block-backend.h" - #include "hw/scsi/scsi.h" --#include "block/scsi.h" -+#include "scsi/constants.h" - #include "hw/virtio/virtio-bus.h" - #include "hw/virtio/virtio-access.h" - -diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c -index 2635c38..1591283 100644 ---- a/hw/scsi/virtio-scsi.c -+++ b/hw/scsi/virtio-scsi.c -@@ -21,7 +21,7 @@ - #include "qemu/iov.h" - #include "sysemu/block-backend.h" - #include "hw/scsi/scsi.h" --#include "block/scsi.h" -+#include "scsi/constants.h" - #include "hw/virtio/virtio-bus.h" - #include "hw/virtio/virtio-access.h" - -diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c -index d185393..d6b315f 100644 ---- a/hw/scsi/vmw_pvscsi.c -+++ b/hw/scsi/vmw_pvscsi.c -@@ -28,7 +28,7 @@ - #include "qemu/osdep.h" - #include "qapi/error.h" - #include "hw/scsi/scsi.h" --#include "block/scsi.h" -+#include "scsi/constants.h" - #include "hw/pci/msi.h" - #include "vmw_pvscsi.h" - #include "trace.h" -diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c -index fffc424..c218b53 100644 ---- a/hw/usb/dev-uas.c -+++ b/hw/usb/dev-uas.c -@@ -19,7 +19,7 @@ - #include "hw/usb.h" - #include "hw/usb/desc.h" - #include "hw/scsi/scsi.h" --#include "block/scsi.h" -+#include "scsi/constants.h" - - /* --------------------------------------------------------------------- */ - -diff --git a/include/block/scsi.h b/include/block/scsi.h -deleted file mode 100644 -index a141dd7..0000000 ---- a/include/block/scsi.h -+++ /dev/null -@@ -1,314 +0,0 @@ --/* Copyright (C) 1998, 1999 Free Software Foundation, Inc. -- This file is part of the GNU C Library. -- -- The GNU C Library is free software; you can redistribute it and/or -- modify it under the terms of the GNU Lesser General Public -- License as published by the Free Software Foundation; either -- version 2.1 of the License, or (at your option) any later version. -- -- The GNU C Library 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 -- Lesser General Public License for more details. -- -- You should have received a copy of the GNU Lesser General Public -- License along with this library; if not, see . --*/ -- --/* -- * This header file contains public constants and structures used by -- * the scsi code for linux. -- */ -- --#ifndef BLOCK_SCSI_H --#define BLOCK_SCSI_H -- --/* -- * SCSI opcodes -- */ -- --#define TEST_UNIT_READY 0x00 --#define REWIND 0x01 --#define REQUEST_SENSE 0x03 --#define FORMAT_UNIT 0x04 --#define READ_BLOCK_LIMITS 0x05 --#define INITIALIZE_ELEMENT_STATUS 0x07 --#define REASSIGN_BLOCKS 0x07 --#define READ_6 0x08 --#define WRITE_6 0x0a --#define SET_CAPACITY 0x0b --#define READ_REVERSE 0x0f --#define WRITE_FILEMARKS 0x10 --#define SPACE 0x11 --#define INQUIRY 0x12 --#define RECOVER_BUFFERED_DATA 0x14 --#define MODE_SELECT 0x15 --#define RESERVE 0x16 --#define RELEASE 0x17 --#define COPY 0x18 --#define ERASE 0x19 --#define MODE_SENSE 0x1a --#define LOAD_UNLOAD 0x1b --#define SCAN 0x1b --#define START_STOP 0x1b --#define RECEIVE_DIAGNOSTIC 0x1c --#define SEND_DIAGNOSTIC 0x1d --#define ALLOW_MEDIUM_REMOVAL 0x1e --#define SET_WINDOW 0x24 --#define READ_CAPACITY_10 0x25 --#define GET_WINDOW 0x25 --#define READ_10 0x28 --#define WRITE_10 0x2a --#define SEND 0x2a --#define SEEK_10 0x2b --#define LOCATE_10 0x2b --#define POSITION_TO_ELEMENT 0x2b --#define WRITE_VERIFY_10 0x2e --#define VERIFY_10 0x2f --#define SEARCH_HIGH 0x30 --#define SEARCH_EQUAL 0x31 --#define OBJECT_POSITION 0x31 --#define SEARCH_LOW 0x32 --#define SET_LIMITS 0x33 --#define PRE_FETCH 0x34 --#define READ_POSITION 0x34 --#define GET_DATA_BUFFER_STATUS 0x34 --#define SYNCHRONIZE_CACHE 0x35 --#define LOCK_UNLOCK_CACHE 0x36 --#define INITIALIZE_ELEMENT_STATUS_WITH_RANGE 0x37 --#define READ_DEFECT_DATA 0x37 --#define MEDIUM_SCAN 0x38 --#define COMPARE 0x39 --#define COPY_VERIFY 0x3a --#define WRITE_BUFFER 0x3b --#define READ_BUFFER 0x3c --#define UPDATE_BLOCK 0x3d --#define READ_LONG_10 0x3e --#define WRITE_LONG_10 0x3f --#define CHANGE_DEFINITION 0x40 --#define WRITE_SAME_10 0x41 --#define UNMAP 0x42 --#define READ_TOC 0x43 --#define REPORT_DENSITY_SUPPORT 0x44 --#define GET_CONFIGURATION 0x46 --#define SANITIZE 0x48 --#define GET_EVENT_STATUS_NOTIFICATION 0x4a --#define LOG_SELECT 0x4c --#define LOG_SENSE 0x4d --#define READ_DISC_INFORMATION 0x51 --#define RESERVE_TRACK 0x53 --#define MODE_SELECT_10 0x55 --#define RESERVE_10 0x56 --#define RELEASE_10 0x57 --#define MODE_SENSE_10 0x5a --#define SEND_CUE_SHEET 0x5d --#define PERSISTENT_RESERVE_IN 0x5e --#define PERSISTENT_RESERVE_OUT 0x5f --#define VARLENGTH_CDB 0x7f --#define WRITE_FILEMARKS_16 0x80 --#define READ_REVERSE_16 0x81 --#define ALLOW_OVERWRITE 0x82 --#define EXTENDED_COPY 0x83 --#define ATA_PASSTHROUGH_16 0x85 --#define ACCESS_CONTROL_IN 0x86 --#define ACCESS_CONTROL_OUT 0x87 --#define READ_16 0x88 --#define COMPARE_AND_WRITE 0x89 --#define WRITE_16 0x8a --#define WRITE_VERIFY_16 0x8e --#define VERIFY_16 0x8f --#define PRE_FETCH_16 0x90 --#define SPACE_16 0x91 --#define SYNCHRONIZE_CACHE_16 0x91 --#define LOCATE_16 0x92 --#define WRITE_SAME_16 0x93 --#define ERASE_16 0x93 --#define SERVICE_ACTION_IN_16 0x9e --#define WRITE_LONG_16 0x9f --#define REPORT_LUNS 0xa0 --#define ATA_PASSTHROUGH_12 0xa1 --#define MAINTENANCE_IN 0xa3 --#define MAINTENANCE_OUT 0xa4 --#define MOVE_MEDIUM 0xa5 --#define EXCHANGE_MEDIUM 0xa6 --#define SET_READ_AHEAD 0xa7 --#define READ_12 0xa8 --#define WRITE_12 0xaa --#define SERVICE_ACTION_IN_12 0xab --#define ERASE_12 0xac --#define READ_DVD_STRUCTURE 0xad --#define WRITE_VERIFY_12 0xae --#define VERIFY_12 0xaf --#define SEARCH_HIGH_12 0xb0 --#define SEARCH_EQUAL_12 0xb1 --#define SEARCH_LOW_12 0xb2 --#define READ_ELEMENT_STATUS 0xb8 --#define SEND_VOLUME_TAG 0xb6 --#define READ_DEFECT_DATA_12 0xb7 --#define SET_CD_SPEED 0xbb --#define MECHANISM_STATUS 0xbd --#define READ_CD 0xbe --#define SEND_DVD_STRUCTURE 0xbf -- --/* -- * SERVICE ACTION IN subcodes -- */ --#define SAI_READ_CAPACITY_16 0x10 -- --/* -- * READ POSITION service action codes -- */ --#define SHORT_FORM_BLOCK_ID 0x00 --#define SHORT_FORM_VENDOR_SPECIFIC 0x01 --#define LONG_FORM 0x06 --#define EXTENDED_FORM 0x08 -- --/* -- * SAM Status codes -- */ -- --#define GOOD 0x00 --#define CHECK_CONDITION 0x02 --#define CONDITION_GOOD 0x04 --#define BUSY 0x08 --#define INTERMEDIATE_GOOD 0x10 --#define INTERMEDIATE_C_GOOD 0x14 --#define RESERVATION_CONFLICT 0x18 --#define COMMAND_TERMINATED 0x22 --#define TASK_SET_FULL 0x28 --#define ACA_ACTIVE 0x30 --#define TASK_ABORTED 0x40 -- --#define STATUS_MASK 0x3e -- --/* -- * SENSE KEYS -- */ -- --#define NO_SENSE 0x00 --#define RECOVERED_ERROR 0x01 --#define NOT_READY 0x02 --#define MEDIUM_ERROR 0x03 --#define HARDWARE_ERROR 0x04 --#define ILLEGAL_REQUEST 0x05 --#define UNIT_ATTENTION 0x06 --#define DATA_PROTECT 0x07 --#define BLANK_CHECK 0x08 --#define COPY_ABORTED 0x0a --#define ABORTED_COMMAND 0x0b --#define VOLUME_OVERFLOW 0x0d --#define MISCOMPARE 0x0e -- -- --/* -- * DEVICE TYPES -- */ -- --#define TYPE_DISK 0x00 --#define TYPE_TAPE 0x01 --#define TYPE_PRINTER 0x02 --#define TYPE_PROCESSOR 0x03 /* HP scanners use this */ --#define TYPE_WORM 0x04 /* Treated as ROM by our system */ --#define TYPE_ROM 0x05 --#define TYPE_SCANNER 0x06 --#define TYPE_MOD 0x07 /* Magneto-optical disk - -- * - treated as TYPE_DISK */ --#define TYPE_MEDIUM_CHANGER 0x08 --#define TYPE_STORAGE_ARRAY 0x0c /* Storage array device */ --#define TYPE_ENCLOSURE 0x0d /* Enclosure Services Device */ --#define TYPE_RBC 0x0e /* Simplified Direct-Access Device */ --#define TYPE_OSD 0x11 /* Object-storage Device */ --#define TYPE_WLUN 0x1e /* Well known LUN */ --#define TYPE_NOT_PRESENT 0x1f --#define TYPE_INACTIVE 0x20 --#define TYPE_NO_LUN 0x7f -- --/* Mode page codes for mode sense/set */ --#define MODE_PAGE_R_W_ERROR 0x01 --#define MODE_PAGE_HD_GEOMETRY 0x04 --#define MODE_PAGE_FLEXIBLE_DISK_GEOMETRY 0x05 --#define MODE_PAGE_CACHING 0x08 --#define MODE_PAGE_AUDIO_CTL 0x0e --#define MODE_PAGE_POWER 0x1a --#define MODE_PAGE_FAULT_FAIL 0x1c --#define MODE_PAGE_TO_PROTECT 0x1d --#define MODE_PAGE_CAPABILITIES 0x2a --#define MODE_PAGE_ALLS 0x3f --/* Not in Mt. Fuji, but in ATAPI 2.6 -- deprecated now in favor -- * of MODE_PAGE_SENSE_POWER */ --#define MODE_PAGE_CDROM 0x0d -- --/* Event notification classes for GET EVENT STATUS NOTIFICATION */ --#define GESN_NO_EVENTS 0 --#define GESN_OPERATIONAL_CHANGE 1 --#define GESN_POWER_MANAGEMENT 2 --#define GESN_EXTERNAL_REQUEST 3 --#define GESN_MEDIA 4 --#define GESN_MULTIPLE_HOSTS 5 --#define GESN_DEVICE_BUSY 6 -- --/* Event codes for MEDIA event status notification */ --#define MEC_NO_CHANGE 0 --#define MEC_EJECT_REQUESTED 1 --#define MEC_NEW_MEDIA 2 --#define MEC_MEDIA_REMOVAL 3 /* only for media changers */ --#define MEC_MEDIA_CHANGED 4 /* only for media changers */ --#define MEC_BG_FORMAT_COMPLETED 5 /* MRW or DVD+RW b/g format completed */ --#define MEC_BG_FORMAT_RESTARTED 6 /* MRW or DVD+RW b/g format restarted */ -- --#define MS_TRAY_OPEN 1 --#define MS_MEDIA_PRESENT 2 -- --/* -- * Based on values from but extending CD_MINS -- * to the maximum common size allowed by the Orange's Book ATIP -- * -- * 90 and 99 min CDs are also available but using them as the -- * upper limit reduces the effectiveness of the heuristic to -- * detect DVDs burned to less than 25% of their maximum capacity -- */ -- --/* Some generally useful CD-ROM information */ --#define CD_MINS 80 /* max. minutes per CD */ --#define CD_SECS 60 /* seconds per minute */ --#define CD_FRAMES 75 /* frames per second */ --#define CD_FRAMESIZE 2048 /* bytes per frame, "cooked" mode */ --#define CD_MAX_BYTES (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE) --#define CD_MAX_SECTORS (CD_MAX_BYTES / 512) -- --/* -- * The MMC values are not IDE specific and might need to be moved -- * to a common header if they are also needed for the SCSI emulation -- */ -- --/* Profile list from MMC-6 revision 1 table 91 */ --#define MMC_PROFILE_NONE 0x0000 --#define MMC_PROFILE_CD_ROM 0x0008 --#define MMC_PROFILE_CD_R 0x0009 --#define MMC_PROFILE_CD_RW 0x000A --#define MMC_PROFILE_DVD_ROM 0x0010 --#define MMC_PROFILE_DVD_R_SR 0x0011 --#define MMC_PROFILE_DVD_RAM 0x0012 --#define MMC_PROFILE_DVD_RW_RO 0x0013 --#define MMC_PROFILE_DVD_RW_SR 0x0014 --#define MMC_PROFILE_DVD_R_DL_SR 0x0015 --#define MMC_PROFILE_DVD_R_DL_JR 0x0016 --#define MMC_PROFILE_DVD_RW_DL 0x0017 --#define MMC_PROFILE_DVD_DDR 0x0018 --#define MMC_PROFILE_DVD_PLUS_RW 0x001A --#define MMC_PROFILE_DVD_PLUS_R 0x001B --#define MMC_PROFILE_DVD_PLUS_RW_DL 0x002A --#define MMC_PROFILE_DVD_PLUS_R_DL 0x002B --#define MMC_PROFILE_BD_ROM 0x0040 --#define MMC_PROFILE_BD_R_SRM 0x0041 --#define MMC_PROFILE_BD_R_RRM 0x0042 --#define MMC_PROFILE_BD_RE 0x0043 --#define MMC_PROFILE_HDDVD_ROM 0x0050 --#define MMC_PROFILE_HDDVD_R 0x0051 --#define MMC_PROFILE_HDDVD_RAM 0x0052 --#define MMC_PROFILE_HDDVD_RW 0x0053 --#define MMC_PROFILE_HDDVD_R_DL 0x0058 --#define MMC_PROFILE_HDDVD_RW_DL 0x005A --#define MMC_PROFILE_INVALID 0xFFFF -- --#endif -diff --git a/include/hw/ide/internal.h b/include/hw/ide/internal.h -index f1aca72..41cd42d 100644 ---- a/include/hw/ide/internal.h -+++ b/include/hw/ide/internal.h -@@ -11,7 +11,7 @@ - #include "sysemu/dma.h" - #include "sysemu/sysemu.h" - #include "hw/block/block.h" --#include "block/scsi.h" -+#include "scsi/constants.h" - - /* debug IDE devices */ - //#define DEBUG_IDE -diff --git a/include/scsi/constants.h b/include/scsi/constants.h -new file mode 100644 -index 0000000..a141dd7 ---- /dev/null -+++ b/include/scsi/constants.h -@@ -0,0 +1,314 @@ -+/* Copyright (C) 1998, 1999 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library 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 -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with this library; if not, see . -+*/ -+ -+/* -+ * This header file contains public constants and structures used by -+ * the scsi code for linux. -+ */ -+ -+#ifndef BLOCK_SCSI_H -+#define BLOCK_SCSI_H -+ -+/* -+ * SCSI opcodes -+ */ -+ -+#define TEST_UNIT_READY 0x00 -+#define REWIND 0x01 -+#define REQUEST_SENSE 0x03 -+#define FORMAT_UNIT 0x04 -+#define READ_BLOCK_LIMITS 0x05 -+#define INITIALIZE_ELEMENT_STATUS 0x07 -+#define REASSIGN_BLOCKS 0x07 -+#define READ_6 0x08 -+#define WRITE_6 0x0a -+#define SET_CAPACITY 0x0b -+#define READ_REVERSE 0x0f -+#define WRITE_FILEMARKS 0x10 -+#define SPACE 0x11 -+#define INQUIRY 0x12 -+#define RECOVER_BUFFERED_DATA 0x14 -+#define MODE_SELECT 0x15 -+#define RESERVE 0x16 -+#define RELEASE 0x17 -+#define COPY 0x18 -+#define ERASE 0x19 -+#define MODE_SENSE 0x1a -+#define LOAD_UNLOAD 0x1b -+#define SCAN 0x1b -+#define START_STOP 0x1b -+#define RECEIVE_DIAGNOSTIC 0x1c -+#define SEND_DIAGNOSTIC 0x1d -+#define ALLOW_MEDIUM_REMOVAL 0x1e -+#define SET_WINDOW 0x24 -+#define READ_CAPACITY_10 0x25 -+#define GET_WINDOW 0x25 -+#define READ_10 0x28 -+#define WRITE_10 0x2a -+#define SEND 0x2a -+#define SEEK_10 0x2b -+#define LOCATE_10 0x2b -+#define POSITION_TO_ELEMENT 0x2b -+#define WRITE_VERIFY_10 0x2e -+#define VERIFY_10 0x2f -+#define SEARCH_HIGH 0x30 -+#define SEARCH_EQUAL 0x31 -+#define OBJECT_POSITION 0x31 -+#define SEARCH_LOW 0x32 -+#define SET_LIMITS 0x33 -+#define PRE_FETCH 0x34 -+#define READ_POSITION 0x34 -+#define GET_DATA_BUFFER_STATUS 0x34 -+#define SYNCHRONIZE_CACHE 0x35 -+#define LOCK_UNLOCK_CACHE 0x36 -+#define INITIALIZE_ELEMENT_STATUS_WITH_RANGE 0x37 -+#define READ_DEFECT_DATA 0x37 -+#define MEDIUM_SCAN 0x38 -+#define COMPARE 0x39 -+#define COPY_VERIFY 0x3a -+#define WRITE_BUFFER 0x3b -+#define READ_BUFFER 0x3c -+#define UPDATE_BLOCK 0x3d -+#define READ_LONG_10 0x3e -+#define WRITE_LONG_10 0x3f -+#define CHANGE_DEFINITION 0x40 -+#define WRITE_SAME_10 0x41 -+#define UNMAP 0x42 -+#define READ_TOC 0x43 -+#define REPORT_DENSITY_SUPPORT 0x44 -+#define GET_CONFIGURATION 0x46 -+#define SANITIZE 0x48 -+#define GET_EVENT_STATUS_NOTIFICATION 0x4a -+#define LOG_SELECT 0x4c -+#define LOG_SENSE 0x4d -+#define READ_DISC_INFORMATION 0x51 -+#define RESERVE_TRACK 0x53 -+#define MODE_SELECT_10 0x55 -+#define RESERVE_10 0x56 -+#define RELEASE_10 0x57 -+#define MODE_SENSE_10 0x5a -+#define SEND_CUE_SHEET 0x5d -+#define PERSISTENT_RESERVE_IN 0x5e -+#define PERSISTENT_RESERVE_OUT 0x5f -+#define VARLENGTH_CDB 0x7f -+#define WRITE_FILEMARKS_16 0x80 -+#define READ_REVERSE_16 0x81 -+#define ALLOW_OVERWRITE 0x82 -+#define EXTENDED_COPY 0x83 -+#define ATA_PASSTHROUGH_16 0x85 -+#define ACCESS_CONTROL_IN 0x86 -+#define ACCESS_CONTROL_OUT 0x87 -+#define READ_16 0x88 -+#define COMPARE_AND_WRITE 0x89 -+#define WRITE_16 0x8a -+#define WRITE_VERIFY_16 0x8e -+#define VERIFY_16 0x8f -+#define PRE_FETCH_16 0x90 -+#define SPACE_16 0x91 -+#define SYNCHRONIZE_CACHE_16 0x91 -+#define LOCATE_16 0x92 -+#define WRITE_SAME_16 0x93 -+#define ERASE_16 0x93 -+#define SERVICE_ACTION_IN_16 0x9e -+#define WRITE_LONG_16 0x9f -+#define REPORT_LUNS 0xa0 -+#define ATA_PASSTHROUGH_12 0xa1 -+#define MAINTENANCE_IN 0xa3 -+#define MAINTENANCE_OUT 0xa4 -+#define MOVE_MEDIUM 0xa5 -+#define EXCHANGE_MEDIUM 0xa6 -+#define SET_READ_AHEAD 0xa7 -+#define READ_12 0xa8 -+#define WRITE_12 0xaa -+#define SERVICE_ACTION_IN_12 0xab -+#define ERASE_12 0xac -+#define READ_DVD_STRUCTURE 0xad -+#define WRITE_VERIFY_12 0xae -+#define VERIFY_12 0xaf -+#define SEARCH_HIGH_12 0xb0 -+#define SEARCH_EQUAL_12 0xb1 -+#define SEARCH_LOW_12 0xb2 -+#define READ_ELEMENT_STATUS 0xb8 -+#define SEND_VOLUME_TAG 0xb6 -+#define READ_DEFECT_DATA_12 0xb7 -+#define SET_CD_SPEED 0xbb -+#define MECHANISM_STATUS 0xbd -+#define READ_CD 0xbe -+#define SEND_DVD_STRUCTURE 0xbf -+ -+/* -+ * SERVICE ACTION IN subcodes -+ */ -+#define SAI_READ_CAPACITY_16 0x10 -+ -+/* -+ * READ POSITION service action codes -+ */ -+#define SHORT_FORM_BLOCK_ID 0x00 -+#define SHORT_FORM_VENDOR_SPECIFIC 0x01 -+#define LONG_FORM 0x06 -+#define EXTENDED_FORM 0x08 -+ -+/* -+ * SAM Status codes -+ */ -+ -+#define GOOD 0x00 -+#define CHECK_CONDITION 0x02 -+#define CONDITION_GOOD 0x04 -+#define BUSY 0x08 -+#define INTERMEDIATE_GOOD 0x10 -+#define INTERMEDIATE_C_GOOD 0x14 -+#define RESERVATION_CONFLICT 0x18 -+#define COMMAND_TERMINATED 0x22 -+#define TASK_SET_FULL 0x28 -+#define ACA_ACTIVE 0x30 -+#define TASK_ABORTED 0x40 -+ -+#define STATUS_MASK 0x3e -+ -+/* -+ * SENSE KEYS -+ */ -+ -+#define NO_SENSE 0x00 -+#define RECOVERED_ERROR 0x01 -+#define NOT_READY 0x02 -+#define MEDIUM_ERROR 0x03 -+#define HARDWARE_ERROR 0x04 -+#define ILLEGAL_REQUEST 0x05 -+#define UNIT_ATTENTION 0x06 -+#define DATA_PROTECT 0x07 -+#define BLANK_CHECK 0x08 -+#define COPY_ABORTED 0x0a -+#define ABORTED_COMMAND 0x0b -+#define VOLUME_OVERFLOW 0x0d -+#define MISCOMPARE 0x0e -+ -+ -+/* -+ * DEVICE TYPES -+ */ -+ -+#define TYPE_DISK 0x00 -+#define TYPE_TAPE 0x01 -+#define TYPE_PRINTER 0x02 -+#define TYPE_PROCESSOR 0x03 /* HP scanners use this */ -+#define TYPE_WORM 0x04 /* Treated as ROM by our system */ -+#define TYPE_ROM 0x05 -+#define TYPE_SCANNER 0x06 -+#define TYPE_MOD 0x07 /* Magneto-optical disk - -+ * - treated as TYPE_DISK */ -+#define TYPE_MEDIUM_CHANGER 0x08 -+#define TYPE_STORAGE_ARRAY 0x0c /* Storage array device */ -+#define TYPE_ENCLOSURE 0x0d /* Enclosure Services Device */ -+#define TYPE_RBC 0x0e /* Simplified Direct-Access Device */ -+#define TYPE_OSD 0x11 /* Object-storage Device */ -+#define TYPE_WLUN 0x1e /* Well known LUN */ -+#define TYPE_NOT_PRESENT 0x1f -+#define TYPE_INACTIVE 0x20 -+#define TYPE_NO_LUN 0x7f -+ -+/* Mode page codes for mode sense/set */ -+#define MODE_PAGE_R_W_ERROR 0x01 -+#define MODE_PAGE_HD_GEOMETRY 0x04 -+#define MODE_PAGE_FLEXIBLE_DISK_GEOMETRY 0x05 -+#define MODE_PAGE_CACHING 0x08 -+#define MODE_PAGE_AUDIO_CTL 0x0e -+#define MODE_PAGE_POWER 0x1a -+#define MODE_PAGE_FAULT_FAIL 0x1c -+#define MODE_PAGE_TO_PROTECT 0x1d -+#define MODE_PAGE_CAPABILITIES 0x2a -+#define MODE_PAGE_ALLS 0x3f -+/* Not in Mt. Fuji, but in ATAPI 2.6 -- deprecated now in favor -+ * of MODE_PAGE_SENSE_POWER */ -+#define MODE_PAGE_CDROM 0x0d -+ -+/* Event notification classes for GET EVENT STATUS NOTIFICATION */ -+#define GESN_NO_EVENTS 0 -+#define GESN_OPERATIONAL_CHANGE 1 -+#define GESN_POWER_MANAGEMENT 2 -+#define GESN_EXTERNAL_REQUEST 3 -+#define GESN_MEDIA 4 -+#define GESN_MULTIPLE_HOSTS 5 -+#define GESN_DEVICE_BUSY 6 -+ -+/* Event codes for MEDIA event status notification */ -+#define MEC_NO_CHANGE 0 -+#define MEC_EJECT_REQUESTED 1 -+#define MEC_NEW_MEDIA 2 -+#define MEC_MEDIA_REMOVAL 3 /* only for media changers */ -+#define MEC_MEDIA_CHANGED 4 /* only for media changers */ -+#define MEC_BG_FORMAT_COMPLETED 5 /* MRW or DVD+RW b/g format completed */ -+#define MEC_BG_FORMAT_RESTARTED 6 /* MRW or DVD+RW b/g format restarted */ -+ -+#define MS_TRAY_OPEN 1 -+#define MS_MEDIA_PRESENT 2 -+ -+/* -+ * Based on values from but extending CD_MINS -+ * to the maximum common size allowed by the Orange's Book ATIP -+ * -+ * 90 and 99 min CDs are also available but using them as the -+ * upper limit reduces the effectiveness of the heuristic to -+ * detect DVDs burned to less than 25% of their maximum capacity -+ */ -+ -+/* Some generally useful CD-ROM information */ -+#define CD_MINS 80 /* max. minutes per CD */ -+#define CD_SECS 60 /* seconds per minute */ -+#define CD_FRAMES 75 /* frames per second */ -+#define CD_FRAMESIZE 2048 /* bytes per frame, "cooked" mode */ -+#define CD_MAX_BYTES (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE) -+#define CD_MAX_SECTORS (CD_MAX_BYTES / 512) -+ -+/* -+ * The MMC values are not IDE specific and might need to be moved -+ * to a common header if they are also needed for the SCSI emulation -+ */ -+ -+/* Profile list from MMC-6 revision 1 table 91 */ -+#define MMC_PROFILE_NONE 0x0000 -+#define MMC_PROFILE_CD_ROM 0x0008 -+#define MMC_PROFILE_CD_R 0x0009 -+#define MMC_PROFILE_CD_RW 0x000A -+#define MMC_PROFILE_DVD_ROM 0x0010 -+#define MMC_PROFILE_DVD_R_SR 0x0011 -+#define MMC_PROFILE_DVD_RAM 0x0012 -+#define MMC_PROFILE_DVD_RW_RO 0x0013 -+#define MMC_PROFILE_DVD_RW_SR 0x0014 -+#define MMC_PROFILE_DVD_R_DL_SR 0x0015 -+#define MMC_PROFILE_DVD_R_DL_JR 0x0016 -+#define MMC_PROFILE_DVD_RW_DL 0x0017 -+#define MMC_PROFILE_DVD_DDR 0x0018 -+#define MMC_PROFILE_DVD_PLUS_RW 0x001A -+#define MMC_PROFILE_DVD_PLUS_R 0x001B -+#define MMC_PROFILE_DVD_PLUS_RW_DL 0x002A -+#define MMC_PROFILE_DVD_PLUS_R_DL 0x002B -+#define MMC_PROFILE_BD_ROM 0x0040 -+#define MMC_PROFILE_BD_R_SRM 0x0041 -+#define MMC_PROFILE_BD_R_RRM 0x0042 -+#define MMC_PROFILE_BD_RE 0x0043 -+#define MMC_PROFILE_HDDVD_ROM 0x0050 -+#define MMC_PROFILE_HDDVD_R 0x0051 -+#define MMC_PROFILE_HDDVD_RAM 0x0052 -+#define MMC_PROFILE_HDDVD_RW 0x0053 -+#define MMC_PROFILE_HDDVD_R_DL 0x0058 -+#define MMC_PROFILE_HDDVD_RW_DL 0x005A -+#define MMC_PROFILE_INVALID 0xFFFF -+ -+#endif -diff --git a/scsi/utils.c b/scsi/utils.c -index 6ee9f40..fab60bd 100644 ---- a/scsi/utils.c -+++ b/scsi/utils.c -@@ -14,7 +14,7 @@ - */ - - #include "qemu/osdep.h" --#include "block/scsi.h" -+#include "scsi/constants.h" - #include "scsi/utils.h" - #include "qemu/bswap.h" - -diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c -index 87a3b6e..082d323 100644 ---- a/tests/virtio-scsi-test.c -+++ b/tests/virtio-scsi-test.c -@@ -10,7 +10,7 @@ - - #include "qemu/osdep.h" - #include "libqtest.h" --#include "block/scsi.h" -+#include "scsi/constants.h" - #include "libqos/libqos-pc.h" - #include "libqos/libqos-spapr.h" - #include "libqos/virtio.h" --- -1.8.3.1 - diff --git a/SOURCES/kvm-scsi-move-non-emulation-specific-code-to-scsi.patch b/SOURCES/kvm-scsi-move-non-emulation-specific-code-to-scsi.patch deleted file mode 100644 index 7fbf795..0000000 --- a/SOURCES/kvm-scsi-move-non-emulation-specific-code-to-scsi.patch +++ /dev/null @@ -1,1445 +0,0 @@ -From a5ba8413e64d791d33b24a0ad7475d223e5607b6 Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Sat, 2 Dec 2017 12:19:44 +0100 -Subject: [PATCH 18/36] scsi: move non-emulation specific code to scsi/ -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Paolo Bonzini -Message-id: <20171202121953.13317-9-pbonzini@redhat.com> -Patchwork-id: 78081 -O-Subject: [RHEL7.4 qemu-kvm-rhev PATCH 08/17] scsi: move non-emulation specific code to scsi/ -Bugzilla: 1464908 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: John Snow - -util/scsi.c includes some SCSI code that is shared by block/iscsi.c and -hw/scsi, but the introduction of the persistent reservation helper -will add many more instances of this. There is also include/block/scsi.h, -which actually is not part of the core block layer. - -The persistent reservation manager will also need a home. A scsi/ -directory provides one for both the aforementioned shared code and -the PR manager code. - -Reviewed-by: Philippe Mathieu-Daudé -Signed-off-by: Paolo Bonzini -(cherry picked from commit e5b5728cd330f533e02e483af8973ad7ffccce8b) -Signed-off-by: Miroslav Rezanina ---- - MAINTAINERS | 7 + - Makefile.objs | 2 +- - block/iscsi.c | 6 +- - hw/scsi/scsi-bus.c | 397 --------------------------------------- - hw/scsi/scsi-generic.c | 8 - - include/block/scsi.h | 2 - - include/hw/scsi/scsi.h | 94 +--------- - include/scsi/scsi.h | 20 -- - include/scsi/utils.h | 119 ++++++++++++ - scsi/Makefile.objs | 1 + - scsi/utils.c | 492 +++++++++++++++++++++++++++++++++++++++++++++++++ - util/Makefile.objs | 1 - - util/scsi.c | 90 --------- - 13 files changed, 626 insertions(+), 613 deletions(-) - delete mode 100644 include/scsi/scsi.h - create mode 100644 include/scsi/utils.h - create mode 100644 scsi/Makefile.objs - create mode 100644 scsi/utils.c - delete mode 100644 util/scsi.c - -diff --git a/MAINTAINERS b/MAINTAINERS -index 2a4e503..074da8c 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -1215,6 +1215,13 @@ F: migration/block* - F: include/block/aio.h - T: git git://github.com/stefanha/qemu.git block - -+Block SCSI subsystem -+M: Paolo Bonzini -+L: qemu-block@nongnu.org -+S: Supported -+F: include/scsi/* -+F: scsi/* -+ - Block Jobs - M: Jeff Cody - L: qemu-block@nongnu.org -diff --git a/Makefile.objs b/Makefile.objs -index 24a4ea0..f68aa3b 100644 ---- a/Makefile.objs -+++ b/Makefile.objs -@@ -11,7 +11,7 @@ chardev-obj-y = chardev/ - - block-obj-y += nbd/ - block-obj-y += block.o blockjob.o --block-obj-y += block/ -+block-obj-y += block/ scsi/ - block-obj-y += qemu-io-cmds.o - block-obj-$(CONFIG_REPLICATION) += replication.o - -diff --git a/block/iscsi.c b/block/iscsi.c -index 4bed63c..40adc3c 100644 ---- a/block/iscsi.c -+++ b/block/iscsi.c -@@ -40,10 +40,14 @@ - #include "qmp-commands.h" - #include "qapi/qmp/qstring.h" - #include "crypto/secret.h" --#include "scsi/scsi.h" -+#include "scsi/utils.h" - -+/* Conflict between scsi/utils.h and libiscsi! :( */ -+#define SCSI_XFER_NONE ISCSI_XFER_NONE - #include - #include -+#undef SCSI_XFER_NONE -+QEMU_BUILD_BUG_ON((int)SCSI_XFER_NONE != (int)ISCSI_XFER_NONE); - - #ifdef __linux__ - #include -diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c -index 256610a..635cdf6 100644 ---- a/hw/scsi/scsi-bus.c -+++ b/hw/scsi/scsi-bus.c -@@ -964,36 +964,6 @@ static int ata_passthrough_16_xfer(SCSIDevice *dev, uint8_t *buf) - return xfer * unit; - } - --uint32_t scsi_data_cdb_xfer(uint8_t *buf) --{ -- if ((buf[0] >> 5) == 0 && buf[4] == 0) { -- return 256; -- } else { -- return scsi_cdb_xfer(buf); -- } --} -- --uint32_t scsi_cdb_xfer(uint8_t *buf) --{ -- switch (buf[0] >> 5) { -- case 0: -- return buf[4]; -- break; -- case 1: -- case 2: -- return lduw_be_p(&buf[7]); -- break; -- case 4: -- return ldl_be_p(&buf[10]) & 0xffffffffULL; -- break; -- case 5: -- return ldl_be_p(&buf[6]) & 0xffffffffULL; -- break; -- default: -- return -1; -- } --} -- - static int scsi_req_xfer(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) - { - cmd->xfer = scsi_cdb_xfer(buf); -@@ -1306,53 +1276,6 @@ static void scsi_cmd_xfer_mode(SCSICommand *cmd) - } - } - --static uint64_t scsi_cmd_lba(SCSICommand *cmd) --{ -- uint8_t *buf = cmd->buf; -- uint64_t lba; -- -- switch (buf[0] >> 5) { -- case 0: -- lba = ldl_be_p(&buf[0]) & 0x1fffff; -- break; -- case 1: -- case 2: -- case 5: -- lba = ldl_be_p(&buf[2]) & 0xffffffffULL; -- break; -- case 4: -- lba = ldq_be_p(&buf[2]); -- break; -- default: -- lba = -1; -- -- } -- return lba; --} -- --int scsi_cdb_length(uint8_t *buf) { -- int cdb_len; -- -- switch (buf[0] >> 5) { -- case 0: -- cdb_len = 6; -- break; -- case 1: -- case 2: -- cdb_len = 10; -- break; -- case 4: -- cdb_len = 16; -- break; -- case 5: -- cdb_len = 12; -- break; -- default: -- cdb_len = -1; -- } -- return cdb_len; --} -- - int scsi_req_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf) - { - int rc; -@@ -1399,326 +1322,6 @@ void scsi_device_report_change(SCSIDevice *dev, SCSISense sense) - } - } - --/* -- * Predefined sense codes -- */ -- --/* No sense data available */ --const struct SCSISense sense_code_NO_SENSE = { -- .key = NO_SENSE , .asc = 0x00 , .ascq = 0x00 --}; -- --/* LUN not ready, Manual intervention required */ --const struct SCSISense sense_code_LUN_NOT_READY = { -- .key = NOT_READY, .asc = 0x04, .ascq = 0x03 --}; -- --/* LUN not ready, Medium not present */ --const struct SCSISense sense_code_NO_MEDIUM = { -- .key = NOT_READY, .asc = 0x3a, .ascq = 0x00 --}; -- --/* LUN not ready, medium removal prevented */ --const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = { -- .key = NOT_READY, .asc = 0x53, .ascq = 0x02 --}; -- --/* Hardware error, internal target failure */ --const struct SCSISense sense_code_TARGET_FAILURE = { -- .key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00 --}; -- --/* Illegal request, invalid command operation code */ --const struct SCSISense sense_code_INVALID_OPCODE = { -- .key = ILLEGAL_REQUEST, .asc = 0x20, .ascq = 0x00 --}; -- --/* Illegal request, LBA out of range */ --const struct SCSISense sense_code_LBA_OUT_OF_RANGE = { -- .key = ILLEGAL_REQUEST, .asc = 0x21, .ascq = 0x00 --}; -- --/* Illegal request, Invalid field in CDB */ --const struct SCSISense sense_code_INVALID_FIELD = { -- .key = ILLEGAL_REQUEST, .asc = 0x24, .ascq = 0x00 --}; -- --/* Illegal request, Invalid field in parameter list */ --const struct SCSISense sense_code_INVALID_PARAM = { -- .key = ILLEGAL_REQUEST, .asc = 0x26, .ascq = 0x00 --}; -- --/* Illegal request, Parameter list length error */ --const struct SCSISense sense_code_INVALID_PARAM_LEN = { -- .key = ILLEGAL_REQUEST, .asc = 0x1a, .ascq = 0x00 --}; -- --/* Illegal request, LUN not supported */ --const struct SCSISense sense_code_LUN_NOT_SUPPORTED = { -- .key = ILLEGAL_REQUEST, .asc = 0x25, .ascq = 0x00 --}; -- --/* Illegal request, Saving parameters not supported */ --const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED = { -- .key = ILLEGAL_REQUEST, .asc = 0x39, .ascq = 0x00 --}; -- --/* Illegal request, Incompatible medium installed */ --const struct SCSISense sense_code_INCOMPATIBLE_FORMAT = { -- .key = ILLEGAL_REQUEST, .asc = 0x30, .ascq = 0x00 --}; -- --/* Illegal request, medium removal prevented */ --const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = { -- .key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x02 --}; -- --/* Illegal request, Invalid Transfer Tag */ --const struct SCSISense sense_code_INVALID_TAG = { -- .key = ILLEGAL_REQUEST, .asc = 0x4b, .ascq = 0x01 --}; -- --/* Command aborted, I/O process terminated */ --const struct SCSISense sense_code_IO_ERROR = { -- .key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06 --}; -- --/* Command aborted, I_T Nexus loss occurred */ --const struct SCSISense sense_code_I_T_NEXUS_LOSS = { -- .key = ABORTED_COMMAND, .asc = 0x29, .ascq = 0x07 --}; -- --/* Command aborted, Logical Unit failure */ --const struct SCSISense sense_code_LUN_FAILURE = { -- .key = ABORTED_COMMAND, .asc = 0x3e, .ascq = 0x01 --}; -- --/* Command aborted, Overlapped Commands Attempted */ --const struct SCSISense sense_code_OVERLAPPED_COMMANDS = { -- .key = ABORTED_COMMAND, .asc = 0x4e, .ascq = 0x00 --}; -- --/* Unit attention, Capacity data has changed */ --const struct SCSISense sense_code_CAPACITY_CHANGED = { -- .key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09 --}; -- --/* Unit attention, Power on, reset or bus device reset occurred */ --const struct SCSISense sense_code_RESET = { -- .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00 --}; -- --/* Unit attention, No medium */ --const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = { -- .key = UNIT_ATTENTION, .asc = 0x3a, .ascq = 0x00 --}; -- --/* Unit attention, Medium may have changed */ --const struct SCSISense sense_code_MEDIUM_CHANGED = { -- .key = UNIT_ATTENTION, .asc = 0x28, .ascq = 0x00 --}; -- --/* Unit attention, Reported LUNs data has changed */ --const struct SCSISense sense_code_REPORTED_LUNS_CHANGED = { -- .key = UNIT_ATTENTION, .asc = 0x3f, .ascq = 0x0e --}; -- --/* Unit attention, Device internal reset */ --const struct SCSISense sense_code_DEVICE_INTERNAL_RESET = { -- .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x04 --}; -- --/* Data Protection, Write Protected */ --const struct SCSISense sense_code_WRITE_PROTECTED = { -- .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x00 --}; -- --/* Data Protection, Space Allocation Failed Write Protect */ --const struct SCSISense sense_code_SPACE_ALLOC_FAILED = { -- .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x07 --}; -- --/* -- * scsi_convert_sense -- * -- * Convert between fixed and descriptor sense buffers -- */ --int scsi_convert_sense(uint8_t *in_buf, int in_len, -- uint8_t *buf, int len, bool fixed) --{ -- bool fixed_in; -- SCSISense sense; -- if (!fixed && len < 8) { -- return 0; -- } -- -- if (in_len == 0) { -- sense.key = NO_SENSE; -- sense.asc = 0; -- sense.ascq = 0; -- } else { -- fixed_in = (in_buf[0] & 2) == 0; -- -- if (fixed == fixed_in) { -- memcpy(buf, in_buf, MIN(len, in_len)); -- return MIN(len, in_len); -- } -- -- if (fixed_in) { -- sense.key = in_buf[2]; -- sense.asc = in_buf[12]; -- sense.ascq = in_buf[13]; -- } else { -- sense.key = in_buf[1]; -- sense.asc = in_buf[2]; -- sense.ascq = in_buf[3]; -- } -- } -- -- memset(buf, 0, len); -- if (fixed) { -- /* Return fixed format sense buffer */ -- buf[0] = 0x70; -- buf[2] = sense.key; -- buf[7] = 10; -- buf[12] = sense.asc; -- buf[13] = sense.ascq; -- return MIN(len, SCSI_SENSE_LEN); -- } else { -- /* Return descriptor format sense buffer */ -- buf[0] = 0x72; -- buf[1] = sense.key; -- buf[2] = sense.asc; -- buf[3] = sense.ascq; -- return 8; -- } --} -- --const char *scsi_command_name(uint8_t cmd) --{ -- static const char *names[] = { -- [ TEST_UNIT_READY ] = "TEST_UNIT_READY", -- [ REWIND ] = "REWIND", -- [ REQUEST_SENSE ] = "REQUEST_SENSE", -- [ FORMAT_UNIT ] = "FORMAT_UNIT", -- [ READ_BLOCK_LIMITS ] = "READ_BLOCK_LIMITS", -- [ REASSIGN_BLOCKS ] = "REASSIGN_BLOCKS/INITIALIZE ELEMENT STATUS", -- /* LOAD_UNLOAD and INITIALIZE_ELEMENT_STATUS use the same operation code */ -- [ READ_6 ] = "READ_6", -- [ WRITE_6 ] = "WRITE_6", -- [ SET_CAPACITY ] = "SET_CAPACITY", -- [ READ_REVERSE ] = "READ_REVERSE", -- [ WRITE_FILEMARKS ] = "WRITE_FILEMARKS", -- [ SPACE ] = "SPACE", -- [ INQUIRY ] = "INQUIRY", -- [ RECOVER_BUFFERED_DATA ] = "RECOVER_BUFFERED_DATA", -- [ MAINTENANCE_IN ] = "MAINTENANCE_IN", -- [ MAINTENANCE_OUT ] = "MAINTENANCE_OUT", -- [ MODE_SELECT ] = "MODE_SELECT", -- [ RESERVE ] = "RESERVE", -- [ RELEASE ] = "RELEASE", -- [ COPY ] = "COPY", -- [ ERASE ] = "ERASE", -- [ MODE_SENSE ] = "MODE_SENSE", -- [ START_STOP ] = "START_STOP/LOAD_UNLOAD", -- /* LOAD_UNLOAD and START_STOP use the same operation code */ -- [ RECEIVE_DIAGNOSTIC ] = "RECEIVE_DIAGNOSTIC", -- [ SEND_DIAGNOSTIC ] = "SEND_DIAGNOSTIC", -- [ ALLOW_MEDIUM_REMOVAL ] = "ALLOW_MEDIUM_REMOVAL", -- [ READ_CAPACITY_10 ] = "READ_CAPACITY_10", -- [ READ_10 ] = "READ_10", -- [ WRITE_10 ] = "WRITE_10", -- [ SEEK_10 ] = "SEEK_10/POSITION_TO_ELEMENT", -- /* SEEK_10 and POSITION_TO_ELEMENT use the same operation code */ -- [ WRITE_VERIFY_10 ] = "WRITE_VERIFY_10", -- [ VERIFY_10 ] = "VERIFY_10", -- [ SEARCH_HIGH ] = "SEARCH_HIGH", -- [ SEARCH_EQUAL ] = "SEARCH_EQUAL", -- [ SEARCH_LOW ] = "SEARCH_LOW", -- [ SET_LIMITS ] = "SET_LIMITS", -- [ PRE_FETCH ] = "PRE_FETCH/READ_POSITION", -- /* READ_POSITION and PRE_FETCH use the same operation code */ -- [ SYNCHRONIZE_CACHE ] = "SYNCHRONIZE_CACHE", -- [ LOCK_UNLOCK_CACHE ] = "LOCK_UNLOCK_CACHE", -- [ READ_DEFECT_DATA ] = "READ_DEFECT_DATA/INITIALIZE_ELEMENT_STATUS_WITH_RANGE", -- /* READ_DEFECT_DATA and INITIALIZE_ELEMENT_STATUS_WITH_RANGE use the same operation code */ -- [ MEDIUM_SCAN ] = "MEDIUM_SCAN", -- [ COMPARE ] = "COMPARE", -- [ COPY_VERIFY ] = "COPY_VERIFY", -- [ WRITE_BUFFER ] = "WRITE_BUFFER", -- [ READ_BUFFER ] = "READ_BUFFER", -- [ UPDATE_BLOCK ] = "UPDATE_BLOCK", -- [ READ_LONG_10 ] = "READ_LONG_10", -- [ WRITE_LONG_10 ] = "WRITE_LONG_10", -- [ CHANGE_DEFINITION ] = "CHANGE_DEFINITION", -- [ WRITE_SAME_10 ] = "WRITE_SAME_10", -- [ UNMAP ] = "UNMAP", -- [ READ_TOC ] = "READ_TOC", -- [ REPORT_DENSITY_SUPPORT ] = "REPORT_DENSITY_SUPPORT", -- [ SANITIZE ] = "SANITIZE", -- [ GET_CONFIGURATION ] = "GET_CONFIGURATION", -- [ LOG_SELECT ] = "LOG_SELECT", -- [ LOG_SENSE ] = "LOG_SENSE", -- [ MODE_SELECT_10 ] = "MODE_SELECT_10", -- [ RESERVE_10 ] = "RESERVE_10", -- [ RELEASE_10 ] = "RELEASE_10", -- [ MODE_SENSE_10 ] = "MODE_SENSE_10", -- [ PERSISTENT_RESERVE_IN ] = "PERSISTENT_RESERVE_IN", -- [ PERSISTENT_RESERVE_OUT ] = "PERSISTENT_RESERVE_OUT", -- [ WRITE_FILEMARKS_16 ] = "WRITE_FILEMARKS_16", -- [ EXTENDED_COPY ] = "EXTENDED_COPY", -- [ ATA_PASSTHROUGH_16 ] = "ATA_PASSTHROUGH_16", -- [ ACCESS_CONTROL_IN ] = "ACCESS_CONTROL_IN", -- [ ACCESS_CONTROL_OUT ] = "ACCESS_CONTROL_OUT", -- [ READ_16 ] = "READ_16", -- [ COMPARE_AND_WRITE ] = "COMPARE_AND_WRITE", -- [ WRITE_16 ] = "WRITE_16", -- [ WRITE_VERIFY_16 ] = "WRITE_VERIFY_16", -- [ VERIFY_16 ] = "VERIFY_16", -- [ PRE_FETCH_16 ] = "PRE_FETCH_16", -- [ SYNCHRONIZE_CACHE_16 ] = "SPACE_16/SYNCHRONIZE_CACHE_16", -- /* SPACE_16 and SYNCHRONIZE_CACHE_16 use the same operation code */ -- [ LOCATE_16 ] = "LOCATE_16", -- [ WRITE_SAME_16 ] = "ERASE_16/WRITE_SAME_16", -- /* ERASE_16 and WRITE_SAME_16 use the same operation code */ -- [ SERVICE_ACTION_IN_16 ] = "SERVICE_ACTION_IN_16", -- [ WRITE_LONG_16 ] = "WRITE_LONG_16", -- [ REPORT_LUNS ] = "REPORT_LUNS", -- [ ATA_PASSTHROUGH_12 ] = "BLANK/ATA_PASSTHROUGH_12", -- [ MOVE_MEDIUM ] = "MOVE_MEDIUM", -- [ EXCHANGE_MEDIUM ] = "EXCHANGE MEDIUM", -- [ READ_12 ] = "READ_12", -- [ WRITE_12 ] = "WRITE_12", -- [ ERASE_12 ] = "ERASE_12/GET_PERFORMANCE", -- /* ERASE_12 and GET_PERFORMANCE use the same operation code */ -- [ SERVICE_ACTION_IN_12 ] = "SERVICE_ACTION_IN_12", -- [ WRITE_VERIFY_12 ] = "WRITE_VERIFY_12", -- [ VERIFY_12 ] = "VERIFY_12", -- [ SEARCH_HIGH_12 ] = "SEARCH_HIGH_12", -- [ SEARCH_EQUAL_12 ] = "SEARCH_EQUAL_12", -- [ SEARCH_LOW_12 ] = "SEARCH_LOW_12", -- [ READ_ELEMENT_STATUS ] = "READ_ELEMENT_STATUS", -- [ SEND_VOLUME_TAG ] = "SEND_VOLUME_TAG/SET_STREAMING", -- /* SEND_VOLUME_TAG and SET_STREAMING use the same operation code */ -- [ READ_CD ] = "READ_CD", -- [ READ_DEFECT_DATA_12 ] = "READ_DEFECT_DATA_12", -- [ READ_DVD_STRUCTURE ] = "READ_DVD_STRUCTURE", -- [ RESERVE_TRACK ] = "RESERVE_TRACK", -- [ SEND_CUE_SHEET ] = "SEND_CUE_SHEET", -- [ SEND_DVD_STRUCTURE ] = "SEND_DVD_STRUCTURE", -- [ SET_CD_SPEED ] = "SET_CD_SPEED", -- [ SET_READ_AHEAD ] = "SET_READ_AHEAD", -- [ ALLOW_OVERWRITE ] = "ALLOW_OVERWRITE", -- [ MECHANISM_STATUS ] = "MECHANISM_STATUS", -- [ GET_EVENT_STATUS_NOTIFICATION ] = "GET_EVENT_STATUS_NOTIFICATION", -- [ READ_DISC_INFORMATION ] = "READ_DISC_INFORMATION", -- }; -- -- if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL) -- return "*UNKNOWN*"; -- return names[cmd]; --} -- - SCSIRequest *scsi_req_ref(SCSIRequest *req) - { - assert(req->refcount > 0); -diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c -index 7e1cbab..7a8f500 100644 ---- a/hw/scsi/scsi-generic.c -+++ b/hw/scsi/scsi-generic.c -@@ -36,14 +36,6 @@ do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0) - #include - #include "block/scsi.h" - --#define SG_ERR_DRIVER_TIMEOUT 0x06 --#define SG_ERR_DRIVER_SENSE 0x08 -- --#define SG_ERR_DID_OK 0x00 --#define SG_ERR_DID_NO_CONNECT 0x01 --#define SG_ERR_DID_BUS_BUSY 0x02 --#define SG_ERR_DID_TIME_OUT 0x03 -- - #ifndef MAX_UINT - #define MAX_UINT ((unsigned int)-1) - #endif -diff --git a/include/block/scsi.h b/include/block/scsi.h -index cdf0a58..a141dd7 100644 ---- a/include/block/scsi.h -+++ b/include/block/scsi.h -@@ -150,8 +150,6 @@ - #define READ_CD 0xbe - #define SEND_DVD_STRUCTURE 0xbf - --const char *scsi_command_name(uint8_t cmd); -- - /* - * SERVICE ACTION IN subcodes - */ -diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h -index 6ef67fb..23a8ee6 100644 ---- a/include/hw/scsi/scsi.h -+++ b/include/hw/scsi/scsi.h -@@ -4,45 +4,20 @@ - #include "hw/qdev.h" - #include "hw/block/block.h" - #include "sysemu/sysemu.h" -+#include "scsi/utils.h" - #include "qemu/notify.h" - - #define MAX_SCSI_DEVS 255 - --#define SCSI_CMD_BUF_SIZE 16 --#define SCSI_SENSE_LEN 18 --#define SCSI_SENSE_LEN_SCANNER 32 --#define SCSI_INQUIRY_LEN 36 -- - typedef struct SCSIBus SCSIBus; - typedef struct SCSIBusInfo SCSIBusInfo; --typedef struct SCSICommand SCSICommand; - typedef struct SCSIDevice SCSIDevice; - typedef struct SCSIRequest SCSIRequest; - typedef struct SCSIReqOps SCSIReqOps; - --enum SCSIXferMode { -- SCSI_XFER_NONE, /* TEST_UNIT_READY, ... */ -- SCSI_XFER_FROM_DEV, /* READ, INQUIRY, MODE_SENSE, ... */ -- SCSI_XFER_TO_DEV, /* WRITE, MODE_SELECT, ... */ --}; -- --typedef struct SCSISense { -- uint8_t key; -- uint8_t asc; -- uint8_t ascq; --} SCSISense; -- - #define SCSI_SENSE_BUF_SIZE_OLD 96 - #define SCSI_SENSE_BUF_SIZE 252 - --struct SCSICommand { -- uint8_t buf[SCSI_CMD_BUF_SIZE]; -- int len; -- size_t xfer; -- uint64_t lba; -- enum SCSIXferMode mode; --}; -- - struct SCSIRequest { - SCSIBus *bus; - SCSIDevice *dev; -@@ -180,73 +155,6 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk, - void scsi_bus_legacy_handle_cmdline(SCSIBus *bus, bool deprecated); - void scsi_legacy_handle_cmdline(void); - --/* -- * Predefined sense codes -- */ -- --/* No sense data available */ --extern const struct SCSISense sense_code_NO_SENSE; --/* LUN not ready, Manual intervention required */ --extern const struct SCSISense sense_code_LUN_NOT_READY; --/* LUN not ready, Medium not present */ --extern const struct SCSISense sense_code_NO_MEDIUM; --/* LUN not ready, medium removal prevented */ --extern const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED; --/* Hardware error, internal target failure */ --extern const struct SCSISense sense_code_TARGET_FAILURE; --/* Illegal request, invalid command operation code */ --extern const struct SCSISense sense_code_INVALID_OPCODE; --/* Illegal request, LBA out of range */ --extern const struct SCSISense sense_code_LBA_OUT_OF_RANGE; --/* Illegal request, Invalid field in CDB */ --extern const struct SCSISense sense_code_INVALID_FIELD; --/* Illegal request, Invalid field in parameter list */ --extern const struct SCSISense sense_code_INVALID_PARAM; --/* Illegal request, Parameter list length error */ --extern const struct SCSISense sense_code_INVALID_PARAM_LEN; --/* Illegal request, LUN not supported */ --extern const struct SCSISense sense_code_LUN_NOT_SUPPORTED; --/* Illegal request, Saving parameters not supported */ --extern const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED; --/* Illegal request, Incompatible format */ --extern const struct SCSISense sense_code_INCOMPATIBLE_FORMAT; --/* Illegal request, medium removal prevented */ --extern const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED; --/* Illegal request, Invalid Transfer Tag */ --extern const struct SCSISense sense_code_INVALID_TAG; --/* Command aborted, I/O process terminated */ --extern const struct SCSISense sense_code_IO_ERROR; --/* Command aborted, I_T Nexus loss occurred */ --extern const struct SCSISense sense_code_I_T_NEXUS_LOSS; --/* Command aborted, Logical Unit failure */ --extern const struct SCSISense sense_code_LUN_FAILURE; --/* Command aborted, Overlapped Commands Attempted */ --extern const struct SCSISense sense_code_OVERLAPPED_COMMANDS; --/* LUN not ready, Capacity data has changed */ --extern const struct SCSISense sense_code_CAPACITY_CHANGED; --/* LUN not ready, Medium not present */ --extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM; --/* Unit attention, Power on, reset or bus device reset occurred */ --extern const struct SCSISense sense_code_RESET; --/* Unit attention, Medium may have changed*/ --extern const struct SCSISense sense_code_MEDIUM_CHANGED; --/* Unit attention, Reported LUNs data has changed */ --extern const struct SCSISense sense_code_REPORTED_LUNS_CHANGED; --/* Unit attention, Device internal reset */ --extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET; --/* Data Protection, Write Protected */ --extern const struct SCSISense sense_code_WRITE_PROTECTED; --/* Data Protection, Space Allocation Failed Write Protect */ --extern const struct SCSISense sense_code_SPACE_ALLOC_FAILED; -- --#define SENSE_CODE(x) sense_code_ ## x -- --uint32_t scsi_data_cdb_xfer(uint8_t *buf); --uint32_t scsi_cdb_xfer(uint8_t *buf); --int scsi_cdb_length(uint8_t *buf); --int scsi_convert_sense(uint8_t *in_buf, int in_len, -- uint8_t *buf, int len, bool fixed); -- - SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d, - uint32_t tag, uint32_t lun, void *hba_private); - SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun, -diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h -deleted file mode 100644 -index fe33038..0000000 ---- a/include/scsi/scsi.h -+++ /dev/null -@@ -1,20 +0,0 @@ --/* -- * SCSI helpers -- * -- * Copyright 2017 Red Hat, Inc. -- * -- * Authors: -- * Fam Zheng -- * -- * 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. -- */ --#ifndef QEMU_SCSI_H --#define QEMU_SCSI_H -- --int scsi_sense_to_errno(int key, int asc, int ascq); --int scsi_sense_buf_to_errno(const uint8_t *sense, size_t sense_size); -- --#endif -diff --git a/include/scsi/utils.h b/include/scsi/utils.h -new file mode 100644 -index 0000000..90bf4dc ---- /dev/null -+++ b/include/scsi/utils.h -@@ -0,0 +1,119 @@ -+#ifndef SCSI_UTILS_H -+#define SCSI_UTILS_H 1 -+ -+#ifdef CONFIG_LINUX -+#include -+#endif -+ -+#define SCSI_CMD_BUF_SIZE 16 -+#define SCSI_SENSE_LEN 18 -+#define SCSI_SENSE_LEN_SCANNER 32 -+#define SCSI_INQUIRY_LEN 36 -+ -+enum SCSIXferMode { -+ SCSI_XFER_NONE, /* TEST_UNIT_READY, ... */ -+ SCSI_XFER_FROM_DEV, /* READ, INQUIRY, MODE_SENSE, ... */ -+ SCSI_XFER_TO_DEV, /* WRITE, MODE_SELECT, ... */ -+}; -+ -+typedef struct SCSICommand { -+ uint8_t buf[SCSI_CMD_BUF_SIZE]; -+ int len; -+ size_t xfer; -+ uint64_t lba; -+ enum SCSIXferMode mode; -+} SCSICommand; -+ -+typedef struct SCSISense { -+ uint8_t key; -+ uint8_t asc; -+ uint8_t ascq; -+} SCSISense; -+ -+/* -+ * Predefined sense codes -+ */ -+ -+/* No sense data available */ -+extern const struct SCSISense sense_code_NO_SENSE; -+/* LUN not ready, Manual intervention required */ -+extern const struct SCSISense sense_code_LUN_NOT_READY; -+/* LUN not ready, Medium not present */ -+extern const struct SCSISense sense_code_NO_MEDIUM; -+/* LUN not ready, medium removal prevented */ -+extern const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED; -+/* Hardware error, internal target failure */ -+extern const struct SCSISense sense_code_TARGET_FAILURE; -+/* Illegal request, invalid command operation code */ -+extern const struct SCSISense sense_code_INVALID_OPCODE; -+/* Illegal request, LBA out of range */ -+extern const struct SCSISense sense_code_LBA_OUT_OF_RANGE; -+/* Illegal request, Invalid field in CDB */ -+extern const struct SCSISense sense_code_INVALID_FIELD; -+/* Illegal request, Invalid field in parameter list */ -+extern const struct SCSISense sense_code_INVALID_PARAM; -+/* Illegal request, Parameter list length error */ -+extern const struct SCSISense sense_code_INVALID_PARAM_LEN; -+/* Illegal request, LUN not supported */ -+extern const struct SCSISense sense_code_LUN_NOT_SUPPORTED; -+/* Illegal request, Saving parameters not supported */ -+extern const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED; -+/* Illegal request, Incompatible format */ -+extern const struct SCSISense sense_code_INCOMPATIBLE_FORMAT; -+/* Illegal request, medium removal prevented */ -+extern const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED; -+/* Illegal request, Invalid Transfer Tag */ -+extern const struct SCSISense sense_code_INVALID_TAG; -+/* Command aborted, I/O process terminated */ -+extern const struct SCSISense sense_code_IO_ERROR; -+/* Command aborted, I_T Nexus loss occurred */ -+extern const struct SCSISense sense_code_I_T_NEXUS_LOSS; -+/* Command aborted, Logical Unit failure */ -+extern const struct SCSISense sense_code_LUN_FAILURE; -+/* Command aborted, Overlapped Commands Attempted */ -+extern const struct SCSISense sense_code_OVERLAPPED_COMMANDS; -+/* LUN not ready, Capacity data has changed */ -+extern const struct SCSISense sense_code_CAPACITY_CHANGED; -+/* LUN not ready, Medium not present */ -+extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM; -+/* Unit attention, Power on, reset or bus device reset occurred */ -+extern const struct SCSISense sense_code_RESET; -+/* Unit attention, Medium may have changed*/ -+extern const struct SCSISense sense_code_MEDIUM_CHANGED; -+/* Unit attention, Reported LUNs data has changed */ -+extern const struct SCSISense sense_code_REPORTED_LUNS_CHANGED; -+/* Unit attention, Device internal reset */ -+extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET; -+/* Data Protection, Write Protected */ -+extern const struct SCSISense sense_code_WRITE_PROTECTED; -+/* Data Protection, Space Allocation Failed Write Protect */ -+extern const struct SCSISense sense_code_SPACE_ALLOC_FAILED; -+ -+#define SENSE_CODE(x) sense_code_ ## x -+ -+int scsi_sense_to_errno(int key, int asc, int ascq); -+int scsi_sense_buf_to_errno(const uint8_t *sense, size_t sense_size); -+ -+int scsi_convert_sense(uint8_t *in_buf, int in_len, -+ uint8_t *buf, int len, bool fixed); -+const char *scsi_command_name(uint8_t cmd); -+ -+uint64_t scsi_cmd_lba(SCSICommand *cmd); -+uint32_t scsi_data_cdb_xfer(uint8_t *buf); -+uint32_t scsi_cdb_xfer(uint8_t *buf); -+int scsi_cdb_length(uint8_t *buf); -+ -+/* Linux SG_IO interface. */ -+#ifdef CONFIG_LINUX -+#define SG_ERR_DRIVER_TIMEOUT 0x06 -+#define SG_ERR_DRIVER_SENSE 0x08 -+ -+#define SG_ERR_DID_OK 0x00 -+#define SG_ERR_DID_NO_CONNECT 0x01 -+#define SG_ERR_DID_BUS_BUSY 0x02 -+#define SG_ERR_DID_TIME_OUT 0x03 -+ -+#define SG_ERR_DRIVER_SENSE 0x08 -+#endif -+ -+#endif -diff --git a/scsi/Makefile.objs b/scsi/Makefile.objs -new file mode 100644 -index 0000000..31b82a5 ---- /dev/null -+++ b/scsi/Makefile.objs -@@ -0,0 +1 @@ -+block-obj-y += utils.o -diff --git a/scsi/utils.c b/scsi/utils.c -new file mode 100644 -index 0000000..2327e06 ---- /dev/null -+++ b/scsi/utils.c -@@ -0,0 +1,492 @@ -+/* -+ * SCSI helpers -+ * -+ * Copyright 2017 Red Hat, Inc. -+ * -+ * Authors: -+ * Fam Zheng -+ * Paolo Bonzini -+ * -+ * 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. -+ */ -+ -+#include "qemu/osdep.h" -+#include "block/scsi.h" -+#include "scsi/utils.h" -+#include "qemu/bswap.h" -+ -+uint32_t scsi_data_cdb_xfer(uint8_t *buf) -+{ -+ if ((buf[0] >> 5) == 0 && buf[4] == 0) { -+ return 256; -+ } else { -+ return scsi_cdb_xfer(buf); -+ } -+} -+ -+uint32_t scsi_cdb_xfer(uint8_t *buf) -+{ -+ switch (buf[0] >> 5) { -+ case 0: -+ return buf[4]; -+ break; -+ case 1: -+ case 2: -+ return lduw_be_p(&buf[7]); -+ break; -+ case 4: -+ return ldl_be_p(&buf[10]) & 0xffffffffULL; -+ break; -+ case 5: -+ return ldl_be_p(&buf[6]) & 0xffffffffULL; -+ break; -+ default: -+ return -1; -+ } -+} -+ -+uint64_t scsi_cmd_lba(SCSICommand *cmd) -+{ -+ uint8_t *buf = cmd->buf; -+ uint64_t lba; -+ -+ switch (buf[0] >> 5) { -+ case 0: -+ lba = ldl_be_p(&buf[0]) & 0x1fffff; -+ break; -+ case 1: -+ case 2: -+ case 5: -+ lba = ldl_be_p(&buf[2]) & 0xffffffffULL; -+ break; -+ case 4: -+ lba = ldq_be_p(&buf[2]); -+ break; -+ default: -+ lba = -1; -+ -+ } -+ return lba; -+} -+ -+int scsi_cdb_length(uint8_t *buf) -+{ -+ int cdb_len; -+ -+ switch (buf[0] >> 5) { -+ case 0: -+ cdb_len = 6; -+ break; -+ case 1: -+ case 2: -+ cdb_len = 10; -+ break; -+ case 4: -+ cdb_len = 16; -+ break; -+ case 5: -+ cdb_len = 12; -+ break; -+ default: -+ cdb_len = -1; -+ } -+ return cdb_len; -+} -+ -+/* -+ * Predefined sense codes -+ */ -+ -+/* No sense data available */ -+const struct SCSISense sense_code_NO_SENSE = { -+ .key = NO_SENSE , .asc = 0x00 , .ascq = 0x00 -+}; -+ -+/* LUN not ready, Manual intervention required */ -+const struct SCSISense sense_code_LUN_NOT_READY = { -+ .key = NOT_READY, .asc = 0x04, .ascq = 0x03 -+}; -+ -+/* LUN not ready, Medium not present */ -+const struct SCSISense sense_code_NO_MEDIUM = { -+ .key = NOT_READY, .asc = 0x3a, .ascq = 0x00 -+}; -+ -+/* LUN not ready, medium removal prevented */ -+const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = { -+ .key = NOT_READY, .asc = 0x53, .ascq = 0x02 -+}; -+ -+/* Hardware error, internal target failure */ -+const struct SCSISense sense_code_TARGET_FAILURE = { -+ .key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00 -+}; -+ -+/* Illegal request, invalid command operation code */ -+const struct SCSISense sense_code_INVALID_OPCODE = { -+ .key = ILLEGAL_REQUEST, .asc = 0x20, .ascq = 0x00 -+}; -+ -+/* Illegal request, LBA out of range */ -+const struct SCSISense sense_code_LBA_OUT_OF_RANGE = { -+ .key = ILLEGAL_REQUEST, .asc = 0x21, .ascq = 0x00 -+}; -+ -+/* Illegal request, Invalid field in CDB */ -+const struct SCSISense sense_code_INVALID_FIELD = { -+ .key = ILLEGAL_REQUEST, .asc = 0x24, .ascq = 0x00 -+}; -+ -+/* Illegal request, Invalid field in parameter list */ -+const struct SCSISense sense_code_INVALID_PARAM = { -+ .key = ILLEGAL_REQUEST, .asc = 0x26, .ascq = 0x00 -+}; -+ -+/* Illegal request, Parameter list length error */ -+const struct SCSISense sense_code_INVALID_PARAM_LEN = { -+ .key = ILLEGAL_REQUEST, .asc = 0x1a, .ascq = 0x00 -+}; -+ -+/* Illegal request, LUN not supported */ -+const struct SCSISense sense_code_LUN_NOT_SUPPORTED = { -+ .key = ILLEGAL_REQUEST, .asc = 0x25, .ascq = 0x00 -+}; -+ -+/* Illegal request, Saving parameters not supported */ -+const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED = { -+ .key = ILLEGAL_REQUEST, .asc = 0x39, .ascq = 0x00 -+}; -+ -+/* Illegal request, Incompatible medium installed */ -+const struct SCSISense sense_code_INCOMPATIBLE_FORMAT = { -+ .key = ILLEGAL_REQUEST, .asc = 0x30, .ascq = 0x00 -+}; -+ -+/* Illegal request, medium removal prevented */ -+const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = { -+ .key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x02 -+}; -+ -+/* Illegal request, Invalid Transfer Tag */ -+const struct SCSISense sense_code_INVALID_TAG = { -+ .key = ILLEGAL_REQUEST, .asc = 0x4b, .ascq = 0x01 -+}; -+ -+/* Command aborted, I/O process terminated */ -+const struct SCSISense sense_code_IO_ERROR = { -+ .key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06 -+}; -+ -+/* Command aborted, I_T Nexus loss occurred */ -+const struct SCSISense sense_code_I_T_NEXUS_LOSS = { -+ .key = ABORTED_COMMAND, .asc = 0x29, .ascq = 0x07 -+}; -+ -+/* Command aborted, Logical Unit failure */ -+const struct SCSISense sense_code_LUN_FAILURE = { -+ .key = ABORTED_COMMAND, .asc = 0x3e, .ascq = 0x01 -+}; -+ -+/* Command aborted, Overlapped Commands Attempted */ -+const struct SCSISense sense_code_OVERLAPPED_COMMANDS = { -+ .key = ABORTED_COMMAND, .asc = 0x4e, .ascq = 0x00 -+}; -+ -+/* Unit attention, Capacity data has changed */ -+const struct SCSISense sense_code_CAPACITY_CHANGED = { -+ .key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09 -+}; -+ -+/* Unit attention, Power on, reset or bus device reset occurred */ -+const struct SCSISense sense_code_RESET = { -+ .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00 -+}; -+ -+/* Unit attention, No medium */ -+const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = { -+ .key = UNIT_ATTENTION, .asc = 0x3a, .ascq = 0x00 -+}; -+ -+/* Unit attention, Medium may have changed */ -+const struct SCSISense sense_code_MEDIUM_CHANGED = { -+ .key = UNIT_ATTENTION, .asc = 0x28, .ascq = 0x00 -+}; -+ -+/* Unit attention, Reported LUNs data has changed */ -+const struct SCSISense sense_code_REPORTED_LUNS_CHANGED = { -+ .key = UNIT_ATTENTION, .asc = 0x3f, .ascq = 0x0e -+}; -+ -+/* Unit attention, Device internal reset */ -+const struct SCSISense sense_code_DEVICE_INTERNAL_RESET = { -+ .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x04 -+}; -+ -+/* Data Protection, Write Protected */ -+const struct SCSISense sense_code_WRITE_PROTECTED = { -+ .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x00 -+}; -+ -+/* Data Protection, Space Allocation Failed Write Protect */ -+const struct SCSISense sense_code_SPACE_ALLOC_FAILED = { -+ .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x07 -+}; -+ -+/* -+ * scsi_convert_sense -+ * -+ * Convert between fixed and descriptor sense buffers -+ */ -+int scsi_convert_sense(uint8_t *in_buf, int in_len, -+ uint8_t *buf, int len, bool fixed) -+{ -+ bool fixed_in; -+ SCSISense sense; -+ if (!fixed && len < 8) { -+ return 0; -+ } -+ -+ if (in_len == 0) { -+ sense.key = NO_SENSE; -+ sense.asc = 0; -+ sense.ascq = 0; -+ } else { -+ fixed_in = (in_buf[0] & 2) == 0; -+ -+ if (fixed == fixed_in) { -+ memcpy(buf, in_buf, MIN(len, in_len)); -+ return MIN(len, in_len); -+ } -+ -+ if (fixed_in) { -+ sense.key = in_buf[2]; -+ sense.asc = in_buf[12]; -+ sense.ascq = in_buf[13]; -+ } else { -+ sense.key = in_buf[1]; -+ sense.asc = in_buf[2]; -+ sense.ascq = in_buf[3]; -+ } -+ } -+ -+ memset(buf, 0, len); -+ if (fixed) { -+ /* Return fixed format sense buffer */ -+ buf[0] = 0x70; -+ buf[2] = sense.key; -+ buf[7] = 10; -+ buf[12] = sense.asc; -+ buf[13] = sense.ascq; -+ return MIN(len, SCSI_SENSE_LEN); -+ } else { -+ /* Return descriptor format sense buffer */ -+ buf[0] = 0x72; -+ buf[1] = sense.key; -+ buf[2] = sense.asc; -+ buf[3] = sense.ascq; -+ return 8; -+ } -+} -+ -+int scsi_sense_to_errno(int key, int asc, int ascq) -+{ -+ switch (key) { -+ case 0x00: /* NO SENSE */ -+ case 0x01: /* RECOVERED ERROR */ -+ case 0x06: /* UNIT ATTENTION */ -+ /* These sense keys are not errors */ -+ return 0; -+ case 0x0b: /* COMMAND ABORTED */ -+ return ECANCELED; -+ case 0x02: /* NOT READY */ -+ case 0x05: /* ILLEGAL REQUEST */ -+ case 0x07: /* DATA PROTECTION */ -+ /* Parse ASCQ */ -+ break; -+ default: -+ return EIO; -+ } -+ switch ((asc << 8) | ascq) { -+ case 0x1a00: /* PARAMETER LIST LENGTH ERROR */ -+ case 0x2000: /* INVALID OPERATION CODE */ -+ case 0x2400: /* INVALID FIELD IN CDB */ -+ case 0x2600: /* INVALID FIELD IN PARAMETER LIST */ -+ return EINVAL; -+ case 0x2100: /* LBA OUT OF RANGE */ -+ case 0x2707: /* SPACE ALLOC FAILED */ -+ return ENOSPC; -+ case 0x2500: /* LOGICAL UNIT NOT SUPPORTED */ -+ return ENOTSUP; -+ case 0x3a00: /* MEDIUM NOT PRESENT */ -+ case 0x3a01: /* MEDIUM NOT PRESENT TRAY CLOSED */ -+ case 0x3a02: /* MEDIUM NOT PRESENT TRAY OPEN */ -+ return ENOMEDIUM; -+ case 0x2700: /* WRITE PROTECTED */ -+ return EACCES; -+ case 0x0401: /* NOT READY, IN PROGRESS OF BECOMING READY */ -+ return EAGAIN; -+ case 0x0402: /* NOT READY, INITIALIZING COMMAND REQUIRED */ -+ return ENOTCONN; -+ default: -+ return EIO; -+ } -+} -+ -+int scsi_sense_buf_to_errno(const uint8_t *sense, size_t sense_size) -+{ -+ int key, asc, ascq; -+ if (sense_size < 1) { -+ return EIO; -+ } -+ switch (sense[0]) { -+ case 0x70: /* Fixed format sense data. */ -+ if (sense_size < 14) { -+ return EIO; -+ } -+ key = sense[2] & 0xF; -+ asc = sense[12]; -+ ascq = sense[13]; -+ break; -+ case 0x72: /* Descriptor format sense data. */ -+ if (sense_size < 4) { -+ return EIO; -+ } -+ key = sense[1] & 0xF; -+ asc = sense[2]; -+ ascq = sense[3]; -+ break; -+ default: -+ return EIO; -+ break; -+ } -+ return scsi_sense_to_errno(key, asc, ascq); -+} -+ -+const char *scsi_command_name(uint8_t cmd) -+{ -+ static const char *names[] = { -+ [ TEST_UNIT_READY ] = "TEST_UNIT_READY", -+ [ REWIND ] = "REWIND", -+ [ REQUEST_SENSE ] = "REQUEST_SENSE", -+ [ FORMAT_UNIT ] = "FORMAT_UNIT", -+ [ READ_BLOCK_LIMITS ] = "READ_BLOCK_LIMITS", -+ [ REASSIGN_BLOCKS ] = "REASSIGN_BLOCKS/INITIALIZE ELEMENT STATUS", -+ /* LOAD_UNLOAD and INITIALIZE_ELEMENT_STATUS use the same operation code */ -+ [ READ_6 ] = "READ_6", -+ [ WRITE_6 ] = "WRITE_6", -+ [ SET_CAPACITY ] = "SET_CAPACITY", -+ [ READ_REVERSE ] = "READ_REVERSE", -+ [ WRITE_FILEMARKS ] = "WRITE_FILEMARKS", -+ [ SPACE ] = "SPACE", -+ [ INQUIRY ] = "INQUIRY", -+ [ RECOVER_BUFFERED_DATA ] = "RECOVER_BUFFERED_DATA", -+ [ MAINTENANCE_IN ] = "MAINTENANCE_IN", -+ [ MAINTENANCE_OUT ] = "MAINTENANCE_OUT", -+ [ MODE_SELECT ] = "MODE_SELECT", -+ [ RESERVE ] = "RESERVE", -+ [ RELEASE ] = "RELEASE", -+ [ COPY ] = "COPY", -+ [ ERASE ] = "ERASE", -+ [ MODE_SENSE ] = "MODE_SENSE", -+ [ START_STOP ] = "START_STOP/LOAD_UNLOAD", -+ /* LOAD_UNLOAD and START_STOP use the same operation code */ -+ [ RECEIVE_DIAGNOSTIC ] = "RECEIVE_DIAGNOSTIC", -+ [ SEND_DIAGNOSTIC ] = "SEND_DIAGNOSTIC", -+ [ ALLOW_MEDIUM_REMOVAL ] = "ALLOW_MEDIUM_REMOVAL", -+ [ READ_CAPACITY_10 ] = "READ_CAPACITY_10", -+ [ READ_10 ] = "READ_10", -+ [ WRITE_10 ] = "WRITE_10", -+ [ SEEK_10 ] = "SEEK_10/POSITION_TO_ELEMENT", -+ /* SEEK_10 and POSITION_TO_ELEMENT use the same operation code */ -+ [ WRITE_VERIFY_10 ] = "WRITE_VERIFY_10", -+ [ VERIFY_10 ] = "VERIFY_10", -+ [ SEARCH_HIGH ] = "SEARCH_HIGH", -+ [ SEARCH_EQUAL ] = "SEARCH_EQUAL", -+ [ SEARCH_LOW ] = "SEARCH_LOW", -+ [ SET_LIMITS ] = "SET_LIMITS", -+ [ PRE_FETCH ] = "PRE_FETCH/READ_POSITION", -+ /* READ_POSITION and PRE_FETCH use the same operation code */ -+ [ SYNCHRONIZE_CACHE ] = "SYNCHRONIZE_CACHE", -+ [ LOCK_UNLOCK_CACHE ] = "LOCK_UNLOCK_CACHE", -+ [ READ_DEFECT_DATA ] = "READ_DEFECT_DATA/INITIALIZE_ELEMENT_STATUS_WITH_RANGE", -+ /* READ_DEFECT_DATA and INITIALIZE_ELEMENT_STATUS_WITH_RANGE use the same operation code */ -+ [ MEDIUM_SCAN ] = "MEDIUM_SCAN", -+ [ COMPARE ] = "COMPARE", -+ [ COPY_VERIFY ] = "COPY_VERIFY", -+ [ WRITE_BUFFER ] = "WRITE_BUFFER", -+ [ READ_BUFFER ] = "READ_BUFFER", -+ [ UPDATE_BLOCK ] = "UPDATE_BLOCK", -+ [ READ_LONG_10 ] = "READ_LONG_10", -+ [ WRITE_LONG_10 ] = "WRITE_LONG_10", -+ [ CHANGE_DEFINITION ] = "CHANGE_DEFINITION", -+ [ WRITE_SAME_10 ] = "WRITE_SAME_10", -+ [ UNMAP ] = "UNMAP", -+ [ READ_TOC ] = "READ_TOC", -+ [ REPORT_DENSITY_SUPPORT ] = "REPORT_DENSITY_SUPPORT", -+ [ SANITIZE ] = "SANITIZE", -+ [ GET_CONFIGURATION ] = "GET_CONFIGURATION", -+ [ LOG_SELECT ] = "LOG_SELECT", -+ [ LOG_SENSE ] = "LOG_SENSE", -+ [ MODE_SELECT_10 ] = "MODE_SELECT_10", -+ [ RESERVE_10 ] = "RESERVE_10", -+ [ RELEASE_10 ] = "RELEASE_10", -+ [ MODE_SENSE_10 ] = "MODE_SENSE_10", -+ [ PERSISTENT_RESERVE_IN ] = "PERSISTENT_RESERVE_IN", -+ [ PERSISTENT_RESERVE_OUT ] = "PERSISTENT_RESERVE_OUT", -+ [ WRITE_FILEMARKS_16 ] = "WRITE_FILEMARKS_16", -+ [ EXTENDED_COPY ] = "EXTENDED_COPY", -+ [ ATA_PASSTHROUGH_16 ] = "ATA_PASSTHROUGH_16", -+ [ ACCESS_CONTROL_IN ] = "ACCESS_CONTROL_IN", -+ [ ACCESS_CONTROL_OUT ] = "ACCESS_CONTROL_OUT", -+ [ READ_16 ] = "READ_16", -+ [ COMPARE_AND_WRITE ] = "COMPARE_AND_WRITE", -+ [ WRITE_16 ] = "WRITE_16", -+ [ WRITE_VERIFY_16 ] = "WRITE_VERIFY_16", -+ [ VERIFY_16 ] = "VERIFY_16", -+ [ PRE_FETCH_16 ] = "PRE_FETCH_16", -+ [ SYNCHRONIZE_CACHE_16 ] = "SPACE_16/SYNCHRONIZE_CACHE_16", -+ /* SPACE_16 and SYNCHRONIZE_CACHE_16 use the same operation code */ -+ [ LOCATE_16 ] = "LOCATE_16", -+ [ WRITE_SAME_16 ] = "ERASE_16/WRITE_SAME_16", -+ /* ERASE_16 and WRITE_SAME_16 use the same operation code */ -+ [ SERVICE_ACTION_IN_16 ] = "SERVICE_ACTION_IN_16", -+ [ WRITE_LONG_16 ] = "WRITE_LONG_16", -+ [ REPORT_LUNS ] = "REPORT_LUNS", -+ [ ATA_PASSTHROUGH_12 ] = "BLANK/ATA_PASSTHROUGH_12", -+ [ MOVE_MEDIUM ] = "MOVE_MEDIUM", -+ [ EXCHANGE_MEDIUM ] = "EXCHANGE MEDIUM", -+ [ READ_12 ] = "READ_12", -+ [ WRITE_12 ] = "WRITE_12", -+ [ ERASE_12 ] = "ERASE_12/GET_PERFORMANCE", -+ /* ERASE_12 and GET_PERFORMANCE use the same operation code */ -+ [ SERVICE_ACTION_IN_12 ] = "SERVICE_ACTION_IN_12", -+ [ WRITE_VERIFY_12 ] = "WRITE_VERIFY_12", -+ [ VERIFY_12 ] = "VERIFY_12", -+ [ SEARCH_HIGH_12 ] = "SEARCH_HIGH_12", -+ [ SEARCH_EQUAL_12 ] = "SEARCH_EQUAL_12", -+ [ SEARCH_LOW_12 ] = "SEARCH_LOW_12", -+ [ READ_ELEMENT_STATUS ] = "READ_ELEMENT_STATUS", -+ [ SEND_VOLUME_TAG ] = "SEND_VOLUME_TAG/SET_STREAMING", -+ /* SEND_VOLUME_TAG and SET_STREAMING use the same operation code */ -+ [ READ_CD ] = "READ_CD", -+ [ READ_DEFECT_DATA_12 ] = "READ_DEFECT_DATA_12", -+ [ READ_DVD_STRUCTURE ] = "READ_DVD_STRUCTURE", -+ [ RESERVE_TRACK ] = "RESERVE_TRACK", -+ [ SEND_CUE_SHEET ] = "SEND_CUE_SHEET", -+ [ SEND_DVD_STRUCTURE ] = "SEND_DVD_STRUCTURE", -+ [ SET_CD_SPEED ] = "SET_CD_SPEED", -+ [ SET_READ_AHEAD ] = "SET_READ_AHEAD", -+ [ ALLOW_OVERWRITE ] = "ALLOW_OVERWRITE", -+ [ MECHANISM_STATUS ] = "MECHANISM_STATUS", -+ [ GET_EVENT_STATUS_NOTIFICATION ] = "GET_EVENT_STATUS_NOTIFICATION", -+ [ READ_DISC_INFORMATION ] = "READ_DISC_INFORMATION", -+ }; -+ -+ if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL) { -+ return "*UNKNOWN*"; -+ } -+ return names[cmd]; -+} -diff --git a/util/Makefile.objs b/util/Makefile.objs -index c9e6c49..50a55ec 100644 ---- a/util/Makefile.objs -+++ b/util/Makefile.objs -@@ -45,4 +45,3 @@ util-obj-y += qht.o - util-obj-y += range.o - util-obj-y += stats64.o - util-obj-y += systemd.o --util-obj-y += scsi.o -diff --git a/util/scsi.c b/util/scsi.c -deleted file mode 100644 -index 472293d..0000000 ---- a/util/scsi.c -+++ /dev/null -@@ -1,90 +0,0 @@ --/* -- * SCSI helpers -- * -- * Copyright 2017 Red Hat, Inc. -- * -- * Authors: -- * Fam Zheng -- * -- * 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. -- */ -- --#include "qemu/osdep.h" --#include "scsi/scsi.h" -- --int scsi_sense_to_errno(int key, int asc, int ascq) --{ -- switch (key) { -- case 0x00: /* NO SENSE */ -- case 0x01: /* RECOVERED ERROR */ -- case 0x06: /* UNIT ATTENTION */ -- /* These sense keys are not errors */ -- return 0; -- case 0x0b: /* COMMAND ABORTED */ -- return ECANCELED; -- case 0x02: /* NOT READY */ -- case 0x05: /* ILLEGAL REQUEST */ -- case 0x07: /* DATA PROTECTION */ -- /* Parse ASCQ */ -- break; -- default: -- return EIO; -- } -- switch ((asc << 8) | ascq) { -- case 0x1a00: /* PARAMETER LIST LENGTH ERROR */ -- case 0x2000: /* INVALID OPERATION CODE */ -- case 0x2400: /* INVALID FIELD IN CDB */ -- case 0x2600: /* INVALID FIELD IN PARAMETER LIST */ -- return EINVAL; -- case 0x2100: /* LBA OUT OF RANGE */ -- case 0x2707: /* SPACE ALLOC FAILED */ -- return ENOSPC; -- case 0x2500: /* LOGICAL UNIT NOT SUPPORTED */ -- return ENOTSUP; -- case 0x3a00: /* MEDIUM NOT PRESENT */ -- case 0x3a01: /* MEDIUM NOT PRESENT TRAY CLOSED */ -- case 0x3a02: /* MEDIUM NOT PRESENT TRAY OPEN */ -- return ENOMEDIUM; -- case 0x2700: /* WRITE PROTECTED */ -- return EACCES; -- case 0x0401: /* NOT READY, IN PROGRESS OF BECOMING READY */ -- return EAGAIN; -- case 0x0402: /* NOT READY, INITIALIZING COMMAND REQUIRED */ -- return ENOTCONN; -- default: -- return EIO; -- } --} -- --int scsi_sense_buf_to_errno(const uint8_t *sense, size_t sense_size) --{ -- int key, asc, ascq; -- if (sense_size < 1) { -- return EIO; -- } -- switch (sense[0]) { -- case 0x70: /* Fixed format sense data. */ -- if (sense_size < 14) { -- return EIO; -- } -- key = sense[2] & 0xF; -- asc = sense[12]; -- ascq = sense[13]; -- break; -- case 0x72: /* Descriptor format sense data. */ -- if (sense_size < 4) { -- return EIO; -- } -- key = sense[1] & 0xF; -- asc = sense[2]; -- ascq = sense[3]; -- break; -- default: -- return EIO; -- break; -- } -- return scsi_sense_to_errno(key, asc, ascq); --} --- -1.8.3.1 - diff --git a/SOURCES/kvm-scsi-rename-scsi_build_sense-to-scsi_convert_sense.patch b/SOURCES/kvm-scsi-rename-scsi_build_sense-to-scsi_convert_sense.patch deleted file mode 100644 index 539a71f..0000000 --- a/SOURCES/kvm-scsi-rename-scsi_build_sense-to-scsi_convert_sense.patch +++ /dev/null @@ -1,103 +0,0 @@ -From ddae0e4b41b8bdf17934bce837558bb8eeecb2ea Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Sat, 2 Dec 2017 12:19:43 +0100 -Subject: [PATCH 17/36] scsi: rename scsi_build_sense to scsi_convert_sense -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Paolo Bonzini -Message-id: <20171202121953.13317-8-pbonzini@redhat.com> -Patchwork-id: 78079 -O-Subject: [RHEL7.4 qemu-kvm-rhev PATCH 07/17] scsi: rename scsi_build_sense to scsi_convert_sense -Bugzilla: 1464908 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: John Snow - -After introducing the scsi/ subdirectory, there will be a scsi_build_sense -function that is the same as scsi_req_build_sense but without needing -a SCSIRequest. The existing scsi_build_sense function gets in the way, -remove it. - -Reviewed-by: Philippe Mathieu-Daudé -Signed-off-by: Paolo Bonzini -(cherry picked from commit 37b6045c455275af37f0433b05b0dad123e14daf) -Signed-off-by: Miroslav Rezanina ---- - hw/scsi/scsi-bus.c | 10 +++++----- - hw/scsi/scsi-disk.c | 4 ++-- - include/hw/scsi/scsi.h | 4 ++-- - 3 files changed, 9 insertions(+), 9 deletions(-) - -diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c -index 55aa5a7..256610a 100644 ---- a/hw/scsi/scsi-bus.c -+++ b/hw/scsi/scsi-bus.c -@@ -798,7 +798,7 @@ int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len) - return 0; - } - -- ret = scsi_build_sense(req->sense, req->sense_len, buf, len, true); -+ ret = scsi_convert_sense(req->sense, req->sense_len, buf, len, true); - - /* - * FIXME: clearing unit attention conditions upon autosense should be done -@@ -819,7 +819,7 @@ int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len) - - int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed) - { -- return scsi_build_sense(dev->sense, dev->sense_len, buf, len, fixed); -+ return scsi_convert_sense(dev->sense, dev->sense_len, buf, len, fixed); - } - - void scsi_req_build_sense(SCSIRequest *req, SCSISense sense) -@@ -1539,12 +1539,12 @@ const struct SCSISense sense_code_SPACE_ALLOC_FAILED = { - }; - - /* -- * scsi_build_sense -+ * scsi_convert_sense - * - * Convert between fixed and descriptor sense buffers - */ --int scsi_build_sense(uint8_t *in_buf, int in_len, -- uint8_t *buf, int len, bool fixed) -+int scsi_convert_sense(uint8_t *in_buf, int in_len, -+ uint8_t *buf, int len, bool fixed) - { - bool fixed_in; - SCSISense sense; -diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c -index 21d6b4e..b7714e3 100644 ---- a/hw/scsi/scsi-disk.c -+++ b/hw/scsi/scsi-disk.c -@@ -1996,8 +1996,8 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) - break; - case REQUEST_SENSE: - /* Just return "NO SENSE". */ -- buflen = scsi_build_sense(NULL, 0, outbuf, r->buflen, -- (req->cmd.buf[1] & 1) == 0); -+ buflen = scsi_convert_sense(NULL, 0, outbuf, r->buflen, -+ (req->cmd.buf[1] & 1) == 0); - if (buflen < 0) { - goto illegal_request; - } -diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h -index 6b85786..6ef67fb 100644 ---- a/include/hw/scsi/scsi.h -+++ b/include/hw/scsi/scsi.h -@@ -244,8 +244,8 @@ extern const struct SCSISense sense_code_SPACE_ALLOC_FAILED; - uint32_t scsi_data_cdb_xfer(uint8_t *buf); - uint32_t scsi_cdb_xfer(uint8_t *buf); - int scsi_cdb_length(uint8_t *buf); --int scsi_build_sense(uint8_t *in_buf, int in_len, -- uint8_t *buf, int len, bool fixed); -+int scsi_convert_sense(uint8_t *in_buf, int in_len, -+ uint8_t *buf, int len, bool fixed); - - SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d, - uint32_t tag, uint32_t lun, void *hba_private); --- -1.8.3.1 - diff --git a/SOURCES/kvm-serial-always-transmit-send-receive-buffers-on-migra.patch b/SOURCES/kvm-serial-always-transmit-send-receive-buffers-on-migra.patch deleted file mode 100644 index 05a68c7..0000000 --- a/SOURCES/kvm-serial-always-transmit-send-receive-buffers-on-migra.patch +++ /dev/null @@ -1,93 +0,0 @@ -From b1163e497bdb3d6f04593940b6ec7842ec35c8ff Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Thu, 11 Jan 2018 13:56:44 +0100 -Subject: [PATCH 01/21] serial: always transmit send/receive buffers on - migration - -RH-Author: Paolo Bonzini -Message-id: <20180111135644.16253-1-pbonzini@redhat.com> -Patchwork-id: 78551 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH v2] serial: always transmit send/receive buffers on migration -Bugzilla: 1459945 -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Miroslav Rezanina - -When subsections were added in qemu 2.3, they were all disabled -for machine types that require pre-2.3 compatibility. The commit -message says "disabling these subsections on older machine types should -leave it no worse than existing qemu", but actually migrating from -new QEMU to new QEMU (but with old machine type) will detect an -inconsistent migration state and fail the migration: - - qemu-system-x86_64: inconsistent state in serial device (tsr not empty, tsr_retry=0 - qemu-system-x86_64: Failed to load serial:state - qemu-system-x86_64: error while loading state for instance 0x0 of device 'serial' - -In fact, this shows that migration from new source to old destination -might have also eaten the data in the FIFO or transmit/receive buffers. - -It's actually pretty easy to trigger the failure by connecting a console -to a hung-up reader (not a *disconnected* reader!). The fix is to -handle the subsections the same as we did in the qemu-kvm BZ1452067. -The data registers are migrated, which may indeed cause some more migrations -to fail to old qemu-kvm-rhev, but it will fix migration to new qemu-kvm-rhev. -Some subsections are still keyed on migrate_pre_2_2; from the commit message -of downstream commit 7d2e8f9662feb64c0b15b6fd53e06e3c56921f27: - - thr_ipending can be reconstructed fairly - reliably by serial_post_load. The others are features that are - unlikely to be used in RHEL, respectively receive timeout (Linux - does not even have the UART_IIR_CTI symbol in the driver) and - physical serial ports connected to a modem - -I consider this okay because nobody has yet complained about it for -qemu-kvm. It's also safer because the failure avoids serial data loss -on migration. This is consistent with the intended use of subsections. - -Signed-off-by: Paolo Bonzini -Signed-off-by: Miroslav Rezanina ---- - hw/char/serial.c | 12 ------------ - 1 file changed, 12 deletions(-) - -diff --git a/hw/char/serial.c b/hw/char/serial.c -index fe4f41d..d82f7eb 100644 ---- a/hw/char/serial.c -+++ b/hw/char/serial.c -@@ -720,10 +720,6 @@ static const VMStateDescription vmstate_serial_thr_ipending = { - static bool serial_tsr_needed(void *opaque) - { - SerialState *s = (SerialState *)opaque; -- if (migrate_pre_2_2) { -- return false; -- } -- - return s->tsr_retry != 0; - } - -@@ -743,10 +739,6 @@ static const VMStateDescription vmstate_serial_tsr = { - static bool serial_recv_fifo_needed(void *opaque) - { - SerialState *s = (SerialState *)opaque; -- if (migrate_pre_2_2) { -- return false; -- } -- - return !fifo8_is_empty(&s->recv_fifo); - - } -@@ -765,10 +757,6 @@ static const VMStateDescription vmstate_serial_recv_fifo = { - static bool serial_xmit_fifo_needed(void *opaque) - { - SerialState *s = (SerialState *)opaque; -- if (migrate_pre_2_2) { -- return false; -- } -- - return !fifo8_is_empty(&s->xmit_fifo); - } - --- -1.8.3.1 - diff --git a/SOURCES/kvm-setup b/SOURCES/kvm-setup index abbd587..e59a643 100644 --- a/SOURCES/kvm-setup +++ b/SOURCES/kvm-setup @@ -1,7 +1,13 @@ -#! /bin/bash +#!/bin/bash kvm_setup_powerpc () { - if grep '^platform[[:space:]]*:[[:space:]]*PowerNV' /proc/cpuinfo > /dev/null; then + isPowerNV=no + isPOWER8=no + + grep -q '^platform[[:space:]]*:[[:space:]]*PowerNV' /proc/cpuinfo && isPowerNV=yes + grep -q '^cpu[[:space:]]*:[[:space:]]*POWER8' /proc/cpuinfo && isPOWER8=yes + + if [ "$isPowerNV" = "yes" ] ; then # PowerNV platform, which is KVM HV capable if [ -z "$SUBCORES" ]; then @@ -18,15 +24,24 @@ kvm_setup_powerpc () { # order to run KVM guests. (Also applieds to POWER7, but we # don't support that). # + # Additionally, POWER8 guests can't benefit from transparent + # hugepages used to back them, and THPs allocated by any app + # can potentially interfere with HPT allocation (if they + # become locked, they can fragment the CMA). So, also disable + # THPs system wide. + # # POWER9 doesn't have this limitation (though it will for hash # guests on radix host when that's implemented). So, only set # up subcores and disable SMT for POWER*. - if grep '^cpu[[:space:]]*:[[:space:]]*POWER8' /proc/cpuinfo > /dev/null; then + if [ "$isPOWER8" = "yes" ] ; then # Step 2. Configure subcore mode /usr/sbin/ppc64_cpu --subcores-per-core=$SUBCORES # Step 3. Disable SMT (multithreading) /usr/sbin/ppc64_cpu --smt=off + + # Step 4. Disable transparent hugepages (THP) + echo never > /sys/kernel/mm/transparent_hugepage/enabled fi fi } diff --git a/SOURCES/kvm-setup-ppc64.sysconfig b/SOURCES/kvm-setup-ppc64.sysconfig new file mode 100644 index 0000000..7fb22d4 --- /dev/null +++ b/SOURCES/kvm-setup-ppc64.sysconfig @@ -0,0 +1,3 @@ +# POWER8 parameter +# Set the number of subcores per core +#SUBCORES=1 diff --git a/SOURCES/kvm-sheepdog-Fix-sd_co_create_opts-memory-leaks.patch b/SOURCES/kvm-sheepdog-Fix-sd_co_create_opts-memory-leaks.patch new file mode 100644 index 0000000..d3c892a --- /dev/null +++ b/SOURCES/kvm-sheepdog-Fix-sd_co_create_opts-memory-leaks.patch @@ -0,0 +1,63 @@ +From d9da0aedd0dc6aeee5751855eda3560f1757910c Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:47:44 +0200 +Subject: [PATCH 15/89] sheepdog: Fix sd_co_create_opts() memory leaks + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-2-kwolf@redhat.com> +Patchwork-id: 81074 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 01/73] sheepdog: Fix sd_co_create_opts() memory leaks +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +Both the option string for the 'redundancy' option and the +SheepdogRedundancy object that is created accordingly could be leaked in +error paths. This fixes the memory leaks. + +Reported by Coverity (CID 1390614 and 1390641). + +Signed-off-by: Kevin Wolf +Message-id: 20180503153509.22223-1-kwolf@redhat.com +Reviewed-by: Jeff Cody +Signed-off-by: Jeff Cody +(cherry picked from commit a2cb9239b7610ffb00f9ced5cd7640d40b0e1ccf) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/sheepdog.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/block/sheepdog.c b/block/sheepdog.c +index d1c9bf5..933880c 100644 +--- a/block/sheepdog.c ++++ b/block/sheepdog.c +@@ -1977,6 +1977,7 @@ static SheepdogRedundancy *parse_redundancy_str(const char *opt) + } else { + ret = qemu_strtol(n2, NULL, 10, &parity); + if (ret < 0) { ++ g_free(redundancy); + return NULL; + } + +@@ -2172,7 +2173,7 @@ static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts, + BlockdevCreateOptions *create_options = NULL; + QDict *qdict, *location_qdict; + Visitor *v; +- const char *redundancy; ++ char *redundancy; + Error *local_err = NULL; + int ret; + +@@ -2240,6 +2241,7 @@ static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts, + fail: + qapi_free_BlockdevCreateOptions(create_options); + qobject_unref(qdict); ++ g_free(redundancy); + return ret; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-slirp-Correct-size-check-in-m_inc.patch b/SOURCES/kvm-slirp-Correct-size-check-in-m_inc.patch index c861af2..7804fd1 100644 --- a/SOURCES/kvm-slirp-Correct-size-check-in-m_inc.patch +++ b/SOURCES/kvm-slirp-Correct-size-check-in-m_inc.patch @@ -1,13 +1,13 @@ -From ebad012fad51bd72c0618face6188086ee9c2be4 Mon Sep 17 00:00:00 2001 +From 44dfd8eea4b562e77587cdd1b2ae6b6decc870f9 Mon Sep 17 00:00:00 2001 From: Xiao Wang -Date: Wed, 8 Aug 2018 06:01:52 +0200 -Subject: [PATCH 3/3] slirp: Correct size check in m_inc() +Date: Wed, 8 Aug 2018 07:52:57 +0200 +Subject: [PATCH 2/5] slirp: Correct size check in m_inc() RH-Author: Xiao Wang -Message-id: <1533708112-14286-4-git-send-email-jasowang@redhat.com> -Patchwork-id: 81672 -O-Subject: [RHEL-7.5.z qemu-kvm-ma PATCH V2 3/3] slirp: Correct size check in m_inc() -Bugzilla: 1586247 +Message-id: <1533714777-24827-3-git-send-email-jasowang@redhat.com> +Patchwork-id: 81674 +O-Subject: [RHEL-7.6/7.5z qemu-kvm-rhev 2/2] slirp: Correct size check in m_inc() +Bugzilla: 1586255 RH-Acked-by: Dr. David Alan Gilbert RH-Acked-by: wexu@redhat.com RH-Acked-by: Thomas Huth diff --git a/SOURCES/kvm-slirp-correct-size-computation-while-concatenating-m.patch b/SOURCES/kvm-slirp-correct-size-computation-while-concatenating-m.patch index 795b7ef..32e5e9f 100644 --- a/SOURCES/kvm-slirp-correct-size-computation-while-concatenating-m.patch +++ b/SOURCES/kvm-slirp-correct-size-computation-while-concatenating-m.patch @@ -1,23 +1,20 @@ -From 8b8438b164750b1e864b8093e0b83b76365b7246 Mon Sep 17 00:00:00 2001 +From 34a609b26d1c20f15b168ebf889705886f9c7d1d Mon Sep 17 00:00:00 2001 From: Xiao Wang -Date: Wed, 8 Aug 2018 06:01:50 +0200 -Subject: [PATCH 1/3] slirp: correct size computation while concatenating mbuf +Date: Mon, 30 Jul 2018 08:06:27 +0200 +Subject: [PATCH 13/15] slirp: correct size computation while concatenating + mbuf RH-Author: Xiao Wang -Message-id: <1533708112-14286-2-git-send-email-jasowang@redhat.com> -Patchwork-id: 81669 -O-Subject: [RHEL-7.5.z qemu-kvm-ma PATCH V2 1/3] slirp: correct size computation while concatenating mbuf -Bugzilla: 1586247 -RH-Acked-by: Dr. David Alan Gilbert +Message-id: <1532937987-25050-1-git-send-email-jasowang@redhat.com> +Patchwork-id: 81544 +O-Subject: [RHEL-7.6/7.5z qemu-kvm-rhev] slirp: correct size computation while concatenating mbuf +Bugzilla: 1586255 RH-Acked-by: wexu@redhat.com -RH-Acked-by: Thomas Huth +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Miroslav Rezanina From: Prasad J Pandit -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1586247 -Brew Build: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=17635033 -Test status: Tested by myself - While reassembling incoming fragmented datagrams, 'm_cat' routine extends the 'mbuf' buffer, if it has insufficient room. It computes a wrong buffer size, which leads to overwriting adjacent heap buffer diff --git a/SOURCES/kvm-slirp-fix-clearing-ifq_so-from-pending-packets.patch b/SOURCES/kvm-slirp-fix-clearing-ifq_so-from-pending-packets.patch deleted file mode 100644 index 77ff6c7..0000000 --- a/SOURCES/kvm-slirp-fix-clearing-ifq_so-from-pending-packets.patch +++ /dev/null @@ -1,93 +0,0 @@ -From fab160fce838f609b3a395fcef40e4efce5c0fa7 Mon Sep 17 00:00:00 2001 -From: Xiao Wang -Date: Tue, 28 Nov 2017 03:43:20 +0100 -Subject: [PATCH 14/21] slirp: fix clearing ifq_so from pending packets -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Xiao Wang -Message-id: <1511840600-52375-1-git-send-email-jasowang@redhat.com> -Patchwork-id: 77930 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH] slirp: fix clearing ifq_so from pending packets -Bugzilla: 1508750 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: wexu@redhat.com -RH-Acked-by: Michael S. Tsirkin - -From: Samuel Thibault - -The if_fastq and if_batchq contain not only packets, but queues of packets -for the same socket. When sofree frees a socket, it thus has to clear ifq_so -from all the packets from the queues, not only the first. - -Signed-off-by: Samuel Thibault -Reviewed-by: Philippe Mathieu-Daudé -Cc: qemu-stable@nongnu.org -Signed-off-by: Peter Maydell -(cherry picked from commit 1201d308519f1e915866d7583d5136d03cc1d384) -Signed-off-by: Miroslav Rezanina ---- - slirp/socket.c | 39 +++++++++++++++++++++++---------------- - 1 file changed, 23 insertions(+), 16 deletions(-) - -diff --git a/slirp/socket.c b/slirp/socket.c -index ecec029..cb7b5b6 100644 ---- a/slirp/socket.c -+++ b/slirp/socket.c -@@ -60,29 +60,36 @@ socreate(Slirp *slirp) - } - - /* -+ * Remove references to so from the given message queue. -+ */ -+static void -+soqfree(struct socket *so, struct quehead *qh) -+{ -+ struct mbuf *ifq; -+ -+ for (ifq = (struct mbuf *) qh->qh_link; -+ (struct quehead *) ifq != qh; -+ ifq = ifq->ifq_next) { -+ if (ifq->ifq_so == so) { -+ struct mbuf *ifm; -+ ifq->ifq_so = NULL; -+ for (ifm = ifq->ifs_next; ifm != ifq; ifm = ifm->ifs_next) { -+ ifm->ifq_so = NULL; -+ } -+ } -+ } -+} -+ -+/* - * remque and free a socket, clobber cache - */ - void - sofree(struct socket *so) - { - Slirp *slirp = so->slirp; -- struct mbuf *ifm; - -- for (ifm = (struct mbuf *) slirp->if_fastq.qh_link; -- (struct quehead *) ifm != &slirp->if_fastq; -- ifm = ifm->ifq_next) { -- if (ifm->ifq_so == so) { -- ifm->ifq_so = NULL; -- } -- } -- -- for (ifm = (struct mbuf *) slirp->if_batchq.qh_link; -- (struct quehead *) ifm != &slirp->if_batchq; -- ifm = ifm->ifq_next) { -- if (ifm->ifq_so == so) { -- ifm->ifq_so = NULL; -- } -- } -+ soqfree(so, &slirp->if_fastq); -+ soqfree(so, &slirp->if_batchq); - - if (so->so_emu==EMU_RSH && so->extra) { - sofree(so->extra); --- -1.8.3.1 - diff --git a/SOURCES/kvm-slirp-reformat-m_inc-routine.patch b/SOURCES/kvm-slirp-reformat-m_inc-routine.patch index d70ae47..06a82cd 100644 --- a/SOURCES/kvm-slirp-reformat-m_inc-routine.patch +++ b/SOURCES/kvm-slirp-reformat-m_inc-routine.patch @@ -1,13 +1,13 @@ -From c97c19773140b2f9941ecd2c4bd390e6c011d730 Mon Sep 17 00:00:00 2001 +From 37e3851f6eac7999e7c5a7cfd41d53f72e47b03d Mon Sep 17 00:00:00 2001 From: Xiao Wang -Date: Wed, 8 Aug 2018 06:01:51 +0200 -Subject: [PATCH 2/3] slirp: reformat m_inc routine +Date: Wed, 8 Aug 2018 07:52:56 +0200 +Subject: [PATCH 1/5] slirp: reformat m_inc routine RH-Author: Xiao Wang -Message-id: <1533708112-14286-3-git-send-email-jasowang@redhat.com> -Patchwork-id: 81671 -O-Subject: [RHEL-7.5.z qemu-kvm-ma PATCH V2 2/3] slirp: reformat m_inc routine -Bugzilla: 1586247 +Message-id: <1533714777-24827-2-git-send-email-jasowang@redhat.com> +Patchwork-id: 81675 +O-Subject: [RHEL-7.6/7.5z qemu-kvm-rhev 1/2] slirp: reformat m_inc routine +Bugzilla: 1586255 RH-Acked-by: Dr. David Alan Gilbert RH-Acked-by: wexu@redhat.com RH-Acked-by: Thomas Huth diff --git a/SOURCES/kvm-snapshot-tests-Try-loadvm-twice.patch b/SOURCES/kvm-snapshot-tests-Try-loadvm-twice.patch deleted file mode 100644 index ac75eb3..0000000 --- a/SOURCES/kvm-snapshot-tests-Try-loadvm-twice.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 5fb5d8c2e07d86138ca30bc27b5e454a6a05329b Mon Sep 17 00:00:00 2001 -From: "Dr. David Alan Gilbert" -Date: Thu, 2 Nov 2017 15:36:57 +0100 -Subject: [PATCH 4/9] snapshot/tests: Try loadvm twice - -RH-Author: Dr. David Alan Gilbert -Message-id: <20171102153657.13452-3-dgilbert@redhat.com> -Patchwork-id: 77483 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 2/2] snapshot/tests: Try loadvm twice -Bugzilla: 1508799 -RH-Acked-by: Peter Xu -RH-Acked-by: Thomas Huth -RH-Acked-by: Stefan Hajnoczi - -From: "Dr. David Alan Gilbert" - -It's legal to loadvm twice, modify the existing save/loadvm test -to do it twice. - -Signed-off-by: Dr. David Alan Gilbert -Message-Id: <20170825141940.20740-3-dgilbert@redhat.com> -Reviewed-by: Peter Xu -Signed-off-by: Dr. David Alan Gilbert -(cherry picked from commit 04583a9e8fbeb2c5c0607327b853b306aef7465f) -Signed-off-by: Miroslav Rezanina ---- - tests/qemu-iotests/068 | 2 +- - tests/qemu-iotests/068.out | 4 ++++ - 2 files changed, 5 insertions(+), 1 deletion(-) - -diff --git a/tests/qemu-iotests/068 b/tests/qemu-iotests/068 -index cfa0f2a..e7fca6a 100755 ---- a/tests/qemu-iotests/068 -+++ b/tests/qemu-iotests/068 -@@ -78,7 +78,7 @@ for extra_args in \ - # Give qemu some time to boot before saving the VM state - { sleep 1; printf "savevm 0\nquit\n"; } | _qemu $extra_args - # Now try to continue from that VM state (this should just work) -- echo quit | _qemu $extra_args -loadvm 0 -+ { sleep 1; printf "loadvm 0\nloadvm 0\nquit\n"; } | _qemu $extra_args -S - done - - # success, all done -diff --git a/tests/qemu-iotests/068.out b/tests/qemu-iotests/068.out -index aa063cf..f07a938 100644 ---- a/tests/qemu-iotests/068.out -+++ b/tests/qemu-iotests/068.out -@@ -7,6 +7,8 @@ QEMU X.Y.Z monitor - type 'help' for more information - (qemu) savevm 0 - (qemu) quit - QEMU X.Y.Z monitor - type 'help' for more information -+(qemu) loadvm 0 -+(qemu) loadvm 0 - (qemu) quit - - === Saving and reloading a VM state to/from a qcow2 image (-object iothread,id=iothread0 -set device.hba0.iothread=iothread0) === -@@ -16,5 +18,7 @@ QEMU X.Y.Z monitor - type 'help' for more information - (qemu) savevm 0 - (qemu) quit - QEMU X.Y.Z monitor - type 'help' for more information -+(qemu) loadvm 0 -+(qemu) loadvm 0 - (qemu) quit - *** done --- -1.8.3.1 - diff --git a/SOURCES/kvm-sockets-avoid-crash-when-cleaning-up-sockets-for-an-.patch b/SOURCES/kvm-sockets-avoid-crash-when-cleaning-up-sockets-for-an-.patch deleted file mode 100644 index 0f7bd6b..0000000 --- a/SOURCES/kvm-sockets-avoid-crash-when-cleaning-up-sockets-for-an-.patch +++ /dev/null @@ -1,45 +0,0 @@ -From b76eb750ff4e5a698428465d6b54684d49319e40 Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Fri, 8 Dec 2017 14:00:16 +0100 -Subject: [PATCH 21/21] sockets: avoid crash when cleaning up sockets for an - invalid FD - -RH-Author: Daniel P. Berrange -Message-id: <20171208140016.29707-1-berrange@redhat.com> -Patchwork-id: 78275 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH] sockets: avoid crash when cleaning up sockets for an invalid FD -Bugzilla: 1506218 -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Laurent Vivier -RH-Acked-by: Markus Armbruster - -If socket_listen_cleanup is passed an invalid FD, then querying the socket -local address will fail. We must thus be prepared for the returned addr to -be NULL - -Reported-by: Dr. David Alan Gilbert -Reviewed-by: Dr. David Alan Gilbert -Signed-off-by: Daniel P. Berrange -(cherry picked from commit 2d7ad7c05e762d5b10a57eba9af1bb6b41700854) -Signed-off-by: Miroslav Rezanina ---- - util/qemu-sockets.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c -index 1358c81..bca6a06 100644 ---- a/util/qemu-sockets.c -+++ b/util/qemu-sockets.c -@@ -1190,6 +1190,9 @@ void socket_listen_cleanup(int fd, Error **errp) - SocketAddress *addr; - - addr = socket_local_address(fd, errp); -+ if (!addr) { -+ return; -+ } - - if (addr->type == SOCKET_ADDRESS_TYPE_UNIX - && addr->u.q_unix.path) { --- -1.8.3.1 - diff --git a/SOURCES/kvm-spapr-Add-ibm-max-associativity-domains-property.patch b/SOURCES/kvm-spapr-Add-ibm-max-associativity-domains-property.patch new file mode 100644 index 0000000..ea49fb3 --- /dev/null +++ b/SOURCES/kvm-spapr-Add-ibm-max-associativity-domains-property.patch @@ -0,0 +1,63 @@ +From 5a7d9ce549b777d52cd680327e4dc17921ab882c Mon Sep 17 00:00:00 2001 +From: Serhii Popovych +Date: Wed, 2 May 2018 18:52:27 +0200 +Subject: [PATCH 04/13] spapr: Add ibm, max-associativity-domains property + +RH-Author: Serhii Popovych +Message-id: <1525287148-92715-2-git-send-email-spopovyc@redhat.com> +Patchwork-id: 80013 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/2] spapr: Add ibm, max-associativity-domains property +Bugzilla: 1570525 +RH-Acked-by: David Gibson +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier + +Now recent kernels (i.e. since linux-stable commit a346137e9142 +("powerpc/numa: Use ibm,max-associativity-domains to discover possible nodes") +support this property to mark initially memory-less NUMA nodes as "possible" +to allow further memory hot-add to them. + +Advertise this property for pSeries machines to let guest kernels detect +maximum supported node configuration and benefit from kernel side change +when hot-add memory to specific, possibly empty before, NUMA node. + +Signed-off-by: Serhii Popovych +Signed-off-by: David Gibson +(cherry picked from commit da9f80fbad21319194e73355dea8a1cff6a574e4) +Signed-off-by: Serhii Popovych +Signed-off-by: Miroslav Rezanina +--- + hw/ppc/spapr.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c +index 360a258..c9561e1 100644 +--- a/hw/ppc/spapr.c ++++ b/hw/ppc/spapr.c +@@ -910,6 +910,13 @@ static void spapr_dt_rtas(sPAPRMachineState *spapr, void *fdt) + 0, cpu_to_be32(SPAPR_MEMORY_BLOCK_SIZE), + cpu_to_be32(max_cpus / smp_threads), + }; ++ uint32_t maxdomains[] = { ++ cpu_to_be32(4), ++ cpu_to_be32(0), ++ cpu_to_be32(0), ++ cpu_to_be32(0), ++ cpu_to_be32(nb_numa_nodes ? nb_numa_nodes - 1 : 0), ++ }; + + _FDT(rtas = fdt_add_subnode(fdt, 0, "rtas")); + +@@ -946,6 +953,9 @@ static void spapr_dt_rtas(sPAPRMachineState *spapr, void *fdt) + _FDT(fdt_setprop(fdt, rtas, "ibm,associativity-reference-points", + refpoints, sizeof(refpoints))); + ++ _FDT(fdt_setprop(fdt, rtas, "ibm,max-associativity-domains", ++ maxdomains, sizeof(maxdomains))); ++ + _FDT(fdt_setprop_cell(fdt, rtas, "rtas-error-log-max", + RTAS_ERROR_LOG_MAX)); + _FDT(fdt_setprop_cell(fdt, rtas, "rtas-event-scan-rate", +-- +1.8.3.1 + diff --git a/SOURCES/kvm-spapr-Adjust-default-VSMT-value-for-better-migration.patch b/SOURCES/kvm-spapr-Adjust-default-VSMT-value-for-better-migration.patch deleted file mode 100644 index ac92131..0000000 --- a/SOURCES/kvm-spapr-Adjust-default-VSMT-value-for-better-migration.patch +++ /dev/null @@ -1,117 +0,0 @@ -From 11a953b475cd0c30c661e8ce4cf4518405792b75 Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Fri, 19 Jan 2018 04:04:58 +0100 -Subject: [PATCH 18/21] spapr: Adjust default VSMT value for better migration - compatibility - -RH-Author: David Gibson -Message-id: <20180119040458.5629-5-dgibson@redhat.com> -Patchwork-id: 78679 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 4/4] spapr: Adjust default VSMT value for better migration compatibility -Bugzilla: 1529243 -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier -RH-Acked-by: Miroslav Rezanina - -From: David Gibson - -fa98fbfc "PC: KVM: Support machine option to set VSMT mode" introduced the -"vsmt" parameter for the pseries machine type, which controls the spacing -of the vcpu ids of thread 0 for each virtual core. This was done to bring -some consistency and stability to how that was done, while still allowing -backwards compatibility for migration and otherwise. - -The default value we used for vsmt was set to the max of the host's -advertised default number of threads and the number of vthreads per vcore -in the guest. This was done to continue running without extra parameters -on older KVM versions which don't allow the VSMT value to be changed. - -Unfortunately, even that smaller than before leakage of host configuration -into guest visible configuration still breaks things. Specifically a guest -with 4 (or less) vthread/vcore will get a different vsmt value when -running on a POWER8 (vsmt==8) and POWER9 (vsmt==4) host. That means the -vcpu ids don't line up so you can't migrate between them, though you should -be able to. - -Long term we really want to make vsmt == smp_threads for sufficiently -new machine types. However, that means that qemu will then require a -sufficiently recent KVM (one which supports changing VSMT) - that's still -not widely enough deployed to be really comfortable to do. - -In the meantime we need some default that will work as often as -possible. This patch changes that default to 8 in all circumstances. -This does change guest visible behaviour (including for existing -machine versions) for many cases - just not the most common/important -case. - -Following is case by case justification for why this is still the least -worst option. Note that any of the old behaviours can still be duplicated -after this patch, it's just that it requires manual intervention by -setting the vsmt property on the command line. - -KVM HV on POWER8 host: - This is the overwhelmingly common case in production setups, and is - unchanged by design. POWER8 hosts will advertise a default VSMT mode - of 8, and > 8 vthreads/vcore isn't permitted - -KVM HV on POWER7 host: - Will break, but POWER7s allowing KVM were never released to the public. - -KVM HV on POWER9 host: - Not yet released to the public, breaking this now will reduce other - breakage later. - -KVM HV on PowerPC 970: - Will theoretically break it, but it was barely supported to begin with - and already required various user visible hacks to work. Also so old - that I just don't care. - -TCG: - This is the nastiest one; it means migration of TCG guests (without - manual vsmt setting) will break. Since TCG is rarely used in production - I think this is worth it for the other benefits. It does also remove - one more barrier to TCG<->KVM migration which could be interesting for - debugging applications. - -KVM PR: - As with TCG, this will break migration of existing configurations, - without adding extra manual vsmt options. As with TCG, it is rare in - production so I think the benefits outweigh breakages. - -Signed-off-by: David Gibson -Reviewed-by: Laurent Vivier -Reviewed-by: Jose Ricardo Ziviani -Reviewed-by: Greg Kurz -(cherry picked from commit 8904e5a75005fe579c28806003892d8ae4a27dfa) - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr.c | 11 ++++++++--- - 1 file changed, 8 insertions(+), 3 deletions(-) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 1086b5a..2bb3b61 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -2254,9 +2254,14 @@ static void spapr_set_vsmt_mode(sPAPRMachineState *spapr, Error **errp) - } - /* In this case, spapr->vsmt has been set by the command line */ - } else { -- /* Choose a VSMT mode that may be higher than necessary but is -- * likely to be compatible with hosts that don't have VSMT. */ -- spapr->vsmt = MAX(kvm_smt, smp_threads); -+ /* -+ * Default VSMT value is tricky, because we need it to be as -+ * consistent as possible (for migration), but this requires -+ * changing it for at least some existing cases. We pick 8 as -+ * the value that we'd get with KVM on POWER8, the -+ * overwhelmingly common case in production systems. -+ */ -+ spapr->vsmt = 8; - } - - /* KVM: If necessary, set the SMT mode: */ --- -1.8.3.1 - diff --git a/SOURCES/kvm-spapr-Allow-some-cases-where-we-can-t-set-VSMT-mode-.patch b/SOURCES/kvm-spapr-Allow-some-cases-where-we-can-t-set-VSMT-mode-.patch deleted file mode 100644 index c4842d0..0000000 --- a/SOURCES/kvm-spapr-Allow-some-cases-where-we-can-t-set-VSMT-mode-.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 689db60fc3f20c8aea0d5f382eb7d4de87e6bb3f Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Fri, 19 Jan 2018 04:04:57 +0100 -Subject: [PATCH 17/21] spapr: Allow some cases where we can't set VSMT mode in - the kernel - -RH-Author: David Gibson -Message-id: <20180119040458.5629-4-dgibson@redhat.com> -Patchwork-id: 78678 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 3/4] spapr: Allow some cases where we can't set VSMT mode in the kernel -Bugzilla: 1529243 -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier -RH-Acked-by: Miroslav Rezanina - -From: David Gibson - -At present if we require a vsmt mode that's not equal to the kernel's -default, and the kernel doesn't let us change it (e.g. because it's an old -kernel without support) then we always fail. - -But in fact we can cope with the kernel having a different vsmt as long as - a) it's >= the actual number of vthreads/vcore (so that guest threads - that are supposed to be on the same core act like it) - b) it's a submultiple of the requested vsmt mode (so that guest threads - spaced by the vsmt value will act like they're on different cores) - -Allowing this case gives us a bit more freedom to adjust the vsmt behaviour -without breaking existing cases. - -Signed-off-by: David Gibson -Reviewed-by: Laurent Vivier -Tested-by: Greg Kurz -Reviewed-by: Greg Kurz -(cherry picked from commit 1f20f2e0ee61d91abff4e86ed1cda1b5244647d3) - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr.c | 26 +++++++++++++++++++------- - 1 file changed, 19 insertions(+), 7 deletions(-) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 5233366..1086b5a 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -2263,17 +2263,29 @@ static void spapr_set_vsmt_mode(sPAPRMachineState *spapr, Error **errp) - if (kvm_enabled() && (spapr->vsmt != kvm_smt)) { - ret = kvmppc_set_smt_threads(spapr->vsmt); - if (ret) { -+ /* Looks like KVM isn't able to change VSMT mode */ - error_setg(&local_err, - "Failed to set KVM's VSMT mode to %d (errno %d)", - spapr->vsmt, ret); -- if (!vsmt_user) { -- error_append_hint(&local_err, "On PPC, a VM with %d threads/" -- "core on a host with %d threads/core requires " -- " the use of VSMT mode %d.\n", -- smp_threads, kvm_smt, spapr->vsmt); -+ /* We can live with that if the default one is big enough -+ * for the number of threads, and a submultiple of the one -+ * we want. In this case we'll waste some vcpu ids, but -+ * behaviour will be correct */ -+ if ((kvm_smt >= smp_threads) && ((spapr->vsmt % kvm_smt) == 0)) { -+ warn_report_err(local_err); -+ local_err = NULL; -+ goto out; -+ } else { -+ if (!vsmt_user) { -+ error_append_hint(&local_err, -+ "On PPC, a VM with %d threads/core" -+ " on a host with %d threads/core" -+ " requires the use of VSMT mode %d.\n", -+ smp_threads, kvm_smt, spapr->vsmt); -+ } -+ kvmppc_hint_smt_possible(&local_err); -+ goto out; - } -- kvmppc_hint_smt_possible(&local_err); -- goto out; - } - } - /* else TCG: nothing to do currently */ --- -1.8.3.1 - diff --git a/SOURCES/kvm-spapr-Capabilities-infrastructure.patch b/SOURCES/kvm-spapr-Capabilities-infrastructure.patch deleted file mode 100644 index e9e393a..0000000 --- a/SOURCES/kvm-spapr-Capabilities-infrastructure.patch +++ /dev/null @@ -1,365 +0,0 @@ -From 466322847847d3948eb7699aafcf9afd9ac3fc26 Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Fri, 19 Jan 2018 02:34:36 +0100 -Subject: [PATCH 08/21] spapr: Capabilities infrastructure - -RH-Author: David Gibson -Message-id: <20180119023442.28577-2-dgibson@redhat.com> -Patchwork-id: 78668 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 1/7] spapr: Capabilities infrastructure -Bugzilla: 1523414 -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth -RH-Acked-by: Miroslav Rezanina - -From: David Gibson - -Because PAPR is a paravirtual environment access to certain CPU (or other) -facilities can be blocked by the hypervisor. PAPR provides ways to -advertise in the device tree whether or not those features are available to -the guest. - -In some places we automatically determine whether to make a feature -available based on whether our host can support it, in most cases this is -based on limitations in the available KVM implementation. - -Although we correctly advertise this to the guest, it means that host -factors might make changes to the guest visible environment which is bad: -as well as generaly reducing reproducibility, it means that a migration -between different host environments can easily go bad. - -We've mostly gotten away with it because the environments considered mature -enough to be well supported (basically, KVM on POWER8) have had consistent -feature availability. But, it's still not right and some limitations on -POWER9 is going to make it more of an issue in future. - -This introduces an infrastructure for defining "sPAPR capabilities". These -are set by default based on the machine version, masked by the capabilities -of the chosen cpu, but can be overriden with machine properties. - -The intention is at reset time we verify that the requested capabilities -can be supported on the host (considering TCG, KVM and/or host cpu -limitations). If not we simply fail, rather than silently modifying the -advertised featureset to the guest. - -This does mean that certain configurations that "worked" may now fail, but -such configurations were already more subtly broken. - -Signed-off-by: David Gibson -Reviewed-by: Greg Kurz -(cherry picked from commit 33face6b8981add8eba1f7cdaf4cf6cede415d2e) -Signed-off-by: Miroslav Rezanina - -Conflicts: - hw/ppc/spapr.c - include/hw/ppc/spapr.h - -Simple contextual conflicts. - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1523414 - -Signed-off-by: David Gibson ---- - hw/ppc/Makefile.objs | 2 +- - hw/ppc/spapr.c | 7 ++ - hw/ppc/spapr_caps.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++++ - include/hw/ppc/spapr.h | 31 +++++++++ - 4 files changed, 220 insertions(+), 1 deletion(-) - create mode 100644 hw/ppc/spapr_caps.c - -diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs -index 856cef5..d4cdbb8 100644 ---- a/hw/ppc/Makefile.objs -+++ b/hw/ppc/Makefile.objs -@@ -1,7 +1,7 @@ - # shared objects - obj-y += ppc.o ppc_booke.o fdt.o - # IBM pSeries (sPAPR) --obj-$(CONFIG_PSERIES) += spapr.o spapr_vio.o spapr_events.o -+obj-$(CONFIG_PSERIES) += spapr.o spapr_caps.o spapr_vio.o spapr_events.o - obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o - obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_rtc.o spapr_drc.o - obj-$(CONFIG_PSERIES) += spapr_cpu_core.o spapr_ovec.o -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index cdc56f3..7a4191d 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -1424,6 +1424,8 @@ static void ppc_spapr_reset(void) - /* Check for unknown sysbus devices */ - foreach_dynamic_sysbus_device(find_unknown_sysbus_device, NULL); - -+ spapr_caps_reset(spapr); -+ - first_ppc_cpu = POWERPC_CPU(first_cpu); - if (kvm_enabled() && kvmppc_has_cap_mmu_radix() && - ppc_check_compat(first_ppc_cpu, CPU_POWERPC_LOGICAL_3_00, 0, -@@ -2267,6 +2269,8 @@ static void ppc_spapr_init(MachineState *machine) - char *filename; - Error *resize_hpt_err = NULL; - -+ spapr_caps_validate(spapr, &error_fatal); -+ - msi_nonbroken = true; - - QLIST_INIT(&spapr->phbs); -@@ -3635,6 +3639,9 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) - */ - mc->numa_mem_align_shift = 28; - smc->has_power9_support = true; -+ -+ smc->default_caps = spapr_caps(0); -+ spapr_caps_add_properties(smc, &error_abort); - } - - static const TypeInfo spapr_machine_info = { -diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c -new file mode 100644 -index 0000000..968ba7b ---- /dev/null -+++ b/hw/ppc/spapr_caps.c -@@ -0,0 +1,181 @@ -+/* -+ * QEMU PowerPC pSeries Logical Partition capabilities handling -+ * -+ * Copyright (c) 2017 David Gibson, Red Hat Inc. -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+#include "qemu/osdep.h" -+#include "qapi/error.h" -+#include "qapi/visitor.h" -+ -+#include "hw/ppc/spapr.h" -+ -+typedef struct sPAPRCapabilityInfo { -+ const char *name; -+ const char *description; -+ uint64_t flag; -+ -+ /* Make sure the virtual hardware can support this capability */ -+ void (*allow)(sPAPRMachineState *spapr, Error **errp); -+ -+ /* If possible, tell the virtual hardware not to allow the cap to -+ * be used at all */ -+ void (*disallow)(sPAPRMachineState *spapr, Error **errp); -+} sPAPRCapabilityInfo; -+ -+static sPAPRCapabilityInfo capability_table[] = { -+}; -+ -+static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr, -+ CPUState *cs) -+{ -+ sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); -+ sPAPRCapabilities caps; -+ -+ caps = smc->default_caps; -+ -+ /* TODO: clamp according to cpu model */ -+ -+ return caps; -+} -+ -+void spapr_caps_reset(sPAPRMachineState *spapr) -+{ -+ Error *local_err = NULL; -+ sPAPRCapabilities caps; -+ int i; -+ -+ /* First compute the actual set of caps we're running with.. */ -+ caps = default_caps_with_cpu(spapr, first_cpu); -+ -+ caps.mask |= spapr->forced_caps.mask; -+ caps.mask &= ~spapr->forbidden_caps.mask; -+ -+ spapr->effective_caps = caps; -+ -+ /* .. then apply those caps to the virtual hardware */ -+ -+ for (i = 0; i < ARRAY_SIZE(capability_table); i++) { -+ sPAPRCapabilityInfo *info = &capability_table[i]; -+ -+ if (spapr->effective_caps.mask & info->flag) { -+ /* Failure to allow a cap is fatal - if the guest doesn't -+ * have it, we'll be supplying an incorrect environment */ -+ if (info->allow) { -+ info->allow(spapr, &error_fatal); -+ } -+ } else { -+ /* Failure to enforce a cap is only a warning. The guest -+ * shouldn't be using it, since it's not advertised, so it -+ * doesn't get to complain about weird behaviour if it -+ * goes ahead anyway */ -+ if (info->disallow) { -+ info->disallow(spapr, &local_err); -+ } -+ if (local_err) { -+ warn_report_err(local_err); -+ local_err = NULL; -+ } -+ } -+ } -+} -+ -+static void spapr_cap_get(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ sPAPRCapabilityInfo *cap = opaque; -+ sPAPRMachineState *spapr = SPAPR_MACHINE(obj); -+ bool value = spapr_has_cap(spapr, cap->flag); -+ -+ /* TODO: Could this get called before effective_caps is finalized -+ * in spapr_caps_reset()? */ -+ -+ visit_type_bool(v, name, &value, errp); -+} -+ -+static void spapr_cap_set(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) -+{ -+ sPAPRCapabilityInfo *cap = opaque; -+ sPAPRMachineState *spapr = SPAPR_MACHINE(obj); -+ bool value; -+ Error *local_err = NULL; -+ -+ visit_type_bool(v, name, &value, &local_err); -+ if (local_err) { -+ error_propagate(errp, local_err); -+ return; -+ } -+ -+ if (value) { -+ spapr->forced_caps.mask |= cap->flag; -+ } else { -+ spapr->forbidden_caps.mask |= cap->flag; -+ } -+} -+ -+void spapr_caps_validate(sPAPRMachineState *spapr, Error **errp) -+{ -+ uint64_t allcaps = 0; -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(capability_table); i++) { -+ g_assert((allcaps & capability_table[i].flag) == 0); -+ allcaps |= capability_table[i].flag; -+ } -+ -+ g_assert((spapr->forced_caps.mask & ~allcaps) == 0); -+ g_assert((spapr->forbidden_caps.mask & ~allcaps) == 0); -+ -+ if (spapr->forced_caps.mask & spapr->forbidden_caps.mask) { -+ error_setg(errp, "Some sPAPR capabilities set both on and off"); -+ return; -+ } -+ -+ /* Check for any caps incompatible with other caps. Nothing to do -+ * yet */ -+} -+ -+void spapr_caps_add_properties(sPAPRMachineClass *smc, Error **errp) -+{ -+ Error *local_err = NULL; -+ ObjectClass *klass = OBJECT_CLASS(smc); -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(capability_table); i++) { -+ sPAPRCapabilityInfo *cap = &capability_table[i]; -+ const char *name = g_strdup_printf("cap-%s", cap->name); -+ -+ object_class_property_add(klass, name, "bool", -+ spapr_cap_get, spapr_cap_set, NULL, -+ cap, &local_err); -+ if (local_err) { -+ error_propagate(errp, local_err); -+ return; -+ } -+ -+ object_class_property_set_description(klass, name, cap->description, -+ &local_err); -+ if (local_err) { -+ error_propagate(errp, local_err); -+ return; -+ } -+ } -+} -diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h -index d9e8e5a..7267151 100644 ---- a/include/hw/ppc/spapr.h -+++ b/include/hw/ppc/spapr.h -@@ -51,6 +51,15 @@ typedef enum { - } sPAPRResizeHPT; - - /** -+ * Capabilities -+ */ -+ -+typedef struct sPAPRCapabilities sPAPRCapabilities; -+struct sPAPRCapabilities { -+ uint64_t mask; -+}; -+ -+/** - * sPAPRMachineClass: - */ - struct sPAPRMachineClass { -@@ -68,6 +77,7 @@ struct sPAPRMachineClass { - hwaddr *mmio32, hwaddr *mmio64, - unsigned n_dma, uint32_t *liobns, Error **errp); - sPAPRResizeHPT resize_hpt_default; -+ sPAPRCapabilities default_caps; - }; - - /** -@@ -129,6 +139,9 @@ struct sPAPRMachineState { - MemoryHotplugState hotplug_memory; - - const char *icp_type; -+ -+ sPAPRCapabilities forced_caps, forbidden_caps; -+ sPAPRCapabilities effective_caps; - }; - - #define H_SUCCESS 0 -@@ -707,4 +720,22 @@ void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg); - - #define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift)) - -+/* -+ * Handling of optional capabilities -+ */ -+static inline sPAPRCapabilities spapr_caps(uint64_t mask) -+{ -+ sPAPRCapabilities caps = { mask }; -+ return caps; -+} -+ -+static inline bool spapr_has_cap(sPAPRMachineState *spapr, uint64_t cap) -+{ -+ return !!(spapr->effective_caps.mask & cap); -+} -+ -+void spapr_caps_reset(sPAPRMachineState *spapr); -+void spapr_caps_validate(sPAPRMachineState *spapr, Error **errp); -+void spapr_caps_add_properties(sPAPRMachineClass *smc, Error **errp); -+ - #endif /* HW_SPAPR_H */ --- -1.8.3.1 - diff --git a/SOURCES/kvm-spapr-Correct-RAM-size-calculation-for-HPT-resizing.patch b/SOURCES/kvm-spapr-Correct-RAM-size-calculation-for-HPT-resizing.patch deleted file mode 100644 index 63d6795..0000000 --- a/SOURCES/kvm-spapr-Correct-RAM-size-calculation-for-HPT-resizing.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 61cace627e7140a63e27c7b1f949fc3b44ec120c Mon Sep 17 00:00:00 2001 -From: Serhii Popovych -Date: Wed, 22 Nov 2017 13:35:31 +0100 -Subject: [PATCH 1/7] spapr: Correct RAM size calculation for HPT resizing - -RH-Author: Serhii Popovych -Message-id: <1511357731-4779-1-git-send-email-spopovyc@redhat.com> -Patchwork-id: 77778 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH v2] spapr: Correct RAM size calculation for HPT resizing -Bugzilla: 1499647 -RH-Acked-by: Laurent Vivier -RH-Acked-by: David Gibson -RH-Acked-by: Thomas Huth - -From: David Gibson - -The only thing making this change distinct from one in -upstream is get_plugged_memory_size() function which -isn't present in 2.10.x branch and it is a part of new -QMP interface command which we do not want to introduce -in downstream. - -So assuming that we replace get_plugged_memory_size() -with direct call to pc_existing_dimms_capacity(). - - commit db50f280cf5f714e64ff2b134aae138908f07502 - Author: David Gibson - Date: Wed Oct 11 00:16:57 2017 +1100 - - spapr: Correct RAM size calculation for HPT resizing - - In order to prevent the guest from forcing the allocation of large amounts - of qemu memory (or host kernel memory, in the case of KVM HV), we limit - the size of Hashed Page Table (HPT) it is allowed to allocated, based on - its RAM size. - - However, the current calculation is not correct: it only adds up the size - of plugged memory, ignoring the base memory size. This patch corrects it. - - While we're there, use get_plugged_memory_size() instead of directly - calling pc_existing_dimms_capacity(). The only difference is that it - will abort on failure, which is right: a failure here indicates something - wrong within qemu. - - Signed-off-by: David Gibson - Reviewed-by: Greg Kurz - Reviewed-by: Laurent Vivier - -Signed-off-by: Serhii Popovych -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr_hcall.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c -index b503299..217358d 100644 ---- a/hw/ppc/spapr_hcall.c -+++ b/hw/ppc/spapr_hcall.c -@@ -472,7 +472,7 @@ static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu, - target_ulong flags = args[0]; - int shift = args[1]; - sPAPRPendingHPT *pending = spapr->pending_hpt; -- uint64_t current_ram_size = MACHINE(spapr)->ram_size; -+ uint64_t current_ram_size; - int rc; - - if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DISABLED) { -@@ -494,7 +494,8 @@ static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu, - return H_PARAMETER; - } - -- current_ram_size = pc_existing_dimms_capacity(&error_fatal); -+ current_ram_size = MACHINE(spapr)->ram_size + -+ pc_existing_dimms_capacity(&error_fatal); - - /* We only allow the guest to allocate an HPT one order above what - * we'd normally give them (to stop a small guest claiming a huge --- -1.8.3.1 - diff --git a/SOURCES/kvm-spapr-Correct-compatibility-mode-setting-for-hotplug.patch b/SOURCES/kvm-spapr-Correct-compatibility-mode-setting-for-hotplug.patch deleted file mode 100644 index 41c367b..0000000 --- a/SOURCES/kvm-spapr-Correct-compatibility-mode-setting-for-hotplug.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 4d5b8f8fecbbf460f8c2f789784542e2d0e1fd20 Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Fri, 12 Jan 2018 03:43:33 +0100 -Subject: [PATCH 06/12] spapr: Correct compatibility mode setting for - hotplugged CPUs - -RH-Author: David Gibson -Message-id: <20180112034333.5242-1-dgibson@redhat.com> -Patchwork-id: 78556 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH] spapr: Correct compatibility mode setting for hotplugged CPUs -Bugzilla: 1528234 -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier -RH-Acked-by: Serhii Popovych - -From: David Gibson - -Currently the pseries machine sets the compatibility mode for the -guest's cpus in two places: 1) at machine reset and 2) after CAS -negotiation. - -This means that if we set or negotiate a compatiblity mode, then -hotplug a cpu, the hotplugged cpu doesn't get the right mode set and -will incorrectly have the full native features. - -To correct this, we set the compatibility mode on a cpu when it is -brought online with the 'start-cpu' RTAS call. Given that we no -longer need to set the compatibility mode on all CPUs at machine -reset, so we change that to only set the mode for the boot cpu. - -Signed-off-by: David Gibson -Reported-by: Satheesh Rajendran -Tested-by: Satheesh Rajendran -Reviewed-by: Alexey Kardashevskiy -(cherry picked from commit 51f84465dd985fc21589b2eac1f18658fc9783e9) -Signed-off-by: Miroslav Rezanina - -Conflicts: - hw/ppc/spapr_rtas.c - -Minor contextual conflict. - -Signed-off-by: David Gibson ---- - hw/ppc/spapr.c | 2 +- - hw/ppc/spapr_rtas.c | 9 +++++++++ - 2 files changed, 10 insertions(+), 1 deletion(-) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index e276632..cdc56f3 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -1462,7 +1462,7 @@ static void ppc_spapr_reset(void) - spapr_ovec_cleanup(spapr->ov5_cas); - spapr->ov5_cas = spapr_ovec_new(); - -- ppc_set_compat_all(spapr->max_compat_pvr, &error_fatal); -+ ppc_set_compat(first_ppc_cpu, spapr->max_compat_pvr, &error_fatal); - } - - fdt = spapr_build_fdt(spapr, rtas_addr, spapr->rtas_size); -diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c -index 94a2799..93f09a0 100644 ---- a/hw/ppc/spapr_rtas.c -+++ b/hw/ppc/spapr_rtas.c -@@ -162,6 +162,7 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr, - if (cpu != NULL) { - CPUState *cs = CPU(cpu); - CPUPPCState *env = &cpu->env; -+ Error *local_err = NULL; - - if (!cs->halted) { - rtas_st(rets, 0, RTAS_OUT_HW_ERROR); -@@ -173,6 +174,14 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr, - * new cpu enters */ - kvm_cpu_synchronize_state(cs); - -+ /* Set compatibility mode to match existing cpus */ -+ ppc_set_compat(cpu, POWERPC_CPU(first_cpu)->compat_pvr, &local_err); -+ if (local_err) { -+ error_report_err(local_err); -+ rtas_st(rets, 0, RTAS_OUT_HW_ERROR); -+ return; -+ } -+ - env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME); - env->nip = start; - env->gpr[3] = r3; --- -1.8.3.1 - diff --git a/SOURCES/kvm-spapr-Correct-inverted-test-in-spapr_pc_dimm_node.patch b/SOURCES/kvm-spapr-Correct-inverted-test-in-spapr_pc_dimm_node.patch new file mode 100644 index 0000000..6c81cbb --- /dev/null +++ b/SOURCES/kvm-spapr-Correct-inverted-test-in-spapr_pc_dimm_node.patch @@ -0,0 +1,52 @@ +From 300af272a7b1546ccd40face0c3f6d325f81aa49 Mon Sep 17 00:00:00 2001 +From: David Gibson +Date: Tue, 17 Jul 2018 01:36:38 +0200 +Subject: [PATCH 46/89] spapr: Correct inverted test in spapr_pc_dimm_node() + +RH-Author: David Gibson +Message-id: <20180717013638.11012-1-dgibson@redhat.com> +Patchwork-id: 81371 +O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH] spapr: Correct inverted test in spapr_pc_dimm_node() +Bugzilla: 1598287 +RH-Acked-by: Igor Mammedov +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier + +From: David Gibson + +This function was introduced between v2.11 and v2.12 to replace obsolete +ways of specifying the NUMA nodes for DIMMs. It's used to find the correct +node for an LMB, by locating which DIMM object it lies within. + +Unfortunately, one of the checks is inverted, so we check whether the +address is less than two different things, rather than actually checking +a range. This introduced a regression, meaning that after a reboot qemu +will advertise incorrect node information for memory to the guest. + +Signed-off-by: David Gibson +Reviewed-by: Greg Kurz +Reviewed-by: Igor Mammedov +(cherry picked from commit ccc2cef8b3f1dedd059924eb8ec1a87eff8ef607) + +Signed-off-by: David Gibson +Signed-off-by: Miroslav Rezanina +--- + hw/ppc/spapr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c +index a580334..5f26aea 100644 +--- a/hw/ppc/spapr.c ++++ b/hw/ppc/spapr.c +@@ -659,7 +659,7 @@ static uint32_t spapr_pc_dimm_node(MemoryDeviceInfoList *list, ram_addr_t addr) + if (value && value->type == MEMORY_DEVICE_INFO_KIND_DIMM) { + PCDIMMDeviceInfo *pcdimm_info = value->u.dimm.data; + +- if (pcdimm_info->addr >= addr && ++ if (addr >= pcdimm_info->addr && + addr < (pcdimm_info->addr + pcdimm_info->size)) { + return pcdimm_info->node; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-spapr-Handle-Decimal-Floating-Point-DFP-as-an-option.patch b/SOURCES/kvm-spapr-Handle-Decimal-Floating-Point-DFP-as-an-option.patch deleted file mode 100644 index f24a783..0000000 --- a/SOURCES/kvm-spapr-Handle-Decimal-Floating-Point-DFP-as-an-option.patch +++ /dev/null @@ -1,143 +0,0 @@ -From 4e2f29e8fef6d8428bed4a5c366e5cafd7b92a41 Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Fri, 19 Jan 2018 02:34:40 +0100 -Subject: [PATCH 12/21] spapr: Handle Decimal Floating Point (DFP) as an - optional capability - -RH-Author: David Gibson -Message-id: <20180119023442.28577-6-dgibson@redhat.com> -Patchwork-id: 78672 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 5/7] spapr: Handle Decimal Floating Point (DFP) as an optional capability -Bugzilla: 1523414 -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth -RH-Acked-by: Miroslav Rezanina - -From: David Gibson - -Decimal Floating Point has been available on POWER7 and later (server) -cpus. However, it can be disabled on the hypervisor, meaning that it's -not available to guests. - -We currently handle this by conditionally advertising DFP support in the -device tree depending on whether the guest CPU model supports it - which -can also depend on what's allowed in the host for -cpu host. That can lead -to confusion on migration, since host properties are silently affecting -guest visible properties. - -This patch handles it by treating it as an optional capability for the -pseries machine type. - -Signed-off-by: David Gibson -Reviewed-by: Greg Kurz -(cherry picked from commit 2d1fb9bc8e6e78931d8e1bfeb0ed7a4d223b0480) -Signed-off-by: Miroslav Rezanina - -Conflicts: - hw/ppc/spapr.c - -Due to differences between upstream and downstream machine type -versions. As CAP_DFP is enabled for all upstream versions, enable it -for all downsteam as well. - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1523414 - -Signed-off-by: David Gibson ---- - hw/ppc/spapr.c | 7 ++++--- - hw/ppc/spapr_caps.c | 18 ++++++++++++++++++ - include/hw/ppc/spapr.h | 3 +++ - 3 files changed, 25 insertions(+), 3 deletions(-) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 0ef2af9..41cb2fa 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -575,7 +575,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, - /* Advertise DFP (Decimal Floating Point) if available - * 0 / no property == no DFP - * 1 == DFP available */ -- if (env->insns_flags2 & PPC2_DFP) { -+ if (spapr_has_cap(spapr, SPAPR_CAP_DFP)) { - _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1))); - } - -@@ -3650,7 +3650,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) - mc->numa_mem_align_shift = 28; - smc->has_power9_support = true; - -- smc->default_caps = spapr_caps(SPAPR_CAP_VSX); -+ smc->default_caps = spapr_caps(SPAPR_CAP_VSX | SPAPR_CAP_DFP); - spapr_caps_add_properties(smc, &error_abort); - } - -@@ -4056,7 +4056,8 @@ static void spapr_machine_rhel740_class_options(MachineClass *mc) - smc->has_power9_support = false; - smc->pre_2_10_has_unused_icps = true; - smc->resize_hpt_default = SPAPR_RESIZE_HPT_DISABLED; -- smc->default_caps = spapr_caps(SPAPR_CAP_HTM | SPAPR_CAP_VSX); -+ smc->default_caps = spapr_caps(SPAPR_CAP_HTM | SPAPR_CAP_VSX -+ | SPAPR_CAP_DFP); - } - - DEFINE_SPAPR_MACHINE(rhel740, "rhel7.4.0", false); -diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c -index 9f901fb..2b67ac2 100644 ---- a/hw/ppc/spapr_caps.c -+++ b/hw/ppc/spapr_caps.c -@@ -70,6 +70,16 @@ static void cap_vsx_allow(sPAPRMachineState *spapr, Error **errp) - } - } - -+static void cap_dfp_allow(sPAPRMachineState *spapr, Error **errp) -+{ -+ PowerPCCPU *cpu = POWERPC_CPU(first_cpu); -+ CPUPPCState *env = &cpu->env; -+ -+ if (!(env->insns_flags2 & PPC2_DFP)) { -+ error_setg(errp, "DFP support not available, try cap-dfp=off"); -+ } -+} -+ - static sPAPRCapabilityInfo capability_table[] = { - { - .name = "htm", -@@ -85,6 +95,13 @@ static sPAPRCapabilityInfo capability_table[] = { - .allow = cap_vsx_allow, - /* TODO: add cap_vsx_disallow */ - }, -+ { -+ .name = "dfp", -+ .description = "Allow Decimal Floating Point (DFP)", -+ .flag = SPAPR_CAP_DFP, -+ .allow = cap_dfp_allow, -+ /* TODO: add cap_dfp_disallow */ -+ }, - }; - - static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr, -@@ -104,6 +121,7 @@ static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr, - if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06, - 0, spapr->max_compat_pvr)) { - caps.mask &= ~SPAPR_CAP_VSX; -+ caps.mask &= ~SPAPR_CAP_DFP; - } - - return caps; -diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h -index 36f6816..df767c3 100644 ---- a/include/hw/ppc/spapr.h -+++ b/include/hw/ppc/spapr.h -@@ -62,6 +62,9 @@ typedef enum { - /* Vector Scalar Extensions */ - #define SPAPR_CAP_VSX 0x0000000000000002ULL - -+/* Decimal Floating Point */ -+#define SPAPR_CAP_DFP 0x0000000000000004ULL -+ - typedef struct sPAPRCapabilities sPAPRCapabilities; - struct sPAPRCapabilities { - uint64_t mask; --- -1.8.3.1 - diff --git a/SOURCES/kvm-spapr-Handle-VMX-VSX-presence-as-an-spapr-capability.patch b/SOURCES/kvm-spapr-Handle-VMX-VSX-presence-as-an-spapr-capability.patch deleted file mode 100644 index 9b07a7e..0000000 --- a/SOURCES/kvm-spapr-Handle-VMX-VSX-presence-as-an-spapr-capability.patch +++ /dev/null @@ -1,169 +0,0 @@ -From 268880a2fee41c5c1929aac996a3292db41233cb Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Fri, 19 Jan 2018 02:34:39 +0100 -Subject: [PATCH 11/21] spapr: Handle VMX/VSX presence as an spapr capability - flag - -RH-Author: David Gibson -Message-id: <20180119023442.28577-5-dgibson@redhat.com> -Patchwork-id: 78671 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 4/7] spapr: Handle VMX/VSX presence as an spapr capability flag -Bugzilla: 1523414 -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth -RH-Acked-by: Miroslav Rezanina - -From: David Gibson - -We currently have some conditionals in the spapr device tree code to decide -whether or not to advertise the availability of the VMX (aka Altivec) and -VSX vector extensions to the guest, based on whether the guest cpu has -those features. - -This can lead to confusion and subtle failures on migration, since it makes -a guest visible change based only on host capabilities. We now have a -better mechanism for this, in spapr capabilities flags, which explicitly -depend on user options rather than host capabilities. - -Rework the advertisement of VSX and VMX based on a new VSX capability. We -no longer bother with a conditional for VMX support, because every CPU -that's ever been supported by the pseries machine type supports VMX. - -NOTE: Some userspace distributions (e.g. RHEL7.4) already rely on -availability of VSX in libc, so using cap-vsx=off may lead to a fatal -SIGILL in init. - -Signed-off-by: David Gibson -Reviewed-by: Greg Kurz -(cherry picked from commit 2938664286499c0c30d6e455a7e2e5d3e6c3f63d) -Signed-off-by: Miroslav Rezanina - -Conflicts: - hw/ppc/spapr.c - -Because of the difference between upstream and downstream machine type -versions. Adjusted the logic to enable CAP_VSX on all downstream -machine types, as it is for all upstream types. - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1523414 - -Signed-off-by: David Gibson ---- - hw/ppc/spapr.c | 20 +++++++++++--------- - hw/ppc/spapr_caps.c | 25 +++++++++++++++++++++++++ - include/hw/ppc/spapr.h | 3 +++ - 3 files changed, 39 insertions(+), 9 deletions(-) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 846b906..0ef2af9 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -560,14 +560,16 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, - segs, sizeof(segs)))); - } - -- /* Advertise VMX/VSX (vector extensions) if available -- * 0 / no property == no vector extensions -+ /* Advertise VSX (vector extensions) if available - * 1 == VMX / Altivec available -- * 2 == VSX available */ -- if (env->insns_flags & PPC_ALTIVEC) { -- uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1; -- -- _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx))); -+ * 2 == VSX available -+ * -+ * Only CPUs for which we create core types in spapr_cpu_core.c -+ * are possible, and all of those have VMX */ -+ if (spapr_has_cap(spapr, SPAPR_CAP_VSX)) { -+ _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 2))); -+ } else { -+ _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 1))); - } - - /* Advertise DFP (Decimal Floating Point) if available -@@ -3648,7 +3650,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) - mc->numa_mem_align_shift = 28; - smc->has_power9_support = true; - -- smc->default_caps = spapr_caps(0); -+ smc->default_caps = spapr_caps(SPAPR_CAP_VSX); - spapr_caps_add_properties(smc, &error_abort); - } - -@@ -4054,7 +4056,7 @@ static void spapr_machine_rhel740_class_options(MachineClass *mc) - smc->has_power9_support = false; - smc->pre_2_10_has_unused_icps = true; - smc->resize_hpt_default = SPAPR_RESIZE_HPT_DISABLED; -- smc->default_caps = spapr_caps(SPAPR_CAP_HTM); -+ smc->default_caps = spapr_caps(SPAPR_CAP_HTM | SPAPR_CAP_VSX); - } - - DEFINE_SPAPR_MACHINE(rhel740, "rhel7.4.0", false); -diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c -index 2bdc202..9f901fb 100644 ---- a/hw/ppc/spapr_caps.c -+++ b/hw/ppc/spapr_caps.c -@@ -57,6 +57,19 @@ static void cap_htm_allow(sPAPRMachineState *spapr, Error **errp) - } - } - -+static void cap_vsx_allow(sPAPRMachineState *spapr, Error **errp) -+{ -+ PowerPCCPU *cpu = POWERPC_CPU(first_cpu); -+ CPUPPCState *env = &cpu->env; -+ -+ /* Allowable CPUs in spapr_cpu_core.c should already have gotten -+ * rid of anything that doesn't do VMX */ -+ g_assert(env->insns_flags & PPC_ALTIVEC); -+ if (!(env->insns_flags2 & PPC2_VSX)) { -+ error_setg(errp, "VSX support not available, try cap-vsx=off"); -+ } -+} -+ - static sPAPRCapabilityInfo capability_table[] = { - { - .name = "htm", -@@ -65,6 +78,13 @@ static sPAPRCapabilityInfo capability_table[] = { - .allow = cap_htm_allow, - /* TODO: add cap_htm_disallow */ - }, -+ { -+ .name = "vsx", -+ .description = "Allow Vector Scalar Extensions (VSX)", -+ .flag = SPAPR_CAP_VSX, -+ .allow = cap_vsx_allow, -+ /* TODO: add cap_vsx_disallow */ -+ }, - }; - - static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr, -@@ -81,6 +101,11 @@ static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr, - caps.mask &= ~SPAPR_CAP_HTM; - } - -+ if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06, -+ 0, spapr->max_compat_pvr)) { -+ caps.mask &= ~SPAPR_CAP_VSX; -+ } -+ - return caps; - } - -diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h -index f32967a..36f6816 100644 ---- a/include/hw/ppc/spapr.h -+++ b/include/hw/ppc/spapr.h -@@ -59,6 +59,9 @@ typedef enum { - /* Hardware Transactional Memory */ - #define SPAPR_CAP_HTM 0x0000000000000001ULL - -+/* Vector Scalar Extensions */ -+#define SPAPR_CAP_VSX 0x0000000000000002ULL -+ - typedef struct sPAPRCapabilities sPAPRCapabilities; - struct sPAPRCapabilities { - uint64_t mask; --- -1.8.3.1 - diff --git a/SOURCES/kvm-spapr-Implement-bug-in-spapr-vty-device-to-be-compat.patch b/SOURCES/kvm-spapr-Implement-bug-in-spapr-vty-device-to-be-compat.patch deleted file mode 100644 index 8f0afb6..0000000 --- a/SOURCES/kvm-spapr-Implement-bug-in-spapr-vty-device-to-be-compat.patch +++ /dev/null @@ -1,78 +0,0 @@ -From ea460580ae8d4910bddac476b25eb31c04b4e54c Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Mon, 27 Nov 2017 04:56:27 +0100 -Subject: [PATCH 5/7] spapr: Implement bug in spapr-vty device to be compatible - with PowerVM - -RH-Author: David Gibson -Message-id: <20171127045627.20341-1-dgibson@redhat.com> -Patchwork-id: 77896 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH] spapr: Implement bug in spapr-vty device to be compatible with PowerVM -Bugzilla: 1495090 -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier -RH-Acked-by: Miroslav Rezanina - -From: David Gibson - -The spapr-vty device implements the PAPR defined virtual console, -which is also implemented by IBM's proprietary PowerVM hypervisor. - -PowerVM's implementation has a bug where it inserts an extra \0 after -every \r going to the guest. Because of that Linux's guest side -driver has a workaround which strips \0 characters that appear -immediately after a \r. - -That means that when running under qemu, sending a binary stream from -host to guest via spapr-vty which happens to include a \r\0 sequence -will get corrupted by that workaround. - -To deal with that, this patch duplicates PowerVM's bug, inserting an -extra \0 after each \r. Ugly, but the best option available. - -Signed-off-by: David Gibson -Reviewed-by: Thomas Huth -Reviewed-by: Greg Kurz -(cherry picked from commit 6c3bc244d3cbdc5545504fda4fae0238ec36a3c0) - -Testing: Verified that when transferring a file (raw) through - spapr-vty device, '\r\0' sequences are no longer mangled. - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - hw/char/spapr_vty.c | 18 ++++++++++++++++++ - 1 file changed, 18 insertions(+) - -diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c -index 0fa416c..6748334 100644 ---- a/hw/char/spapr_vty.c -+++ b/hw/char/spapr_vty.c -@@ -58,6 +58,24 @@ static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max) - - while ((n < max) && (dev->out != dev->in)) { - buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE]; -+ -+ /* PowerVM's vty implementation has a bug where it inserts a -+ * \0 after every \r going to the guest. Existing guests have -+ * a workaround for this which removes every \0 immediately -+ * following a \r, so here we make ourselves bug-for-bug -+ * compatible, so that the guest won't drop a real \0-after-\r -+ * that happens to occur in a binary stream. */ -+ if (buf[n - 1] == '\r') { -+ if (n < max) { -+ buf[n++] = '\0'; -+ } else { -+ /* No room for the extra \0, roll back and try again -+ * next time */ -+ dev->out--; -+ n--; -+ break; -+ } -+ } - } - - qemu_chr_fe_accept_input(&dev->chardev); --- -1.8.3.1 - diff --git a/SOURCES/kvm-spapr-Remove-unnecessary-options-field-from-sPAPRCap.patch b/SOURCES/kvm-spapr-Remove-unnecessary-options-field-from-sPAPRCap.patch deleted file mode 100644 index 91d81b1..0000000 --- a/SOURCES/kvm-spapr-Remove-unnecessary-options-field-from-sPAPRCap.patch +++ /dev/null @@ -1,83 +0,0 @@ -From 146d96d35b69fea9311b15de60eb85a076ec2e14 Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Fri, 19 Jan 2018 02:34:42 +0100 -Subject: [PATCH 14/21] spapr: Remove unnecessary 'options' field from - sPAPRCapabilityInfo - -RH-Author: David Gibson -Message-id: <20180119023442.28577-8-dgibson@redhat.com> -Patchwork-id: 78673 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 7/7] spapr: Remove unnecessary 'options' field from sPAPRCapabilityInfo -Bugzilla: 1523414 -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth -RH-Acked-by: Miroslav Rezanina - -From: David Gibson - -The options field here is intended to list the available values for the -capability. It's not used yet, because the existing capabilities are -boolean. - -We're going to add capabilities that aren't, but in that case the info on -the possible values can be folded into the .description field. - -Signed-off-by: David Gibson -(cherry picked from commit 895d5cd620d358c2623c639a150d9320d581b4f8) - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1523414 - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr_caps.c | 6 +----- - 1 file changed, 1 insertion(+), 5 deletions(-) - -diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c -index f95a785..d5c9ce7 100644 ---- a/hw/ppc/spapr_caps.c -+++ b/hw/ppc/spapr_caps.c -@@ -35,7 +35,6 @@ - typedef struct sPAPRCapabilityInfo { - const char *name; - const char *description; -- const char *options; /* valid capability values */ - int index; - - /* Getter and Setter Function Pointers */ -@@ -126,7 +125,6 @@ sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = { - [SPAPR_CAP_HTM] = { - .name = "htm", - .description = "Allow Hardware Transactional Memory (HTM)", -- .options = "", - .index = SPAPR_CAP_HTM, - .get = spapr_cap_get_bool, - .set = spapr_cap_set_bool, -@@ -136,7 +134,6 @@ sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = { - [SPAPR_CAP_VSX] = { - .name = "vsx", - .description = "Allow Vector Scalar Extensions (VSX)", -- .options = "", - .index = SPAPR_CAP_VSX, - .get = spapr_cap_get_bool, - .set = spapr_cap_set_bool, -@@ -146,7 +143,6 @@ sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = { - [SPAPR_CAP_DFP] = { - .name = "dfp", - .description = "Allow Decimal Floating Point (DFP)", -- .options = "", - .index = SPAPR_CAP_DFP, - .get = spapr_cap_get_bool, - .set = spapr_cap_set_bool, -@@ -338,7 +334,7 @@ void spapr_caps_add_properties(sPAPRMachineClass *smc, Error **errp) - return; - } - -- desc = g_strdup_printf("%s%s", cap->description, cap->options); -+ desc = g_strdup_printf("%s", cap->description); - object_class_property_set_description(klass, name, desc, &local_err); - g_free(desc); - if (local_err) { --- -1.8.3.1 - diff --git a/SOURCES/kvm-spapr-Treat-Hardware-Transactional-Memory-HTM-as-an-.patch b/SOURCES/kvm-spapr-Treat-Hardware-Transactional-Memory-HTM-as-an-.patch deleted file mode 100644 index 1c092af..0000000 --- a/SOURCES/kvm-spapr-Treat-Hardware-Transactional-Memory-HTM-as-an-.patch +++ /dev/null @@ -1,193 +0,0 @@ -From 423e8d79df3ef4548d74854a8feeee84cd5e159c Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Fri, 19 Jan 2018 02:34:37 +0100 -Subject: [PATCH 09/21] spapr: Treat Hardware Transactional Memory (HTM) as an - optional capability - -RH-Author: David Gibson -Message-id: <20180119023442.28577-3-dgibson@redhat.com> -Patchwork-id: 78670 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 2/7] spapr: Treat Hardware Transactional Memory (HTM) as an optional capability -Bugzilla: 1523414 -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth -RH-Acked-by: Miroslav Rezanina - -From: David Gibson - -This adds an spapr capability bit for Hardware Transactional Memory. It is -enabled by default for pseries-2.11 and earlier machine types. with POWER8 -or later CPUs (as it must be, since earlier qemu versions would implicitly -allow it). However it is disabled by default for the latest pseries-2.12 -machine type. - -This means that with the latest machine type, HTM will not be available, -regardless of CPU, unless it is explicitly enabled on the command line. -That change is made on the basis that: - - * This way running with -M pseries,accel=tcg will start with whatever cpu - and will provide the same guest visible model as with accel=kvm. - - More specifically, this means existing make check tests don't have - to be modified to use cap-htm=off in order to run with TCG - - * We hope to add a new "HTM without suspend" feature in the not too - distant future which could work on both POWER8 and POWER9 cpus, and - could be enabled by default. - - * Best guesses suggest that future POWER cpus may well only support the - HTM-without-suspend model, not the (frankly, horribly overcomplicated) - POWER8 style HTM with suspend. - - * Anecdotal evidence suggests problems with HTM being enabled when it - wasn't wanted are more common than being missing when it was. - -Signed-off-by: David Gibson -Reviewed-by: Greg Kurz -(cherry picked from commit ee76a09fc72cfbfab2bb5529320ef7e460adffd8) -Signed-off-by: Miroslav Rezanina - -Conflicts: - hw/ppc/spapr.c - -Conflicts due to replacement of upstream machine types with downstream -ones. Omitted original logic since it affects the 2.11 machine type -which isn't in downstream (even in comments). Replaced with logic to -enable HTM capability only for pseries-rhel7.4.0 and earlier machine -types. - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1523414 - -Signed-off-by: David Gibson ---- - hw/ppc/spapr.c | 13 ++++++++----- - hw/ppc/spapr_caps.c | 29 ++++++++++++++++++++++++++++- - include/hw/ppc/spapr.h | 3 +++ - 3 files changed, 39 insertions(+), 6 deletions(-) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 7a4191d..2068a1f 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -253,7 +253,9 @@ static int spapr_fixup_cpu_numa_dt(void *fdt, int offset, PowerPCCPU *cpu) - } - - /* Populate the "ibm,pa-features" property */ --static void spapr_populate_pa_features(PowerPCCPU *cpu, void *fdt, int offset, -+static void spapr_populate_pa_features(sPAPRMachineState *spapr, -+ PowerPCCPU *cpu, -+ void *fdt, int offset, - bool legacy_guest) - { - CPUPPCState *env = &cpu->env; -@@ -318,7 +320,7 @@ static void spapr_populate_pa_features(PowerPCCPU *cpu, void *fdt, int offset, - */ - pa_features[3] |= 0x20; - } -- if (kvmppc_has_cap_htm() && pa_size > 24) { -+ if (spapr_has_cap(spapr, SPAPR_CAP_HTM) && pa_size > 24) { - pa_features[24] |= 0x80; /* Transactional memory support */ - } - if (legacy_guest && pa_size > 40) { -@@ -385,8 +387,8 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPRMachineState *spapr) - return ret; - } - -- spapr_populate_pa_features(cpu, fdt, offset, -- spapr->cas_legacy_guest_workaround); -+ spapr_populate_pa_features(spapr, cpu, fdt, offset, -+ spapr->cas_legacy_guest_workaround); - } - return ret; - } -@@ -582,7 +584,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, - page_sizes_prop, page_sizes_prop_size))); - } - -- spapr_populate_pa_features(cpu, fdt, offset, false); -+ spapr_populate_pa_features(spapr, cpu, fdt, offset, false); - - _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", - cs->cpu_index / vcpus_per_socket))); -@@ -4046,6 +4048,7 @@ static void spapr_machine_rhel740_class_options(MachineClass *mc) - smc->has_power9_support = false; - smc->pre_2_10_has_unused_icps = true; - smc->resize_hpt_default = SPAPR_RESIZE_HPT_DISABLED; -+ smc->default_caps = spapr_caps(SPAPR_CAP_HTM); - } - - DEFINE_SPAPR_MACHINE(rhel740, "rhel7.4.0", false); -diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c -index 968ba7b..3b35b91 100644 ---- a/hw/ppc/spapr_caps.c -+++ b/hw/ppc/spapr_caps.c -@@ -24,6 +24,10 @@ - #include "qemu/osdep.h" - #include "qapi/error.h" - #include "qapi/visitor.h" -+#include "sysemu/hw_accel.h" -+#include "target/ppc/cpu.h" -+#include "cpu-models.h" -+#include "kvm_ppc.h" - - #include "hw/ppc/spapr.h" - -@@ -40,18 +44,41 @@ typedef struct sPAPRCapabilityInfo { - void (*disallow)(sPAPRMachineState *spapr, Error **errp); - } sPAPRCapabilityInfo; - -+static void cap_htm_allow(sPAPRMachineState *spapr, Error **errp) -+{ -+ if (tcg_enabled()) { -+ error_setg(errp, -+ "No Transactional Memory support in TCG, try cap-htm=off"); -+ } else if (kvm_enabled() && !kvmppc_has_cap_htm()) { -+ error_setg(errp, -+"KVM implementation does not support Transactional Memory, try cap-htm=off" -+ ); -+ } -+} -+ - static sPAPRCapabilityInfo capability_table[] = { -+ { -+ .name = "htm", -+ .description = "Allow Hardware Transactional Memory (HTM)", -+ .flag = SPAPR_CAP_HTM, -+ .allow = cap_htm_allow, -+ /* TODO: add cap_htm_disallow */ -+ }, - }; - - static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr, - CPUState *cs) - { - sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); -+ PowerPCCPU *cpu = POWERPC_CPU(cs); - sPAPRCapabilities caps; - - caps = smc->default_caps; - -- /* TODO: clamp according to cpu model */ -+ if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07, -+ 0, spapr->max_compat_pvr)) { -+ caps.mask &= ~SPAPR_CAP_HTM; -+ } - - return caps; - } -diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h -index 7267151..77dc3fb 100644 ---- a/include/hw/ppc/spapr.h -+++ b/include/hw/ppc/spapr.h -@@ -54,6 +54,9 @@ typedef enum { - * Capabilities - */ - -+/* Hardware Transactional Memory */ -+#define SPAPR_CAP_HTM 0x0000000000000001ULL -+ - typedef struct sPAPRCapabilities sPAPRCapabilities; - struct sPAPRCapabilities { - uint64_t mask; --- -1.8.3.1 - diff --git a/SOURCES/kvm-spapr-Validate-capabilities-on-migration.patch b/SOURCES/kvm-spapr-Validate-capabilities-on-migration.patch deleted file mode 100644 index 0132d15..0000000 --- a/SOURCES/kvm-spapr-Validate-capabilities-on-migration.patch +++ /dev/null @@ -1,240 +0,0 @@ -From a6549068139448cfd38e4b1e602fbaba5ed32a97 Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Fri, 19 Jan 2018 02:34:38 +0100 -Subject: [PATCH 10/21] spapr: Validate capabilities on migration - -RH-Author: David Gibson -Message-id: <20180119023442.28577-4-dgibson@redhat.com> -Patchwork-id: 78669 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 3/7] spapr: Validate capabilities on migration -Bugzilla: 1523414 -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth -RH-Acked-by: Miroslav Rezanina - -From: David Gibson - -Now that the "pseries" machine type implements optional capabilities (well, -one so far) there's the possibility of having different capabilities -available at either end of a migration. Although arguably a user error, -it would be nice to catch this situation and fail as gracefully as we can. - -This adds code to migrate the capabilities flags. These aren't pulled -directly into the destination's configuration since what the user has -specified on the destination command line should take precedence. However, -they are checked against the destination capabilities. - -If the source was using a capability which is absent on the destination, -we fail the migration, since that could easily cause a guest crash or other -bad behaviour. If the source lacked a capability which is present on the -destination we warn, but allow the migration to proceed. - -Signed-off-by: David Gibson -Reviewed-by: Greg Kurz -(cherry picked from commit be85537d654565e35e359a74b46fc08b7956525c) - -Adjusted because we don't have 44b1ff31 "migration: pre_save return -int" downstream, which means spapr_caps_pre_save() needs a different -type. - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1523414 - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr.c | 6 ++++ - hw/ppc/spapr_caps.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++-- - include/hw/ppc/spapr.h | 6 ++++ - 3 files changed, 104 insertions(+), 3 deletions(-) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 2068a1f..846b906 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -1547,6 +1547,11 @@ static int spapr_post_load(void *opaque, int version_id) - sPAPRMachineState *spapr = (sPAPRMachineState *)opaque; - int err = 0; - -+ err = spapr_caps_post_migration(spapr); -+ if (err) { -+ return err; -+ } -+ - if (!object_dynamic_cast(OBJECT(spapr->ics), TYPE_ICS_KVM)) { - CPUState *cs; - CPU_FOREACH(cs) { -@@ -1713,6 +1718,7 @@ static const VMStateDescription vmstate_spapr = { - &vmstate_spapr_ov5_cas, - &vmstate_spapr_patb_entry, - &vmstate_spapr_pending_events, -+ &vmstate_spapr_caps, - NULL - } - }; -diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c -index 3b35b91..2bdc202 100644 ---- a/hw/ppc/spapr_caps.c -+++ b/hw/ppc/spapr_caps.c -@@ -22,6 +22,7 @@ - * THE SOFTWARE. - */ - #include "qemu/osdep.h" -+#include "qemu/error-report.h" - #include "qapi/error.h" - #include "qapi/visitor.h" - #include "sysemu/hw_accel.h" -@@ -83,6 +84,92 @@ static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr, - return caps; - } - -+static bool spapr_caps_needed(void *opaque) -+{ -+ sPAPRMachineState *spapr = opaque; -+ -+ return (spapr->forced_caps.mask != 0) || (spapr->forbidden_caps.mask != 0); -+} -+ -+/* This has to be called from the top-level spapr post_load, not the -+ * caps specific one. Otherwise it wouldn't be called when the source -+ * caps are all defaults, which could still conflict with overridden -+ * caps on the destination */ -+int spapr_caps_post_migration(sPAPRMachineState *spapr) -+{ -+ uint64_t allcaps = 0; -+ int i; -+ bool ok = true; -+ sPAPRCapabilities dstcaps = spapr->effective_caps; -+ sPAPRCapabilities srccaps; -+ -+ srccaps = default_caps_with_cpu(spapr, first_cpu); -+ srccaps.mask |= spapr->mig_forced_caps.mask; -+ srccaps.mask &= ~spapr->mig_forbidden_caps.mask; -+ -+ for (i = 0; i < ARRAY_SIZE(capability_table); i++) { -+ sPAPRCapabilityInfo *info = &capability_table[i]; -+ -+ allcaps |= info->flag; -+ -+ if ((srccaps.mask & info->flag) && !(dstcaps.mask & info->flag)) { -+ error_report("cap-%s=on in incoming stream, but off in destination", -+ info->name); -+ ok = false; -+ } -+ -+ if (!(srccaps.mask & info->flag) && (dstcaps.mask & info->flag)) { -+ warn_report("cap-%s=off in incoming stream, but on in destination", -+ info->name); -+ } -+ } -+ -+ if (spapr->mig_forced_caps.mask & ~allcaps) { -+ error_report( -+ "Unknown capabilities 0x%"PRIx64" enabled in incoming stream", -+ spapr->mig_forced_caps.mask & ~allcaps); -+ ok = false; -+ } -+ if (spapr->mig_forbidden_caps.mask & ~allcaps) { -+ warn_report( -+ "Unknown capabilities 0x%"PRIx64" disabled in incoming stream", -+ spapr->mig_forbidden_caps.mask & ~allcaps); -+ } -+ -+ return ok ? 0 : -EINVAL; -+} -+ -+static void spapr_caps_pre_save(void *opaque) -+{ -+ sPAPRMachineState *spapr = opaque; -+ -+ spapr->mig_forced_caps = spapr->forced_caps; -+ spapr->mig_forbidden_caps = spapr->forbidden_caps; -+} -+ -+static int spapr_caps_pre_load(void *opaque) -+{ -+ sPAPRMachineState *spapr = opaque; -+ -+ spapr->mig_forced_caps = spapr_caps(0); -+ spapr->mig_forbidden_caps = spapr_caps(0); -+ return 0; -+} -+ -+const VMStateDescription vmstate_spapr_caps = { -+ .name = "spapr/caps", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .needed = spapr_caps_needed, -+ .pre_save = spapr_caps_pre_save, -+ .pre_load = spapr_caps_pre_load, -+ .fields = (VMStateField[]) { -+ VMSTATE_UINT64(mig_forced_caps.mask, sPAPRMachineState), -+ VMSTATE_UINT64(mig_forbidden_caps.mask, sPAPRMachineState), -+ VMSTATE_END_OF_LIST() -+ }, -+}; -+ - void spapr_caps_reset(sPAPRMachineState *spapr) - { - Error *local_err = NULL; -@@ -92,6 +179,11 @@ void spapr_caps_reset(sPAPRMachineState *spapr) - /* First compute the actual set of caps we're running with.. */ - caps = default_caps_with_cpu(spapr, first_cpu); - -+ /* Remove unnecessary forced/forbidden bits (this will help us -+ * with migration) */ -+ spapr->forced_caps.mask &= ~caps.mask; -+ spapr->forbidden_caps.mask &= caps.mask; -+ - caps.mask |= spapr->forced_caps.mask; - caps.mask &= ~spapr->forbidden_caps.mask; - -@@ -175,9 +267,6 @@ void spapr_caps_validate(sPAPRMachineState *spapr, Error **errp) - error_setg(errp, "Some sPAPR capabilities set both on and off"); - return; - } -- -- /* Check for any caps incompatible with other caps. Nothing to do -- * yet */ - } - - void spapr_caps_add_properties(sPAPRMachineClass *smc, Error **errp) -diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h -index 77dc3fb..f32967a 100644 ---- a/include/hw/ppc/spapr.h -+++ b/include/hw/ppc/spapr.h -@@ -54,6 +54,8 @@ typedef enum { - * Capabilities - */ - -+/* These bits go in the migration stream, so they can't be reassigned */ -+ - /* Hardware Transactional Memory */ - #define SPAPR_CAP_HTM 0x0000000000000001ULL - -@@ -144,6 +146,7 @@ struct sPAPRMachineState { - const char *icp_type; - - sPAPRCapabilities forced_caps, forbidden_caps; -+ sPAPRCapabilities mig_forced_caps, mig_forbidden_caps; - sPAPRCapabilities effective_caps; - }; - -@@ -726,6 +729,8 @@ void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg); - /* - * Handling of optional capabilities - */ -+extern const VMStateDescription vmstate_spapr_caps; -+ - static inline sPAPRCapabilities spapr_caps(uint64_t mask) - { - sPAPRCapabilities caps = { mask }; -@@ -740,5 +745,6 @@ static inline bool spapr_has_cap(sPAPRMachineState *spapr, uint64_t cap) - void spapr_caps_reset(sPAPRMachineState *spapr); - void spapr_caps_validate(sPAPRMachineState *spapr, Error **errp); - void spapr_caps_add_properties(sPAPRMachineClass *smc, Error **errp); -+int spapr_caps_post_migration(sPAPRMachineState *spapr); - - #endif /* HW_SPAPR_H */ --- -1.8.3.1 - diff --git a/SOURCES/kvm-spapr-add-missing-break-in-h_get_cpu_characteristics.patch b/SOURCES/kvm-spapr-add-missing-break-in-h_get_cpu_characteristics.patch deleted file mode 100644 index 5ebab62..0000000 --- a/SOURCES/kvm-spapr-add-missing-break-in-h_get_cpu_characteristics.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 72c1a30661e94a58a347dd6341dd8cabdc23d2dc Mon Sep 17 00:00:00 2001 -From: Suraj Jitindar Singh -Date: Tue, 13 Feb 2018 04:12:30 +0100 -Subject: [PATCH 13/15] spapr: add missing break in h_get_cpu_characteristics() - -RH-Author: Suraj Jitindar Singh -Message-id: <1518495150-24134-10-git-send-email-sursingh@redhat.com> -Patchwork-id: 78985 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 9/9] spapr: add missing break in h_get_cpu_characteristics() -Bugzilla: 1532050 -RH-Acked-by: David Gibson -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth - -From: Greg Kurz - -Detected by Coverity (CID 1385702). This fixes the recently added hypercall -to let guests properly apply Spectre and Meltdown workarounds. - -Fixes: c59704b25473 "target/ppc/spapr: Add H-Call H_GET_CPU_CHARACTERISTICS" -Reported-by: Paolo Bonzini -Signed-off-by: Greg Kurz -Reviewed-by: Suraj Jitindar Singh -Signed-off-by: David Gibson -(cherry picked from commit fa86f59234919b479b7e8da6b0dc2dad894a5eac) - -Conflicts: none - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1532050 - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr_hcall.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c -index 21247cd..d3f811a 100644 ---- a/hw/ppc/spapr_hcall.c -+++ b/hw/ppc/spapr_hcall.c -@@ -1672,6 +1672,7 @@ static target_ulong h_get_cpu_characteristics(PowerPCCPU *cpu, - switch (safe_indirect_branch) { - case SPAPR_CAP_FIXED: - characteristics |= H_CPU_CHAR_BCCTRL_SERIALISED; -+ break; - default: /* broken */ - assert(safe_indirect_branch == SPAPR_CAP_BROKEN); - break; --- -1.8.3.1 - diff --git a/SOURCES/kvm-spapr-disable-cpu-hot-remove.patch b/SOURCES/kvm-spapr-disable-cpu-hot-remove.patch deleted file mode 100644 index 146c090..0000000 --- a/SOURCES/kvm-spapr-disable-cpu-hot-remove.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 3d76fc1a1b8041c952d398140832460f16b7eade Mon Sep 17 00:00:00 2001 -From: Igor Mammedov -Date: Thu, 19 Oct 2017 15:28:13 +0200 -Subject: [PATCH 68/69] spapr: disable cpu hot-remove - -RH-Author: Igor Mammedov -Message-id: <1508426893-172020-1-git-send-email-imammedo@redhat.com> -Patchwork-id: 77378 -O-Subject: [RHV7.5 qemu-kvm-ma PATCH v2] spapr: disable cpu hot-remove -Bugzilla: 1499320 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Thomas Huth -RH-Acked-by: David Gibson - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1499320 -Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=14301295 -Upstream: RHEL-only - -Rebase to 2.10 brought in cpu hot-remove with it, disable it -for qemu-kvm-ma variant of QEMU where it hasn't been supported. -Use CONFIG_RHV to switch unplug off only for qemu-kvm-ma and -not to affect RHEV variant built from the same source code. - -Signed-off-by: Igor Mammedov ---- -v2: - - use CONFIG_RHV to not break RHEV build - -Thanks to Laszlo for hints to use CONFIG_RHV! - -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 3c598fd..5fe7769 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -3148,6 +3148,7 @@ static - void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev, - Error **errp) - { -+#if defined(CONFIG_RHV) - int index; - sPAPRDRConnector *drc; - CPUCore *cc = CPU_CORE(dev); -@@ -3169,6 +3170,9 @@ void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev, - spapr_drc_detach(drc); - - spapr_hotplug_req_remove_by_index(drc); -+#else -+ error_setg(errp, "this feature or command is not currently supported"); -+#endif /* CONFIG_RHV */ - } - - static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev, --- -1.8.3.1 - diff --git a/SOURCES/kvm-spapr-disable-memory-hotplug.patch b/SOURCES/kvm-spapr-disable-memory-hotplug.patch deleted file mode 100644 index 7b28b71..0000000 --- a/SOURCES/kvm-spapr-disable-memory-hotplug.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 437d5386e39a7955bf7a08c3af4d34ac74d677a2 Mon Sep 17 00:00:00 2001 -From: Igor Mammedov -Date: Wed, 31 Jan 2018 10:44:31 +0100 -Subject: [PATCH 8/8] spapr: disable memory hotplug - -RH-Author: Igor Mammedov -Message-id: <1517395471-44118-1-git-send-email-imammedo@redhat.com> -Patchwork-id: 78748 -O-Subject: [RHV7.5 qemu-kvm-ma PATCH v3] spapr: disable memory hotplug -Bugzilla: 1535952 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Laurent Vivier -RH-Acked-by: Dr. David Alan Gilbert - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1535952 -Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=15146188 -Upstream: RHEL-only - -Disable memory hotplug for qemu-kvm-ma variant of QEMU where -shouldn't be supported. -Use CONFIG_RHV to switch feature off only for qemu-kvm-ma and -not to affect RHEV variant built from the same source code. - -PS: -Disable only (un)plug entry points from device_add/del and -leave the rest of hotplug hw intact so that -ma machine -could be migrated to -rhev. -Note: backward migration would be broken if source -rhev -machine used pc-dimm devices (either with -device/device_add) - -Signed-off-by: Igor Mammedov -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 4f1ab14..6c4c088 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -2992,6 +2992,9 @@ out: - static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, - Error **errp) - { -+#if !defined(CONFIG_RHV) -+ error_setg(errp, "Memory hotplug not supported for this machine"); -+#else - PCDIMMDevice *dimm = PC_DIMM(dev); - PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm); - MemoryRegion *mr; -@@ -3019,6 +3022,7 @@ static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, - - out: - g_free(mem_dev); -+#endif - } - - struct sPAPRDIMMState { -@@ -3132,6 +3136,9 @@ void spapr_lmb_release(DeviceState *dev) - static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) - { -+#if !defined(CONFIG_RHV) -+ error_setg(errp, "Memory hot unplug not supported for this machine"); -+#else - sPAPRMachineState *spapr = SPAPR_MACHINE(hotplug_dev); - Error *local_err = NULL; - PCDIMMDevice *dimm = PC_DIMM(dev); -@@ -3186,6 +3193,7 @@ static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev, - nr_lmbs, spapr_drc_index(drc)); - out: - error_propagate(errp, local_err); -+#endif - } - - static void *spapr_populate_hotplug_cpu_dt(CPUState *cs, int *fdt_offset, --- -1.8.3.1 - diff --git a/SOURCES/kvm-spapr-don-t-initialize-PATB-entry-if-max-cpu-compat-.patch b/SOURCES/kvm-spapr-don-t-initialize-PATB-entry-if-max-cpu-compat-.patch deleted file mode 100644 index 5ad7b3e..0000000 --- a/SOURCES/kvm-spapr-don-t-initialize-PATB-entry-if-max-cpu-compat-.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 19ab0de29b4a853622fbccccf957f6a2c44466f3 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Tue, 19 Dec 2017 10:42:36 +0100 -Subject: [PATCH 01/42] spapr: don't initialize PATB entry if max-cpu-compat < - power9 - -RH-Author: Laurent Vivier -Message-id: <20171219104236.22556-1-lvivier@redhat.com> -Patchwork-id: 78413 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH] spapr: don't initialize PATB entry if max-cpu-compat < power9 -Bugzilla: 1525866 -RH-Acked-by: David Gibson -RH-Acked-by: Thomas Huth -RH-Acked-by: Eduardo Habkost - -BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1525866 -BREW: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=14815605 - s390x build is broken (binutils is missing), build only the others -Tested: I tested this patch with upstream QEMU. - As it is difficult to have a P9 host in beaker to check migration - to P8 host, I didn't re-test it with downstream build - (but I have asked QE to do) - -if KVM is enabled and KVM capabilities MMU radix is available, -the partition table entry (patb_entry) for the radix mode is -initialized by default in ppc_spapr_reset(). - -It's a problem if we want to migrate the guest to a POWER8 host -while the kernel is not started to set the value to the one -expected for a POWER8 CPU. - -The "-machine max-cpu-compat=power8" should allow to migrate -a POWER9 KVM host to a POWER8 KVM host, but because patb_entry -is set, the destination QEMU tries to enable radix mode on the -POWER8 host. This fails and cancels the migration: - - Process table config unsupported by the host - error while loading state for instance 0x0 of device 'spapr' - load of migration failed: Invalid argument - -This patch doesn't set the PATB entry if the user provides -a CPU compatibility mode that doesn't support radix mode. - -Signed-off-by: Laurent Vivier -Signed-off-by: David Gibson -(cherry picked from commit 1481fe5fcfeb7fcf3c1ebb9d8c0432e3e0188ccf) -Signed-off-by: Laurent Vivier -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index af7a3bb..d320b6c 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -1424,7 +1424,10 @@ static void ppc_spapr_reset(void) - /* Check for unknown sysbus devices */ - foreach_dynamic_sysbus_device(find_unknown_sysbus_device, NULL); - -- if (kvm_enabled() && kvmppc_has_cap_mmu_radix()) { -+ first_ppc_cpu = POWERPC_CPU(first_cpu); -+ if (kvm_enabled() && kvmppc_has_cap_mmu_radix() && -+ ppc_check_compat(first_ppc_cpu, CPU_POWERPC_LOGICAL_3_00, 0, -+ spapr->max_compat_pvr)) { - /* If using KVM with radix mode available, VCPUs can be started - * without a HPT because KVM will start them in radix mode. - * Set the GR bit in PATB so that we know there is no HPT. */ -@@ -1483,7 +1486,6 @@ static void ppc_spapr_reset(void) - g_free(fdt); - - /* Set up the entry state */ -- first_ppc_cpu = POWERPC_CPU(first_cpu); - first_ppc_cpu->env.gpr[3] = fdt_addr; - first_ppc_cpu->env.gpr[5] = 0; - first_cpu->halted = 0; --- -1.8.3.1 - diff --git a/SOURCES/kvm-spapr-fix-CAS-generated-reset.patch b/SOURCES/kvm-spapr-fix-CAS-generated-reset.patch deleted file mode 100644 index a221208..0000000 --- a/SOURCES/kvm-spapr-fix-CAS-generated-reset.patch +++ /dev/null @@ -1,63 +0,0 @@ -From bc0dcb3a78edf2eb8df0509d4862bb9ff36c4332 Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Wed, 4 Oct 2017 05:40:14 +0200 -Subject: [PATCH 07/34] spapr: fix CAS-generated reset -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: David Gibson -Message-id: <20171004054014.14159-5-dgibson@redhat.com> -Patchwork-id: 76802 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 4/4] spapr: fix CAS-generated reset -Bugzilla: 1448344 -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth -RH-Acked-by: Miroslav Rezanina - -From: Cédric Le Goater - -The OV5_MMU_RADIX_300 requires special handling in the CAS negotiation -process. It is cleared from the option vector of the guest before -evaluating the changes and re-added later. But, when testing for a -possible CAS reset : - - spapr->cas_reboot = spapr_ovec_diff(ov5_updates, - ov5_cas_old, spapr->ov5_cas); - -the bit OV5_MMU_RADIX_300 will each time be seen as removed from the -previous OV5 set, hence generating a reset loop. - -Fix this problem by also clearing the same bit in the ov5_cas_old set. - -Signed-off-by: Cédric Le Goater -Signed-off-by: David Gibson -(cherry picked from commit 30bf9ed1684da582e47ae004f8f3cf14fd6f39dd) - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr_hcall.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c -index 07b3da8..92f1e21 100644 ---- a/hw/ppc/spapr_hcall.c -+++ b/hw/ppc/spapr_hcall.c -@@ -1575,6 +1575,13 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, - * to worry about this for now. - */ - ov5_cas_old = spapr_ovec_clone(spapr->ov5_cas); -+ -+ /* also clear the radix/hash bit from the current ov5_cas bits to -+ * be in sync with the newly ov5 bits. Else the radix bit will be -+ * seen as being removed and this will generate a reset loop -+ */ -+ spapr_ovec_clear(ov5_cas_old, OV5_MMU_RADIX_300); -+ - /* full range of negotiated ov5 capabilities */ - spapr_ovec_intersect(spapr->ov5_cas, spapr->ov5, ov5_guest); - spapr_ovec_cleanup(ov5_guest); --- -1.8.3.1 - diff --git a/SOURCES/kvm-spapr-fix-device-tree-properties-when-using-compatib.patch b/SOURCES/kvm-spapr-fix-device-tree-properties-when-using-compatib.patch deleted file mode 100644 index ed719f7..0000000 --- a/SOURCES/kvm-spapr-fix-device-tree-properties-when-using-compatib.patch +++ /dev/null @@ -1,164 +0,0 @@ -From 384d7ebbde836477e00c19dbe5f68ece3e0fad1e Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Mon, 22 Jan 2018 16:48:48 +0100 -Subject: [PATCH 21/21] spapr: fix device tree properties when using - compatibility mode - -RH-Author: Laurent Vivier -Message-id: <20180122164848.20486-1-lvivier@redhat.com> -Patchwork-id: 78694 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH v2] spapr: fix device tree properties when using compatibility mode -Bugzilla: 1535752 -RH-Acked-by: Thomas Huth -RH-Acked-by: David Gibson -RH-Acked-by: Miroslav Rezanina - -From: Greg Kurz - -Commit 51f84465dd98 changed the compatility mode setting logic: -- machine reset only sets compatibility mode for the boot CPU -- compatibility mode is set for other CPUs when they are put online - by the guest with the "start-cpu" RTAS call - -This causes a regression for machines started with max-compat-cpu: -the device tree nodes related to secondary CPU cores contain wrong -"cpu-version" and "ibm,pa-features" values, as shown below. - -Guest started on a POWER8 host with: - -smp cores=2 -machine pseries,max-cpu-compat=compat7 - - ibm,pa-features = [18 00 f6 3f c7 c0 80 f0 80 00 - 00 00 00 00 00 00 00 00 80 00 80 00 80 00 00 00]; - cpu-version = <0x4d0200>; - - ^^^ - second CPU core - - ibm,pa-features = <0x600f63f 0xc70080c0>; - cpu-version = <0xf000003>; - - ^^^ - boot CPU core - -The second core is advertised in raw POWER8 mode. This happens because -CAS assumes all CPUs to have the same compatibility mode. Since the -boot CPU already has the requested compatibility mode, the CAS code -does not set it for the secondary one, and exposes the bogus device -tree properties in in the CAS response to the guest. - -A similar situation is observed when hot-plugging a CPU core. The -related device tree properties are generated and exposed to guest -with the "ibm,configure-connector" RTAS before "start-cpu" is called. -The CPU core is advertised to the guest in raw mode as well. - -It both cases, it boils down to the fact that "start-cpu" happens too -late. This can be fixed globally by propagating the compatibility mode -of the boot CPU to the other CPUs during reset. For this to work, the -compatibility mode of the boot CPU must be set before the machine code -actually resets all CPUs. - -It is not needed to set the compatibility mode in "start-cpu" anymore, -so the code is dropped. - -Fixes: 51f84465dd98 -Signed-off-by: Greg Kurz -Signed-off-by: David Gibson -(cherry picked from commit 9012a53f067a78022947e18050b145c34a3dc599) -Signed-off-by: Laurent Vivier -Signed-off-by: Miroslav Rezanina - -Conflicts: - hw/ppc/spapr_rtas.c -because of missing commit: -9a94ee5bb1 "spapr/rtas: disable the decrementer interrupt when a " - CPU is unplugged" ---- - hw/ppc/spapr.c | 18 +++++++++--------- - hw/ppc/spapr_cpu_core.c | 7 +++++++ - hw/ppc/spapr_rtas.c | 9 --------- - 3 files changed, 16 insertions(+), 18 deletions(-) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 2bb3b61..4f1ab14 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -1442,6 +1442,15 @@ static void ppc_spapr_reset(void) - spapr_setup_hpt_and_vrma(spapr); - } - -+ /* if this reset wasn't generated by CAS, we should reset our -+ * negotiated options and start from scratch */ -+ if (!spapr->cas_reboot) { -+ spapr_ovec_cleanup(spapr->ov5_cas); -+ spapr->ov5_cas = spapr_ovec_new(); -+ -+ ppc_set_compat(first_ppc_cpu, spapr->max_compat_pvr, &error_fatal); -+ } -+ - qemu_devices_reset(); - - /* DRC reset may cause a device to be unplugged. This will cause troubles -@@ -1462,15 +1471,6 @@ static void ppc_spapr_reset(void) - rtas_addr = rtas_limit - RTAS_MAX_SIZE; - fdt_addr = rtas_addr - FDT_MAX_SIZE; - -- /* if this reset wasn't generated by CAS, we should reset our -- * negotiated options and start from scratch */ -- if (!spapr->cas_reboot) { -- spapr_ovec_cleanup(spapr->ov5_cas); -- spapr->ov5_cas = spapr_ovec_new(); -- -- ppc_set_compat(first_ppc_cpu, spapr->max_compat_pvr, &error_fatal); -- } -- - fdt = spapr_build_fdt(spapr, rtas_addr, spapr->rtas_size); - - spapr_load_rtas(spapr, fdt, rtas_addr); -diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c -index 30c15d5..fbabe49 100644 ---- a/hw/ppc/spapr_cpu_core.c -+++ b/hw/ppc/spapr_cpu_core.c -@@ -101,6 +101,13 @@ static void spapr_cpu_reset(void *opaque) - exit(1); - } - } -+ -+ /* Set compatibility mode to match the boot CPU, which was either set -+ * by the machine reset code or by CAS. This should never fail. -+ */ -+ if (cs != first_cpu) { -+ ppc_set_compat(cpu, POWERPC_CPU(first_cpu)->compat_pvr, &error_abort); -+ } - } - - static void spapr_cpu_destroy(PowerPCCPU *cpu) -diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c -index 93f09a0..94a2799 100644 ---- a/hw/ppc/spapr_rtas.c -+++ b/hw/ppc/spapr_rtas.c -@@ -162,7 +162,6 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr, - if (cpu != NULL) { - CPUState *cs = CPU(cpu); - CPUPPCState *env = &cpu->env; -- Error *local_err = NULL; - - if (!cs->halted) { - rtas_st(rets, 0, RTAS_OUT_HW_ERROR); -@@ -174,14 +173,6 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr, - * new cpu enters */ - kvm_cpu_synchronize_state(cs); - -- /* Set compatibility mode to match existing cpus */ -- ppc_set_compat(cpu, POWERPC_CPU(first_cpu)->compat_pvr, &local_err); -- if (local_err) { -- error_report_err(local_err); -- rtas_st(rets, 0, RTAS_OUT_HW_ERROR); -- return; -- } -- - env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME); - env->nip = start; - env->gpr[3] = r3; --- -1.8.3.1 - diff --git a/SOURCES/kvm-spapr-reset-DRCs-after-devices.patch b/SOURCES/kvm-spapr-reset-DRCs-after-devices.patch deleted file mode 100644 index e9aa272..0000000 --- a/SOURCES/kvm-spapr-reset-DRCs-after-devices.patch +++ /dev/null @@ -1,126 +0,0 @@ -From 4dcd885d5308e34fb4550c20fc7ffc050e014c91 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Mon, 27 Nov 2017 09:03:20 +0100 -Subject: [PATCH 6/7] spapr: reset DRCs after devices - -RH-Author: Laurent Vivier -Message-id: <20171127090320.32307-1-lvivier@redhat.com> -Patchwork-id: 77902 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH] spapr: reset DRCs after devices -Bugzilla: 1516145 -RH-Acked-by: Serhii Popovych -RH-Acked-by: David Gibson -RH-Acked-by: Miroslav Rezanina -RH-Acked-by: Thomas Huth - -From: Greg Kurz - -A DRC with a pending unplug request releases its associated device at -machine reset time. - -In the case of LMB, when all DRCs for a DIMM device have been reset, -the DIMM gets unplugged, causing guest memory to disappear. This may -be very confusing for anything still using this memory. - -This is exactly what happens with vhost backends, and QEMU aborts -with: - -qemu-system-ppc64: used ring relocated for ring 2 -qemu-system-ppc64: qemu/hw/virtio/vhost.c:649: vhost_commit: Assertion - `r >= 0' failed. - -The issue is that each DRC registers a QEMU reset handler, and we -don't control the order in which these handlers are called (ie, -a LMB DRC will unplug a DIMM before the virtio device using the -memory on this DIMM could stop its vhost backend). - -To avoid such situations, let's reset DRCs after all devices -have been reset. - -Reported-by: Mallesh N. Koti -Signed-off-by: Greg Kurz -Reviewed-by: Daniel Henrique Barboza -Reviewed-by: Michael Roth -Signed-off-by: David Gibson -(cherry picked from commit 82512483940c756e2db1bd67ea91b02bc29c5e01) -Signed-off-by: Laurent Vivier -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr.c | 21 +++++++++++++++++++++ - hw/ppc/spapr_drc.c | 7 ------- - 2 files changed, 21 insertions(+), 7 deletions(-) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 2065f09..6c64c55 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -1394,6 +1394,19 @@ static void find_unknown_sysbus_device(SysBusDevice *sbdev, void *opaque) - } - } - -+static int spapr_reset_drcs(Object *child, void *opaque) -+{ -+ sPAPRDRConnector *drc = -+ (sPAPRDRConnector *) object_dynamic_cast(child, -+ TYPE_SPAPR_DR_CONNECTOR); -+ -+ if (drc) { -+ spapr_drc_reset(drc); -+ } -+ -+ return 0; -+} -+ - static void ppc_spapr_reset(void) - { - MachineState *machine = MACHINE(qdev_get_machine()); -@@ -1417,6 +1430,14 @@ static void ppc_spapr_reset(void) - } - - qemu_devices_reset(); -+ -+ /* DRC reset may cause a device to be unplugged. This will cause troubles -+ * if this device is used by another device (eg, a running vhost backend -+ * will crash QEMU if the DIMM holding the vring goes away). To avoid such -+ * situations, we reset DRCs after all devices have been reset. -+ */ -+ object_child_foreach_recursive(object_get_root(), spapr_reset_drcs, NULL); -+ - spapr_clear_pending_events(spapr); - - /* -diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c -index 85c999d..7d33e4c 100644 ---- a/hw/ppc/spapr_drc.c -+++ b/hw/ppc/spapr_drc.c -@@ -455,11 +455,6 @@ void spapr_drc_reset(sPAPRDRConnector *drc) - } - } - --static void drc_reset(void *opaque) --{ -- spapr_drc_reset(SPAPR_DR_CONNECTOR(opaque)); --} -- - bool spapr_drc_needed(void *opaque) - { - sPAPRDRConnector *drc = (sPAPRDRConnector *)opaque; -@@ -517,7 +512,6 @@ static void realize(DeviceState *d, Error **errp) - } - vmstate_register(DEVICE(drc), spapr_drc_index(drc), &vmstate_spapr_drc, - drc); -- qemu_register_reset(drc_reset, drc); - trace_spapr_drc_realize_complete(spapr_drc_index(drc)); - } - -@@ -528,7 +522,6 @@ static void unrealize(DeviceState *d, Error **errp) - char name[256]; - - trace_spapr_drc_unrealize(spapr_drc_index(drc)); -- qemu_unregister_reset(drc_reset, drc); - vmstate_unregister(DEVICE(drc), &vmstate_spapr_drc, drc); - root_container = container_get(object_get_root(), DRC_CONTAINER_PATH); - snprintf(name, sizeof(name), "%x", spapr_drc_index(drc)); --- -1.8.3.1 - diff --git a/SOURCES/kvm-spapr-set-vsmt-to-MAX-8-smp_threads.patch b/SOURCES/kvm-spapr-set-vsmt-to-MAX-8-smp_threads.patch deleted file mode 100644 index 5101c2a..0000000 --- a/SOURCES/kvm-spapr-set-vsmt-to-MAX-8-smp_threads.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 779370f8d1cf47e46b39b210a43d24804e551071 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Mon, 12 Feb 2018 12:04:49 +0100 -Subject: [PATCH 04/15] spapr: set vsmt to MAX(8, smp_threads) - -RH-Author: Laurent Vivier -Message-id: <20180212120449.20810-1-lvivier@redhat.com> -Patchwork-id: 78978 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH] spapr: set vsmt to MAX(8, smp_threads) -Bugzilla: 1542421 -RH-Acked-by: David Gibson -RH-Acked-by: Thomas Huth -RH-Acked-by: Serhii Popovych - -We ignore silently the value of smp_threads when we set -the default VSMT value, and if smp_threads is greater than VSMT -kernel is going into trouble later. - -Fixes: 8904e5a750 -("spapr: Adjust default VSMT value for better migration compatibility") - -Signed-off-by: Laurent Vivier -Reviewed-by: Greg Kurz -Signed-off-by: David Gibson -(cherry picked from commit 4ad64cbd0c3f9df15be5f7d1c920285551e802ca) -Signed-off-by: Laurent Vivier -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 6c4c088..2b991d8 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -2261,7 +2261,7 @@ static void spapr_set_vsmt_mode(sPAPRMachineState *spapr, Error **errp) - * the value that we'd get with KVM on POWER8, the - * overwhelmingly common case in production systems. - */ -- spapr->vsmt = 8; -+ spapr->vsmt = MAX(8, smp_threads); - } - - /* KVM: If necessary, set the SMT mode: */ --- -1.8.3.1 - diff --git a/SOURCES/kvm-spapr_pci-Remove-unhelpful-pagesize-warning.patch b/SOURCES/kvm-spapr_pci-Remove-unhelpful-pagesize-warning.patch new file mode 100644 index 0000000..dadcc0f --- /dev/null +++ b/SOURCES/kvm-spapr_pci-Remove-unhelpful-pagesize-warning.patch @@ -0,0 +1,61 @@ +From 95f87089d1bdd881775a5d09c59363f5460f7ce2 Mon Sep 17 00:00:00 2001 +From: David Gibson +Date: Thu, 14 Jun 2018 01:31:36 +0200 +Subject: [PATCH 5/9] spapr_pci: Remove unhelpful pagesize warning + +RH-Author: David Gibson +Message-id: <20180614013136.3504-1-dgibson@redhat.com> +Patchwork-id: 80681 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH] spapr_pci: Remove unhelpful pagesize warning +Bugzilla: 1505664 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Thomas Huth +RH-Acked-by: Serhii Popovych + +From: David Gibson + +By default, the IOMMU model built into the spapr virtual PCI host bridge +supports 4kiB and 64kiB IOMMU page sizes. However this can be overridden +which may be desirable to allow larger IOMMU page sizes when running a +guest with hugepage backing and passthrough devices. For that reason a +warning was printed when the device wasn't configured to allow the pagesize +with which guest RAM is backed. + +Experience has proven, however, that this message is more confusing than +useful. Worse it sometimes makes little sense when the host-available page +sizes don't match those available on the guest, which can happen with +a POWER8 guest running on a POWER9 KVM host. + +Long term we do want better handling to allow large IOMMU page sizes to be +used, but for now this parameter and warning don't really accomplish it. +So, remove the message, pending a better solution. + +Signed-off-by: David Gibson + +Signed-off-by: David Gibson +Signed-off-by: Miroslav Rezanina +--- + hw/ppc/spapr_pci.c | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c +index 39a1498..f936ce6 100644 +--- a/hw/ppc/spapr_pci.c ++++ b/hw/ppc/spapr_pci.c +@@ -1717,13 +1717,6 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) + } + + /* DMA setup */ +- if (((sphb->page_size_mask & qemu_getrampagesize()) == 0) +- && kvm_enabled()) { +- warn_report("System page size 0x%lx is not enabled in page_size_mask " +- "(0x%"PRIx64"). Performance may be slow", +- qemu_getrampagesize(), sphb->page_size_mask); +- } +- + for (i = 0; i < windows_supported; ++i) { + tcet = spapr_tce_new_table(DEVICE(sphb), sphb->dma_liobn[i]); + if (!tcet) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-target-i386-add-support-for-SPEC_CTRL-MSR.patch b/SOURCES/kvm-target-i386-add-support-for-SPEC_CTRL-MSR.patch deleted file mode 100644 index 9b6d63b..0000000 --- a/SOURCES/kvm-target-i386-add-support-for-SPEC_CTRL-MSR.patch +++ /dev/null @@ -1,143 +0,0 @@ -From f0fac2e6c70510f7a5c5c572831b1a851a29fc07 Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Wed, 13 Dec 2017 15:47:36 -0200 -Subject: [PATCH 1/3] target-i386: add support for SPEC_CTRL MSR - -RH-Author: Eduardo Habkost -Message-id: <20171213174738.20852-2-ehabkost@redhat.com> -Patchwork-id: n/a -O-Subject: [CONFIDENTIAL][RHEL-7.5 qemu-kvm-rhev PATCH v2 1/3] target-i386: cpu: -add new CPUID bits for indirect branch predictor restrictions -Bugzilla: CVE-2017-5715 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Miroslav Rezanina - -Signed-off-by: Miroslav Rezanina ---- - target/i386/cpu.h | 3 +++ - target/i386/kvm.c | 14 ++++++++++++++ - target/i386/machine.c | 20 ++++++++++++++++++++ - 3 files changed, 37 insertions(+) - -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index fd73888..4dfb859 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -335,6 +335,7 @@ - #define MSR_IA32_APICBASE_BASE (0xfffffU<<12) - #define MSR_IA32_FEATURE_CONTROL 0x0000003a - #define MSR_TSC_ADJUST 0x0000003b -+#define MSR_IA32_SPEC_CTRL 0x48 - #define MSR_IA32_TSCDEADLINE 0x6e0 - - #define FEATURE_CONTROL_LOCKED (1<<0) -@@ -1082,6 +1083,8 @@ typedef struct CPUX86State { - - uint32_t pkru; - -+ uint64_t spec_ctrl; -+ - /* End of state preserved by INIT (dummy marker). */ - struct {} end_init_save; - -diff --git a/target/i386/kvm.c b/target/i386/kvm.c -index ee4e91f..3f59629 100644 ---- a/target/i386/kvm.c -+++ b/target/i386/kvm.c -@@ -91,6 +91,7 @@ static bool has_msr_hv_synic; - static bool has_msr_hv_stimer; - static bool has_msr_hv_frequencies; - static bool has_msr_xss; -+static bool has_msr_spec_ctrl; - - static bool has_msr_architectural_pmu; - static uint32_t num_architectural_pmu_counters; -@@ -1145,6 +1146,9 @@ static int kvm_get_supported_msrs(KVMState *s) - case HV_X64_MSR_TSC_FREQUENCY: - has_msr_hv_frequencies = true; - break; -+ case MSR_IA32_SPEC_CTRL: -+ has_msr_spec_ctrl = true; -+ break; - } - } - } -@@ -1627,6 +1631,9 @@ static int kvm_put_msrs(X86CPU *cpu, int level) - if (has_msr_xss) { - kvm_msr_entry_add(cpu, MSR_IA32_XSS, env->xss); - } -+ if (has_msr_spec_ctrl) { -+ kvm_msr_entry_add(cpu, MSR_IA32_SPEC_CTRL, env->spec_ctrl); -+ } - #ifdef TARGET_X86_64 - if (lm_capable_kernel) { - kvm_msr_entry_add(cpu, MSR_CSTAR, env->cstar); -@@ -1635,6 +1642,7 @@ static int kvm_put_msrs(X86CPU *cpu, int level) - kvm_msr_entry_add(cpu, MSR_LSTAR, env->lstar); - } - #endif -+ - /* - * The following MSRs have side effects on the guest or are too heavy - * for normal writeback. Limit them to reset or full state updates. -@@ -2000,6 +2008,9 @@ static int kvm_get_msrs(X86CPU *cpu) - if (has_msr_xss) { - kvm_msr_entry_add(cpu, MSR_IA32_XSS, 0); - } -+ if (has_msr_spec_ctrl) { -+ kvm_msr_entry_add(cpu, MSR_IA32_SPEC_CTRL, 0); -+ } - - - if (!env->tsc_valid) { -@@ -2349,6 +2360,9 @@ static int kvm_get_msrs(X86CPU *cpu) - env->mtrr_var[MSR_MTRRphysIndex(index)].base = msrs[i].data; - } - break; -+ case MSR_IA32_SPEC_CTRL: -+ env->spec_ctrl = msrs[i].data; -+ break; - } - } - -diff --git a/target/i386/machine.c b/target/i386/machine.c -index 6156626..0212270 100644 ---- a/target/i386/machine.c -+++ b/target/i386/machine.c -@@ -838,6 +838,25 @@ static const VMStateDescription vmstate_xsave ={ - } - }; - -+static bool spec_ctrl_needed(void *opaque) -+{ -+ X86CPU *cpu = opaque; -+ CPUX86State *env = &cpu->env; -+ -+ return env->spec_ctrl != 0; -+} -+ -+static const VMStateDescription vmstate_spec_ctrl = { -+ .name = "cpu/spec_ctrl", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .needed = spec_ctrl_needed, -+ .fields = (VMStateField[]){ -+ VMSTATE_UINT64(env.spec_ctrl, X86CPU), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ - VMStateDescription vmstate_x86_cpu = { - .name = "cpu", - .version_id = 12, -@@ -956,6 +975,7 @@ VMStateDescription vmstate_x86_cpu = { - #ifdef TARGET_X86_64 - &vmstate_pkru, - #endif -+ &vmstate_spec_ctrl, - &vmstate_mcg_ext_ctl, - &vmstate_xsave, - NULL --- -1.8.3.1 - diff --git a/SOURCES/kvm-target-i386-cpu-Add-new-EPYC-CPU-model.patch b/SOURCES/kvm-target-i386-cpu-Add-new-EPYC-CPU-model.patch deleted file mode 100644 index a2e38df..0000000 --- a/SOURCES/kvm-target-i386-cpu-Add-new-EPYC-CPU-model.patch +++ /dev/null @@ -1,96 +0,0 @@ -From 89afbdab86f84025f4611fc5e26ba7014216689d Mon Sep 17 00:00:00 2001 -From: Eduardo Habkost -Date: Thu, 5 Oct 2017 22:09:12 +0200 -Subject: [PATCH 03/69] target-i386/cpu: Add new EPYC CPU model - -RH-Author: Eduardo Habkost -Message-id: <20171005220912.11421-1-ehabkost@redhat.com> -Patchwork-id: 76830 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH] target-i386/cpu: Add new EPYC CPU model -Bugzilla: 1445834 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Bandan Das -RH-Acked-by: Igor Mammedov - -From: Brijesh Singh - -Add a new base CPU model called 'EPYC' to model processors from AMD EPYC -family (which includes EPYC 76xx,75xx,74xx, 73xx and 72xx). - -The following features bits have been added/removed compare to Opteron_G5 - -Added: monitor, movbe, rdrand, mmxext, ffxsr, rdtscp, cr8legacy, osvw, - fsgsbase, bmi1, avx2, smep, bmi2, rdseed, adx, smap, clfshopt, sha - xsaveopt, xsavec, xgetbv1, arat - -Removed: xop, fma4, tbm - -Signed-off-by: Brijesh Singh -Message-Id: <20170815170051.127257-1-brijesh.singh@amd.com> -Reviewed-by: Eduardo Habkost -Signed-off-by: Eduardo Habkost -(cherry picked from commit 2e2efc7dbe2b0adc1200b5aa286cdbed729f6751) -Signed-off-by: Eduardo Habkost -Signed-off-by: Miroslav Rezanina ---- - target/i386/cpu.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 44 insertions(+) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 670d121..1cae8fe 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -1547,6 +1547,50 @@ static X86CPUDefinition builtin_x86_defs[] = { - .xlevel = 0x8000001A, - .model_id = "AMD Opteron 63xx class CPU", - }, -+ { -+ .name = "EPYC", -+ .level = 0xd, -+ .vendor = CPUID_VENDOR_AMD, -+ .family = 23, -+ .model = 1, -+ .stepping = 2, -+ .features[FEAT_1_EDX] = -+ CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | CPUID_CLFLUSH | -+ CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | CPUID_PGE | -+ CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | CPUID_MCE | -+ CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | CPUID_DE | -+ CPUID_VME | CPUID_FP87, -+ .features[FEAT_1_ECX] = -+ CPUID_EXT_RDRAND | CPUID_EXT_F16C | CPUID_EXT_AVX | -+ CPUID_EXT_XSAVE | CPUID_EXT_AES | CPUID_EXT_POPCNT | -+ CPUID_EXT_MOVBE | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 | -+ CPUID_EXT_CX16 | CPUID_EXT_FMA | CPUID_EXT_SSSE3 | -+ CPUID_EXT_MONITOR | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3, -+ .features[FEAT_8000_0001_EDX] = -+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_PDPE1GB | -+ CPUID_EXT2_FFXSR | CPUID_EXT2_MMXEXT | CPUID_EXT2_NX | -+ CPUID_EXT2_SYSCALL, -+ .features[FEAT_8000_0001_ECX] = -+ CPUID_EXT3_OSVW | CPUID_EXT3_3DNOWPREFETCH | -+ CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | -+ CPUID_EXT3_CR8LEG | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM, -+ .features[FEAT_7_0_EBX] = -+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_AVX2 | -+ CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_RDSEED | -+ CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_CLFLUSHOPT | -+ CPUID_7_0_EBX_SHA_NI, -+ /* Missing: XSAVES (not supported by some Linux versions, -+ * including v4.1 to v4.12). -+ * KVM doesn't yet expose any XSAVES state save component. -+ */ -+ .features[FEAT_XSAVE] = -+ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | -+ CPUID_XSAVE_XGETBV1, -+ .features[FEAT_6_EAX] = -+ CPUID_6_EAX_ARAT, -+ .xlevel = 0x8000000A, -+ .model_id = "AMD EPYC Processor", -+ }, - }; - - typedef struct PropValue { --- -1.8.3.1 - diff --git a/SOURCES/kvm-target-i386-cpu-add-new-CPU-models-for-indirect-bran.patch b/SOURCES/kvm-target-i386-cpu-add-new-CPU-models-for-indirect-bran.patch deleted file mode 100644 index 94e54db..0000000 --- a/SOURCES/kvm-target-i386-cpu-add-new-CPU-models-for-indirect-bran.patch +++ /dev/null @@ -1,932 +0,0 @@ -From 052aaec83e84cc99a03e023eaaf58d289e0d5d05 Mon Sep 17 00:00:00 2001 -From: Eduardo Habkost -Date: Wed, 13 Dec 2017 15:47:38 -0200 -Subject: [PATCH 3/3] target-i386: cpu: add new CPU models for indirect branch - predictor restrictions - -RH-Author: Eduardo Habkost -Message-id: <20171213174738.20852-4-ehabkost@redhat.com> -Patchwork-id: n/a -O-Subject: [CONFIDENTIAL][RHEL-7.5 qemu-kvm-rhev PATCH v2 3/3] target-i386: cpu: add - new CPU models for indirect branch predictor restrictions -Bugzilla: CVE-2017-5715 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Miroslav Rezanina - -To ensure the New CPU models won't introduce any unexpected -changes except for the spec-ctrl feature (even if people are -running older machine-types), copy all compat_props entries for -existing CPU models to their *-IBRS versions. - -The only entries that are not being copied are the ones touching -"(min-)level" and "(min-)xlevel" because it's an expected result -of the CPU model change (otherwise the spec-ctrl feature would -remain unavailable to the guest). - -The entries that had to be copied can be found using: - $ git grep -E 'Nehalem|Westmere|SandyBridge|IvyBridge|Haswell-noTSX|Haswell|Broadwell-noTSX|Broadwell|Skylake-Client|Skylake-Server|EPYC' - -Note that the upstream-only PC_COMPAT_* macros are not being -touched as they are not used by the RHEL machine-types - -Signed-off-by: Miroslav Rezanina . ---- - hw/i386/pc_piix.c | 100 ++++++++++++ - include/hw/i386/pc.h | 75 +++++++++ - target/i386/cpu.c | 425 ++++++++++++++++++++++++++++++++++++++++++++++++++- - target/i386/cpu.h | 3 + - 4 files changed, 602 insertions(+), 1 deletion(-) - -diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c -index c10e462..7a205c4 100644 ---- a/hw/i386/pc_piix.c -+++ b/hw/i386/pc_piix.c -@@ -1444,96 +1444,191 @@ DEFINE_PC_MACHINE(rhel700, "pc-i440fx-rhel7.0.0", pc_init_rhel700, - .property = "x2apic",\ - .value = "on",\ - },\ -+ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ -+ .driver = "Nehalem-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "x2apic",\ -+ .value = "on",\ -+ },\ - {\ - .driver = "Westmere" "-" TYPE_X86_CPU,\ - .property = "x2apic",\ - .value = "on",\ - },\ -+ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ -+ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "x2apic",\ -+ .value = "on",\ -+ },\ - {\ - .driver = "Westmere" "-" TYPE_X86_CPU,\ - .property = "pclmulqdq",\ - .value = "off",\ - },\ -+ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ -+ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "pclmulqdq",\ -+ .value = "off",\ -+ },\ - {\ - .driver = "Westmere" "-" TYPE_X86_CPU,\ - .property = "fxsr",\ - .value = "on",\ - },\ -+ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ -+ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "fxsr",\ -+ .value = "on",\ -+ },\ - {\ - .driver = "Westmere" "-" TYPE_X86_CPU,\ - .property = "mmx",\ - .value = "on",\ - },\ -+ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ -+ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "mmx",\ -+ .value = "on",\ -+ },\ - {\ - .driver = "Westmere" "-" TYPE_X86_CPU,\ - .property = "pat",\ - .value = "on",\ - },\ -+ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ -+ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "pat",\ -+ .value = "on",\ -+ },\ - {\ - .driver = "Westmere" "-" TYPE_X86_CPU,\ - .property = "cmov",\ - .value = "on",\ - },\ -+ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ -+ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "cmov",\ -+ .value = "on",\ -+ },\ - {\ - .driver = "Westmere" "-" TYPE_X86_CPU,\ - .property = "pge",\ - .value = "on",\ - },\ -+ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ -+ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "pge",\ -+ .value = "on",\ -+ },\ - {\ - .driver = "Westmere" "-" TYPE_X86_CPU,\ - .property = "apic",\ - .value = "on",\ - },\ -+ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ -+ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "apic",\ -+ .value = "on",\ -+ },\ - {\ - .driver = "Westmere" "-" TYPE_X86_CPU,\ - .property = "cx8",\ - .value = "on",\ - },\ -+ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ -+ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "cx8",\ -+ .value = "on",\ -+ },\ - {\ - .driver = "Westmere" "-" TYPE_X86_CPU,\ - .property = "mce",\ - .value = "on",\ - },\ -+ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ -+ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "mce",\ -+ .value = "on",\ -+ },\ - {\ - .driver = "Westmere" "-" TYPE_X86_CPU,\ - .property = "pae",\ - .value = "on",\ - },\ -+ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ -+ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "pae",\ -+ .value = "on",\ -+ },\ - {\ - .driver = "Westmere" "-" TYPE_X86_CPU,\ - .property = "msr",\ - .value = "on",\ - },\ -+ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ -+ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "msr",\ -+ .value = "on",\ -+ },\ - {\ - .driver = "Westmere" "-" TYPE_X86_CPU,\ - .property = "tsc",\ - .value = "on",\ - },\ -+ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ -+ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "tsc",\ -+ .value = "on",\ -+ },\ - {\ - .driver = "Westmere" "-" TYPE_X86_CPU,\ - .property = "pse",\ - .value = "on",\ - },\ -+ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ -+ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "pse",\ -+ .value = "on",\ -+ },\ - {\ - .driver = "Westmere" "-" TYPE_X86_CPU,\ - .property = "de",\ - .value = "on",\ - },\ -+ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ -+ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "de",\ -+ .value = "on",\ -+ },\ - {\ - .driver = "Westmere" "-" TYPE_X86_CPU,\ - .property = "fpu",\ - .value = "on",\ - },\ -+ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ -+ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "fpu",\ -+ .value = "on",\ -+ },\ - {\ - .driver = "Broadwell" "-" TYPE_X86_CPU,\ - .property = "rdtscp",\ - .value = "off",\ - },\ -+ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ -+ .driver = "Broadwell-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "rdtscp",\ -+ .value = "off",\ -+ },\ - {\ - .driver = "Broadwell" "-" TYPE_X86_CPU,\ - .property = "smap",\ - .value = "off",\ - },\ -+ { /* PC_RHEL6_6_COMPAT (copied from the entry above) */ \ -+ .driver = "Broadwell-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "smap",\ -+ .value = "off",\ -+ },\ - {\ - .driver = TYPE_X86_CPU,\ - .property = "rdtscp",\ -@@ -1752,6 +1847,11 @@ DEFINE_PC_MACHINE(rhel640, "rhel6.4.0", pc_init_rhel640, - .driver = "SandyBridge" "-" TYPE_X86_CPU,\ - .property = "tsc-deadline",\ - .value = "off",\ -+ },\ -+ { /* PC_RHEL6_3_COMPAT (copied from the entry above) */ \ -+ .driver = "SandyBridge-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "tsc-deadline",\ -+ .value = "off",\ - }, - - static void pc_compat_rhel630(MachineState *machine) -diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h -index f9b7998..d1b1320 100644 ---- a/include/hw/i386/pc.h -+++ b/include/hw/i386/pc.h -@@ -1118,21 +1118,41 @@ extern void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id); - .property = "abm",\ - .value = "off",\ - },\ -+ { /* PC_RHEL7_2_COMPAT (copied from the entry above) */ \ -+ .driver = "Haswell-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "abm",\ -+ .value = "off",\ -+ },\ - { /* PC_RHEL7_2_COMPAT */ \ - .driver = "Haswell-noTSX-" TYPE_X86_CPU,\ - .property = "abm",\ - .value = "off",\ - },\ -+ { /* PC_RHEL7_2_COMPAT (copied from the entry above) */ \ -+ .driver = "Haswell-noTSX-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "abm",\ -+ .value = "off",\ -+ },\ - { /* PC_RHEL7_2_COMPAT */ \ - .driver = "Broadwell-" TYPE_X86_CPU,\ - .property = "abm",\ - .value = "off",\ - },\ -+ { /* PC_RHEL7_2_COMPAT (copied from the entry above) */ \ -+ .driver = "Broadwell-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "abm",\ -+ .value = "off",\ -+ },\ - { /* PC_RHEL7_2_COMPAT */ \ - .driver = "Broadwell-noTSX-" TYPE_X86_CPU,\ - .property = "abm",\ - .value = "off",\ - },\ -+ { /* PC_RHEL7_2_COMPAT (copied from the entry above) */ \ -+ .driver = "Broadwell-noTSX-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "abm",\ -+ .value = "off",\ -+ },\ - { /* PC_RHEL7_2_COMPAT */ \ - .driver = "host" "-" TYPE_X86_CPU,\ - .property = "host-cache-info",\ -@@ -1198,26 +1218,51 @@ extern void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id); - .property = "vme",\ - .value = "off",\ - },\ -+ { /* PC_RHEL7_1_COMPAT (copied from the entry above) */ \ -+ .driver = "Nehalem-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "vme",\ -+ .value = "off",\ -+ },\ - {\ - .driver = "Westmere" "-" TYPE_X86_CPU,\ - .property = "vme",\ - .value = "off",\ - },\ -+ { /* PC_RHEL7_1_COMPAT (copied from the entry above) */ \ -+ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "vme",\ -+ .value = "off",\ -+ },\ - {\ - .driver = "SandyBridge" "-" TYPE_X86_CPU,\ - .property = "vme",\ - .value = "off",\ - },\ -+ { /* PC_RHEL7_1_COMPAT (copied from the entry above) */ \ -+ .driver = "SandyBridge-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "vme",\ -+ .value = "off",\ -+ },\ - {\ - .driver = "Haswell" "-" TYPE_X86_CPU,\ - .property = "vme",\ - .value = "off",\ - },\ -+ { /* PC_RHEL7_1_COMPAT (copied from the entry above) */ \ -+ .driver = "Haswell-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "vme",\ -+ .value = "off",\ -+ },\ - {\ - .driver = "Broadwell" "-" TYPE_X86_CPU,\ - .property = "vme",\ - .value = "off",\ - },\ -+ { /* PC_RHEL7_1_COMPAT (copied from the entry above) */ \ -+ .driver = "Broadwell-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "vme",\ -+ .value = "off",\ -+ },\ - {\ - .driver = "Opteron_G1" "-" TYPE_X86_CPU,\ - .property = "vme",\ -@@ -1248,21 +1293,41 @@ extern void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id); - .property = "f16c",\ - .value = "off",\ - },\ -+ { /* PC_RHEL7_1_COMPAT (copied from the entry above) */ \ -+ .driver = "Haswell-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "f16c",\ -+ .value = "off",\ -+ },\ - {\ - .driver = "Haswell" "-" TYPE_X86_CPU,\ - .property = "rdrand",\ - .value = "off",\ - },\ -+ { /* PC_RHEL7_1_COMPAT (copied from the entry above) */ \ -+ .driver = "Haswell-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "rdrand",\ -+ .value = "off",\ -+ },\ - {\ - .driver = "Broadwell" "-" TYPE_X86_CPU,\ - .property = "f16c",\ - .value = "off",\ - },\ -+ { /* PC_RHEL7_1_COMPAT (copied from the entry above) */ \ -+ .driver = "Broadwell-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "f16c",\ -+ .value = "off",\ -+ },\ - {\ - .driver = "Broadwell" "-" TYPE_X86_CPU,\ - .property = "rdrand",\ - .value = "off",\ - },\ -+ { /* PC_RHEL7_1_COMPAT (copied from the entry above) */ \ -+ .driver = "Broadwell-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "rdrand",\ -+ .value = "off",\ -+ },\ - {\ - .driver = "coreduo" "-" TYPE_X86_CPU,\ - .property = "vmx",\ -@@ -1431,11 +1496,21 @@ extern void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id); - .property = "x2apic",\ - .value = "on",\ - },\ -+ { /* PC_RHEL7_0_COMPAT (copied from the entry above) */ \ -+ .driver = "Nehalem-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "x2apic",\ -+ .value = "on",\ -+ },\ - {\ - .driver = "Westmere" "-" TYPE_X86_CPU,\ - .property = "x2apic",\ - .value = "on",\ - },\ -+ { /* PC_RHEL7_0_COMPAT (copied from the entry above) */ \ -+ .driver = "Westmere-IBRS" "-" TYPE_X86_CPU,\ -+ .property = "x2apic",\ -+ .value = "on",\ -+ },\ - {\ - .driver = "Opteron_G1" "-" TYPE_X86_CPU,\ - .property = "x2apic",\ -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index 364e52e..da5a266 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -1102,6 +1102,31 @@ static X86CPUDefinition builtin_x86_defs[] = { - .model_id = "Intel Core i7 9xx (Nehalem Class Core i7)", - }, - { -+ .name = "Nehalem-IBRS", -+ .level = 11, -+ .vendor = CPUID_VENDOR_INTEL, -+ .family = 6, -+ .model = 26, -+ .stepping = 3, -+ .features[FEAT_1_EDX] = -+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | -+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | -+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | -+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | -+ CPUID_DE | CPUID_FP87, -+ .features[FEAT_1_ECX] = -+ CPUID_EXT_POPCNT | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 | -+ CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_SSE3, -+ .features[FEAT_7_0_EDX] = -+ CPUID_7_0_EDX_SPEC_CTRL, -+ .features[FEAT_8000_0001_EDX] = -+ CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX, -+ .features[FEAT_8000_0001_ECX] = -+ CPUID_EXT3_LAHF_LM, -+ .xlevel = 0x80000008, -+ .model_id = "Intel Core i7 9xx (Nehalem Core i7, IBRS update)", -+ }, -+ { - .name = "Westmere", - .level = 11, - .vendor = CPUID_VENDOR_INTEL, -@@ -1128,6 +1153,34 @@ static X86CPUDefinition builtin_x86_defs[] = { - .model_id = "Westmere E56xx/L56xx/X56xx (Nehalem-C)", - }, - { -+ .name = "Westmere-IBRS", -+ .level = 11, -+ .vendor = CPUID_VENDOR_INTEL, -+ .family = 6, -+ .model = 44, -+ .stepping = 1, -+ .features[FEAT_1_EDX] = -+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | -+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | -+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | -+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | -+ CPUID_DE | CPUID_FP87, -+ .features[FEAT_1_ECX] = -+ CPUID_EXT_AES | CPUID_EXT_POPCNT | CPUID_EXT_SSE42 | -+ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | -+ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3, -+ .features[FEAT_8000_0001_EDX] = -+ CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX, -+ .features[FEAT_8000_0001_ECX] = -+ CPUID_EXT3_LAHF_LM, -+ .features[FEAT_7_0_EDX] = -+ CPUID_7_0_EDX_SPEC_CTRL, -+ .features[FEAT_6_EAX] = -+ CPUID_6_EAX_ARAT, -+ .xlevel = 0x80000008, -+ .model_id = "Westmere E56xx/L56xx/X56xx (IBRS update)", -+ }, -+ { - .name = "SandyBridge", - .level = 0xd, - .vendor = CPUID_VENDOR_INTEL, -@@ -1159,6 +1212,39 @@ static X86CPUDefinition builtin_x86_defs[] = { - .model_id = "Intel Xeon E312xx (Sandy Bridge)", - }, - { -+ .name = "SandyBridge-IBRS", -+ .level = 0xd, -+ .vendor = CPUID_VENDOR_INTEL, -+ .family = 6, -+ .model = 42, -+ .stepping = 1, -+ .features[FEAT_1_EDX] = -+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | -+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | -+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | -+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | -+ CPUID_DE | CPUID_FP87, -+ .features[FEAT_1_ECX] = -+ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES | -+ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_POPCNT | -+ CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 | -+ CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_PCLMULQDQ | -+ CPUID_EXT_SSE3, -+ .features[FEAT_8000_0001_EDX] = -+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX | -+ CPUID_EXT2_SYSCALL, -+ .features[FEAT_8000_0001_ECX] = -+ CPUID_EXT3_LAHF_LM, -+ .features[FEAT_7_0_EDX] = -+ CPUID_7_0_EDX_SPEC_CTRL, -+ .features[FEAT_XSAVE] = -+ CPUID_XSAVE_XSAVEOPT, -+ .features[FEAT_6_EAX] = -+ CPUID_6_EAX_ARAT, -+ .xlevel = 0x80000008, -+ .model_id = "Intel Xeon E312xx (Sandy Bridge, IBRS update)", -+ }, -+ { - .name = "IvyBridge", - .level = 0xd, - .vendor = CPUID_VENDOR_INTEL, -@@ -1193,6 +1279,42 @@ static X86CPUDefinition builtin_x86_defs[] = { - .model_id = "Intel Xeon E3-12xx v2 (Ivy Bridge)", - }, - { -+ .name = "IvyBridge-IBRS", -+ .level = 0xd, -+ .vendor = CPUID_VENDOR_INTEL, -+ .family = 6, -+ .model = 58, -+ .stepping = 9, -+ .features[FEAT_1_EDX] = -+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | -+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | -+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | -+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | -+ CPUID_DE | CPUID_FP87, -+ .features[FEAT_1_ECX] = -+ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES | -+ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_POPCNT | -+ CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 | -+ CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_PCLMULQDQ | -+ CPUID_EXT_SSE3 | CPUID_EXT_F16C | CPUID_EXT_RDRAND, -+ .features[FEAT_7_0_EBX] = -+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_SMEP | -+ CPUID_7_0_EBX_ERMS, -+ .features[FEAT_8000_0001_EDX] = -+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX | -+ CPUID_EXT2_SYSCALL, -+ .features[FEAT_8000_0001_ECX] = -+ CPUID_EXT3_LAHF_LM, -+ .features[FEAT_7_0_EDX] = -+ CPUID_7_0_EDX_SPEC_CTRL, -+ .features[FEAT_XSAVE] = -+ CPUID_XSAVE_XSAVEOPT, -+ .features[FEAT_6_EAX] = -+ CPUID_6_EAX_ARAT, -+ .xlevel = 0x80000008, -+ .model_id = "Intel Xeon E3-12xx v2 (Ivy Bridge, IBRS)", -+ }, -+ { - .name = "Haswell-noTSX", - .level = 0xd, - .vendor = CPUID_VENDOR_INTEL, -@@ -1227,7 +1349,46 @@ static X86CPUDefinition builtin_x86_defs[] = { - CPUID_6_EAX_ARAT, - .xlevel = 0x80000008, - .model_id = "Intel Core Processor (Haswell, no TSX)", -- }, { -+ }, -+ { -+ .name = "Haswell-noTSX-IBRS", -+ .level = 0xd, -+ .vendor = CPUID_VENDOR_INTEL, -+ .family = 6, -+ .model = 60, -+ .stepping = 1, -+ .features[FEAT_1_EDX] = -+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | -+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | -+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | -+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | -+ CPUID_DE | CPUID_FP87, -+ .features[FEAT_1_ECX] = -+ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES | -+ CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | -+ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | -+ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 | -+ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE | -+ CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND, -+ .features[FEAT_8000_0001_EDX] = -+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX | -+ CPUID_EXT2_SYSCALL, -+ .features[FEAT_8000_0001_ECX] = -+ CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM, -+ .features[FEAT_7_0_EDX] = -+ CPUID_7_0_EDX_SPEC_CTRL, -+ .features[FEAT_7_0_EBX] = -+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | -+ CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | -+ CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID, -+ .features[FEAT_XSAVE] = -+ CPUID_XSAVE_XSAVEOPT, -+ .features[FEAT_6_EAX] = -+ CPUID_6_EAX_ARAT, -+ .xlevel = 0x80000008, -+ .model_id = "Intel Core Processor (Haswell, no TSX, IBRS)", -+ }, -+ { - .name = "Haswell", - .level = 0xd, - .vendor = CPUID_VENDOR_INTEL, -@@ -1265,6 +1426,45 @@ static X86CPUDefinition builtin_x86_defs[] = { - .model_id = "Intel Core Processor (Haswell)", - }, - { -+ .name = "Haswell-IBRS", -+ .level = 0xd, -+ .vendor = CPUID_VENDOR_INTEL, -+ .family = 6, -+ .model = 60, -+ .stepping = 4, -+ .features[FEAT_1_EDX] = -+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | -+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | -+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | -+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | -+ CPUID_DE | CPUID_FP87, -+ .features[FEAT_1_ECX] = -+ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES | -+ CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | -+ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | -+ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 | -+ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE | -+ CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND, -+ .features[FEAT_8000_0001_EDX] = -+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX | -+ CPUID_EXT2_SYSCALL, -+ .features[FEAT_8000_0001_ECX] = -+ CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM, -+ .features[FEAT_7_0_EDX] = -+ CPUID_7_0_EDX_SPEC_CTRL, -+ .features[FEAT_7_0_EBX] = -+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | -+ CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | -+ CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | -+ CPUID_7_0_EBX_RTM, -+ .features[FEAT_XSAVE] = -+ CPUID_XSAVE_XSAVEOPT, -+ .features[FEAT_6_EAX] = -+ CPUID_6_EAX_ARAT, -+ .xlevel = 0x80000008, -+ .model_id = "Intel Core Processor (Haswell, IBRS)", -+ }, -+ { - .name = "Broadwell-noTSX", - .level = 0xd, - .vendor = CPUID_VENDOR_INTEL, -@@ -1303,6 +1503,46 @@ static X86CPUDefinition builtin_x86_defs[] = { - .model_id = "Intel Core Processor (Broadwell, no TSX)", - }, - { -+ .name = "Broadwell-noTSX-IBRS", -+ .level = 0xd, -+ .vendor = CPUID_VENDOR_INTEL, -+ .family = 6, -+ .model = 61, -+ .stepping = 2, -+ .features[FEAT_1_EDX] = -+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | -+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | -+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | -+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | -+ CPUID_DE | CPUID_FP87, -+ .features[FEAT_1_ECX] = -+ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES | -+ CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | -+ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | -+ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 | -+ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE | -+ CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND, -+ .features[FEAT_8000_0001_EDX] = -+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX | -+ CPUID_EXT2_SYSCALL, -+ .features[FEAT_8000_0001_ECX] = -+ CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH, -+ .features[FEAT_7_0_EDX] = -+ CPUID_7_0_EDX_SPEC_CTRL, -+ .features[FEAT_7_0_EBX] = -+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | -+ CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | -+ CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | -+ CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | -+ CPUID_7_0_EBX_SMAP, -+ .features[FEAT_XSAVE] = -+ CPUID_XSAVE_XSAVEOPT, -+ .features[FEAT_6_EAX] = -+ CPUID_6_EAX_ARAT, -+ .xlevel = 0x80000008, -+ .model_id = "Intel Core Processor (Broadwell, no TSX, IBRS)", -+ }, -+ { - .name = "Broadwell", - .level = 0xd, - .vendor = CPUID_VENDOR_INTEL, -@@ -1341,6 +1581,46 @@ static X86CPUDefinition builtin_x86_defs[] = { - .model_id = "Intel Core Processor (Broadwell)", - }, - { -+ .name = "Broadwell-IBRS", -+ .level = 0xd, -+ .vendor = CPUID_VENDOR_INTEL, -+ .family = 6, -+ .model = 61, -+ .stepping = 2, -+ .features[FEAT_1_EDX] = -+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | -+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | -+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | -+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | -+ CPUID_DE | CPUID_FP87, -+ .features[FEAT_1_ECX] = -+ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES | -+ CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | -+ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | -+ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 | -+ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE | -+ CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND, -+ .features[FEAT_8000_0001_EDX] = -+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX | -+ CPUID_EXT2_SYSCALL, -+ .features[FEAT_8000_0001_ECX] = -+ CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH, -+ .features[FEAT_7_0_EDX] = -+ CPUID_7_0_EDX_SPEC_CTRL, -+ .features[FEAT_7_0_EBX] = -+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | -+ CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | -+ CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | -+ CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | -+ CPUID_7_0_EBX_SMAP, -+ .features[FEAT_XSAVE] = -+ CPUID_XSAVE_XSAVEOPT, -+ .features[FEAT_6_EAX] = -+ CPUID_6_EAX_ARAT, -+ .xlevel = 0x80000008, -+ .model_id = "Intel Core Processor (Broadwell, IBRS)", -+ }, -+ { - .name = "Skylake-Client", - .level = 0xd, - .vendor = CPUID_VENDOR_INTEL, -@@ -1386,6 +1666,53 @@ static X86CPUDefinition builtin_x86_defs[] = { - .model_id = "Intel Core Processor (Skylake)", - }, - { -+ .name = "Skylake-Client-IBRS", -+ .level = 0xd, -+ .vendor = CPUID_VENDOR_INTEL, -+ .family = 6, -+ .model = 94, -+ .stepping = 3, -+ .features[FEAT_1_EDX] = -+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | -+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | -+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | -+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | -+ CPUID_DE | CPUID_FP87, -+ .features[FEAT_1_ECX] = -+ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES | -+ CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | -+ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | -+ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 | -+ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE | -+ CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND, -+ .features[FEAT_8000_0001_EDX] = -+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX | -+ CPUID_EXT2_SYSCALL, -+ .features[FEAT_8000_0001_ECX] = -+ CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH, -+ .features[FEAT_7_0_EDX] = -+ CPUID_7_0_EDX_SPEC_CTRL, -+ .features[FEAT_7_0_EBX] = -+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | -+ CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | -+ CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | -+ CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | -+ CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_MPX, -+ /* Missing: XSAVES (not supported by some Linux versions, -+ * including v4.1 to v4.12). -+ * KVM doesn't yet expose any XSAVES state save component, -+ * and the only one defined in Skylake (processor tracing) -+ * probably will block migration anyway. -+ */ -+ .features[FEAT_XSAVE] = -+ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | -+ CPUID_XSAVE_XGETBV1, -+ .features[FEAT_6_EAX] = -+ CPUID_6_EAX_ARAT, -+ .xlevel = 0x80000008, -+ .model_id = "Intel Core Processor (Skylake, IBRS)", -+ }, -+ { - .name = "Skylake-Server", - .level = 0xd, - .vendor = CPUID_VENDOR_INTEL, -@@ -1434,6 +1761,56 @@ static X86CPUDefinition builtin_x86_defs[] = { - .model_id = "Intel Xeon Processor (Skylake)", - }, - { -+ .name = "Skylake-Server-IBRS", -+ .level = 0xd, -+ .vendor = CPUID_VENDOR_INTEL, -+ .family = 6, -+ .model = 85, -+ .stepping = 4, -+ .features[FEAT_1_EDX] = -+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | -+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | -+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | -+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | -+ CPUID_DE | CPUID_FP87, -+ .features[FEAT_1_ECX] = -+ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES | -+ CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | -+ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | -+ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 | -+ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE | -+ CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND, -+ .features[FEAT_8000_0001_EDX] = -+ CPUID_EXT2_LM | CPUID_EXT2_PDPE1GB | CPUID_EXT2_RDTSCP | -+ CPUID_EXT2_NX | CPUID_EXT2_SYSCALL, -+ .features[FEAT_8000_0001_ECX] = -+ CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH, -+ .features[FEAT_7_0_EDX] = -+ CPUID_7_0_EDX_SPEC_CTRL, -+ .features[FEAT_7_0_EBX] = -+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | -+ CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | -+ CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | -+ CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | -+ CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_MPX | CPUID_7_0_EBX_CLWB | -+ CPUID_7_0_EBX_AVX512F | CPUID_7_0_EBX_AVX512DQ | -+ CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512CD | -+ CPUID_7_0_EBX_AVX512VL, -+ /* Missing: XSAVES (not supported by some Linux versions, -+ * including v4.1 to v4.12). -+ * KVM doesn't yet expose any XSAVES state save component, -+ * and the only one defined in Skylake (processor tracing) -+ * probably will block migration anyway. -+ */ -+ .features[FEAT_XSAVE] = -+ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | -+ CPUID_XSAVE_XGETBV1, -+ .features[FEAT_6_EAX] = -+ CPUID_6_EAX_ARAT, -+ .xlevel = 0x80000008, -+ .model_id = "Intel Xeon Processor (Skylake, IBRS)", -+ }, -+ { - .name = "Opteron_G1", - .level = 5, - .vendor = CPUID_VENDOR_AMD, -@@ -1607,6 +1984,52 @@ static X86CPUDefinition builtin_x86_defs[] = { - .xlevel = 0x8000000A, - .model_id = "AMD EPYC Processor", - }, -+ { -+ .name = "EPYC-IBPB", -+ .level = 0xd, -+ .vendor = CPUID_VENDOR_AMD, -+ .family = 23, -+ .model = 1, -+ .stepping = 2, -+ .features[FEAT_1_EDX] = -+ CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | CPUID_CLFLUSH | -+ CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | CPUID_PGE | -+ CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | CPUID_MCE | -+ CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | CPUID_DE | -+ CPUID_VME | CPUID_FP87, -+ .features[FEAT_1_ECX] = -+ CPUID_EXT_RDRAND | CPUID_EXT_F16C | CPUID_EXT_AVX | -+ CPUID_EXT_XSAVE | CPUID_EXT_AES | CPUID_EXT_POPCNT | -+ CPUID_EXT_MOVBE | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 | -+ CPUID_EXT_CX16 | CPUID_EXT_FMA | CPUID_EXT_SSSE3 | -+ CPUID_EXT_MONITOR | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3, -+ .features[FEAT_8000_0001_EDX] = -+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_PDPE1GB | -+ CPUID_EXT2_FFXSR | CPUID_EXT2_MMXEXT | CPUID_EXT2_NX | -+ CPUID_EXT2_SYSCALL, -+ .features[FEAT_8000_0001_ECX] = -+ CPUID_EXT3_OSVW | CPUID_EXT3_3DNOWPREFETCH | -+ CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | -+ CPUID_EXT3_CR8LEG | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM, -+ .features[FEAT_8000_0008_EBX] = -+ CPUID_8000_0008_EBX_IBPB, -+ .features[FEAT_7_0_EBX] = -+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_AVX2 | -+ CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_RDSEED | -+ CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_CLFLUSHOPT | -+ CPUID_7_0_EBX_SHA_NI, -+ /* Missing: XSAVES (not supported by some Linux versions, -+ * including v4.1 to v4.12). -+ * KVM doesn't yet expose any XSAVES state save component. -+ */ -+ .features[FEAT_XSAVE] = -+ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | -+ CPUID_XSAVE_XGETBV1, -+ .features[FEAT_6_EAX] = -+ CPUID_6_EAX_ARAT, -+ .xlevel = 0x8000000A, -+ .model_id = "AMD EPYC Processor (with IBPB)", -+ }, - }; - - typedef struct PropValue { -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index f2686d5..eb77e85 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -643,6 +643,9 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; - - #define CPUID_7_0_EDX_AVX512_4VNNIW (1U << 2) /* AVX512 Neural Network Instructions */ - #define CPUID_7_0_EDX_AVX512_4FMAPS (1U << 3) /* AVX512 Multiply Accumulation Single Precision */ -+#define CPUID_7_0_EDX_SPEC_CTRL (1U << 26) /* Indirect Branch - Restrict Speculation */ -+ -+#define CPUID_8000_0008_EBX_IBPB (1U << 12) /* Indirect Branch Prediction Barrier */ - - #define CPUID_XSAVE_XSAVEOPT (1U << 0) - #define CPUID_XSAVE_XSAVEC (1U << 1) --- -1.8.3.1 - diff --git a/SOURCES/kvm-target-i386-cpu-add-new-CPUID-bits-for-indirect-bran.patch b/SOURCES/kvm-target-i386-cpu-add-new-CPUID-bits-for-indirect-bran.patch deleted file mode 100644 index ad28567..0000000 --- a/SOURCES/kvm-target-i386-cpu-add-new-CPUID-bits-for-indirect-bran.patch +++ /dev/null @@ -1,91 +0,0 @@ -From bc88b0d69c0e81626e5c246cae83e499bfa3dccb Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Wed, 13 Dec 2017 15:47:37 -0200 -Subject: [PATCH 2/3] target-i386: cpu: add new CPUID bits for indirect branch - predictor restrictions - -RH-Author: Eduardo Habkost -Message-id: <20171213174738.20852-3-ehabkost@redhat.com> -Patchwork-id: n/a -O-Subject: [CONFIDENTIAL][RHEL-7.5 qemu-kvm-rhev PATCH v2 2/3] target-i386: add - support for SPEC_CTRL MSR -Bugzilla: CVE-2017-5715 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Miroslav Rezanina - -Signed-off-by: Miroslav Rezanina ---- - target/i386/cpu.c | 23 ++++++++++++++++++++--- - target/i386/cpu.h | 1 + - 2 files changed, 21 insertions(+), 3 deletions(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index c2dee60..364e52e 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -456,8 +456,8 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, -- NULL, NULL, NULL, NULL, -- NULL, NULL, NULL, NULL, -+ NULL, NULL, "spec-ctrl", "stibp", -+ NULL, "arch-facilities", NULL, NULL, - }, - .cpuid_eax = 7, - .cpuid_needs_ecx = true, .cpuid_ecx = 0, -@@ -480,6 +480,22 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - .tcg_features = TCG_APM_FEATURES, - .unmigratable_flags = CPUID_APM_INVTSC, - }, -+ [FEAT_8000_0008_EBX] = { -+ .feat_names = { -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ "ibpb", NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ NULL, NULL, NULL, NULL, -+ }, -+ .cpuid_eax = 0x80000008, -+ .cpuid_reg = R_EBX, -+ .tcg_features = 0, -+ .unmigratable_flags = 0, -+ }, - [FEAT_XSAVE] = { - .feat_names = { - "xsaveopt", "xsavec", "xgetbv1", "xsaves", -@@ -3122,7 +3138,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, - } else { - *eax = cpu->phys_bits; - } -- *ebx = 0; -+ *ebx = env->features[FEAT_8000_0008_EBX]; - *ecx = 0; - *edx = 0; - if (cs->nr_cores * cs->nr_threads > 1) { -@@ -3578,6 +3594,7 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp) - x86_cpu_adjust_feat_level(cpu, FEAT_8000_0001_EDX); - x86_cpu_adjust_feat_level(cpu, FEAT_8000_0001_ECX); - x86_cpu_adjust_feat_level(cpu, FEAT_8000_0007_EDX); -+ x86_cpu_adjust_feat_level(cpu, FEAT_8000_0008_EBX); - x86_cpu_adjust_feat_level(cpu, FEAT_C000_0001_EDX); - x86_cpu_adjust_feat_level(cpu, FEAT_SVM); - x86_cpu_adjust_feat_level(cpu, FEAT_XSAVE); -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index 4dfb859..f2686d5 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -454,6 +454,7 @@ typedef enum FeatureWord { - FEAT_8000_0001_EDX, /* CPUID[8000_0001].EDX */ - FEAT_8000_0001_ECX, /* CPUID[8000_0001].ECX */ - FEAT_8000_0007_EDX, /* CPUID[8000_0007].EDX */ -+ FEAT_8000_0008_EBX, /* CPUID[8000_0008].EBX */ - FEAT_C000_0001_EDX, /* CPUID[C000_0001].EDX */ - FEAT_KVM, /* CPUID[4000_0001].EAX (KVM_CPUID_FEATURES) */ - FEAT_HYPERV_EAX, /* CPUID[4000_0003].EAX */ --- -1.8.3.1 - diff --git a/SOURCES/kvm-target-i386-sanitize-x86-MSR_PAT-loaded-from-another.patch b/SOURCES/kvm-target-i386-sanitize-x86-MSR_PAT-loaded-from-another.patch deleted file mode 100644 index 32fa560..0000000 --- a/SOURCES/kvm-target-i386-sanitize-x86-MSR_PAT-loaded-from-another.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 7705b73dcfd0a9391bb93b9e26695ecb6dc51139 Mon Sep 17 00:00:00 2001 -From: Wei Huang -Date: Wed, 17 Jan 2018 22:13:23 +0100 -Subject: [PATCH 05/21] target-i386: sanitize x86 MSR_PAT loaded from another - source - -RH-Author: Wei Huang -Message-id: <20180117221323.1008-1-wei@redhat.com> -Patchwork-id: 78659 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 1/1] target-i386: sanitize x86 MSR_PAT loaded from another source -Bugzilla: 1529461 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Miroslav Rezanina - -The RHEL 7 downstream commit a94f33258 honors guest VM's writes of MSR_PAT -for SVM machines. But this cause a problem when an x86 VM is migrated from -an old host, such as RHEL 6.9. This is because older system doesn't save -the guest's PAT field during migration; Instead 0x0 is saved and migrated. -At the destination, it will use 0x0 as guest PAT because of a94f33258. -This causes the guest VM's performance to drop significatly. - -This patch solves the problem by sanitizing the PAT field. If it is zero, -we use the default MSR_PAT value (0x0007040600070406ULL) to prevent -performance drop. This solution should work with different types of -(old or new) VM sources. - -Signed-off-by: Wei Huang -Signed-off-by: Miroslav Rezanina ---- - target/i386/cpu.c | 2 +- - target/i386/cpu.h | 1 + - target/i386/machine.c | 3 +++ - 3 files changed, 5 insertions(+), 1 deletion(-) - -diff --git a/target/i386/cpu.c b/target/i386/cpu.c -index da5a266..81d0b75 100644 ---- a/target/i386/cpu.c -+++ b/target/i386/cpu.c -@@ -3678,7 +3678,7 @@ static void x86_cpu_reset(CPUState *s) - /* All units are in INIT state. */ - env->xstate_bv = 0; - -- env->pat = 0x0007040600070406ULL; -+ env->pat = MSR_PAT_DEFAULT; - env->msr_ia32_misc_enable = MSR_IA32_MISC_ENABLE_DEFAULT; - - memset(env->dr, 0, sizeof(env->dr)); -diff --git a/target/i386/cpu.h b/target/i386/cpu.h -index eb77e85..e04579d 100644 ---- a/target/i386/cpu.h -+++ b/target/i386/cpu.h -@@ -385,6 +385,7 @@ - #define MSR_MTRRfix4K_F8000 0x26f - - #define MSR_PAT 0x277 -+#define MSR_PAT_DEFAULT 0x0007040600070406ULL - - #define MSR_MTRRdefType 0x2ff - -diff --git a/target/i386/machine.c b/target/i386/machine.c -index 0212270..9f6ba9a 100644 ---- a/target/i386/machine.c -+++ b/target/i386/machine.c -@@ -274,6 +274,9 @@ static int cpu_post_load(void *opaque, int version_id) - env->hflags &= ~HF_CPL_MASK; - env->hflags |= (env->segs[R_SS].flags >> DESC_DPL_SHIFT) & HF_CPL_MASK; - -+ if (!(env->pat)) -+ env->pat = MSR_PAT_DEFAULT; -+ - env->fpstt = (env->fpus_vmstate >> 11) & 7; - env->fpus = env->fpus_vmstate & ~0x3800; - env->fptag_vmstate ^= 0xff; --- -1.8.3.1 - diff --git a/SOURCES/kvm-target-i386-sev-fix-memory-leaks.patch b/SOURCES/kvm-target-i386-sev-fix-memory-leaks.patch new file mode 100644 index 0000000..57374d9 --- /dev/null +++ b/SOURCES/kvm-target-i386-sev-fix-memory-leaks.patch @@ -0,0 +1,148 @@ +From db0396e4d2663f41aaea944eaaf29141b20f5e1f Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 31 Aug 2018 14:24:58 +0200 +Subject: [PATCH 07/29] target/i386: sev: fix memory leaks + +RH-Author: Markus Armbruster +Message-id: <20180831142459.18567-2-armbru@redhat.com> +Patchwork-id: 81984 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/2] target/i386: sev: fix memory leaks +Bugzilla: 1624390 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: Auger Eric + +From: Paolo Bonzini + +Reported by Coverity. + +Signed-off-by: Paolo Bonzini +(cherry picked from commit bf3175b49952628f96d72d1247d8bb3aa5c2466c) +Signed-off-by: Miroslav Rezanina +--- + target/i386/sev.c | 32 +++++++++++++++++--------------- + 1 file changed, 17 insertions(+), 15 deletions(-) + +diff --git a/target/i386/sev.c b/target/i386/sev.c +index c011671..2395171 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -430,7 +430,8 @@ static int + sev_get_pdh_info(int fd, guchar **pdh, size_t *pdh_len, guchar **cert_chain, + size_t *cert_chain_len) + { +- guchar *pdh_data, *cert_chain_data; ++ guchar *pdh_data = NULL; ++ guchar *cert_chain_data = NULL; + struct sev_user_data_pdh_cert_export export = {}; + int err, r; + +@@ -471,8 +472,9 @@ e_free: + SevCapability * + sev_get_capabilities(void) + { +- SevCapability *cap; +- guchar *pdh_data, *cert_chain_data; ++ SevCapability *cap = NULL; ++ guchar *pdh_data = NULL; ++ guchar *cert_chain_data = NULL; + size_t pdh_len = 0, cert_chain_len = 0; + uint32_t ebx; + int fd; +@@ -486,7 +488,7 @@ sev_get_capabilities(void) + + if (sev_get_pdh_info(fd, &pdh_data, &pdh_len, + &cert_chain_data, &cert_chain_len)) { +- return NULL; ++ goto out; + } + + cap = g_new0(SevCapability, 1); +@@ -502,9 +504,9 @@ sev_get_capabilities(void) + */ + cap->reduced_phys_bits = 1; + ++out: + g_free(pdh_data); + g_free(cert_chain_data); +- + close(fd); + return cap; + } +@@ -530,7 +532,7 @@ sev_launch_start(SEVState *s) + { + gsize sz; + int ret = 1; +- int fw_error; ++ int fw_error, rc; + QSevGuestInfo *sev = s->sev_info; + struct kvm_sev_launch_start *start; + guchar *session = NULL, *dh_cert = NULL; +@@ -543,7 +545,7 @@ sev_launch_start(SEVState *s) + &error_abort); + if (sev->session_file) { + if (sev_read_file_base64(sev->session_file, &session, &sz) < 0) { +- return 1; ++ goto out; + } + start->session_uaddr = (unsigned long)session; + start->session_len = sz; +@@ -551,18 +553,18 @@ sev_launch_start(SEVState *s) + + if (sev->dh_cert_file) { + if (sev_read_file_base64(sev->dh_cert_file, &dh_cert, &sz) < 0) { +- return 1; ++ goto out; + } + start->dh_uaddr = (unsigned long)dh_cert; + start->dh_len = sz; + } + + trace_kvm_sev_launch_start(start->policy, session, dh_cert); +- ret = sev_ioctl(s->sev_fd, KVM_SEV_LAUNCH_START, start, &fw_error); +- if (ret < 0) { ++ rc = sev_ioctl(s->sev_fd, KVM_SEV_LAUNCH_START, start, &fw_error); ++ if (rc < 0) { + error_report("%s: LAUNCH_START ret=%d fw_error=%d '%s'", + __func__, ret, fw_error, fw_error_to_str(fw_error)); +- return 1; ++ goto out; + } + + object_property_set_int(OBJECT(sev), start->handle, "handle", +@@ -570,12 +572,13 @@ sev_launch_start(SEVState *s) + sev_set_guest_state(SEV_STATE_LAUNCH_UPDATE); + s->handle = start->handle; + s->policy = start->policy; ++ ret = 0; + ++out: + g_free(start); + g_free(session); + g_free(dh_cert); +- +- return 0; ++ return ret; + } + + static int +@@ -712,7 +715,7 @@ sev_guest_init(const char *id) + uint32_t host_cbitpos; + struct sev_user_data_status status = {}; + +- s = g_new0(SEVState, 1); ++ sev_state = s = g_new0(SEVState, 1); + s->sev_info = lookup_sev_guest_info(id); + if (!s->sev_info) { + error_report("%s: '%s' is not a valid '%s' object", +@@ -720,7 +723,6 @@ sev_guest_init(const char *id) + goto err; + } + +- sev_state = s; + s->state = SEV_STATE_UNINIT; + + host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-target-ppc-Add-POWER9-DD2.0-model-information.patch b/SOURCES/kvm-target-ppc-Add-POWER9-DD2.0-model-information.patch deleted file mode 100644 index 9ff88d0..0000000 --- a/SOURCES/kvm-target-ppc-Add-POWER9-DD2.0-model-information.patch +++ /dev/null @@ -1,117 +0,0 @@ -From f862178a20240a06504e35d11953982fcf769789 Mon Sep 17 00:00:00 2001 -From: Laurent Vivier -Date: Fri, 8 Dec 2017 14:48:39 +0100 -Subject: [PATCH 1/6] target/ppc: Add POWER9 DD2.0 model information - -RH-Author: Laurent Vivier -Message-id: <20171208144839.6655-1-lvivier@redhat.com> -Patchwork-id: 78276 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH] target/ppc: Add POWER9 DD2.0 model information -Bugzilla: 1523235 -RH-Acked-by: David Gibson -RH-Acked-by: Thomas Huth -RH-Acked-by: Miroslav Rezanina - -From: David Gibson - -Tested: /usr/libexec/qemu-kvm -device help 2>&1|grep -i "power9" - name "POWER9_v1.0-spapr-cpu-core" - name "POWER9_v2.0-spapr-cpu-core" - /usr/libexec/qemu-kvm -cpu help 2>&1|grep -i "power9" - PowerPC POWER9_v1.0 PVR 004e0100 - PowerPC POWER9_v2.0 PVR 004e1200 - PowerPC POWER9 (alias for preferred POWER9 CPU) - -At the moment the only POWER9 model which is listed in qemu is v1.0 (aka -"DD1"). This is a very early (read, buggy) version which will never be -released to the public - it was included in qemu only for the convenience -of those doing bringup on the early silicon. For bonus points, we actually -had its PVR incorrect in the table (0x004e0000 instead of 0x004e0100). We -also never actually implemented the differences in behaviour (read, bugs) -that marked DD1 in qemu. - -Now that we know the PVR for the substantially better v2.0 (DD2) chip, -include it and make it the default POWER9 in qemu. For the time being we -leave the DD1 definition in place for the poor souls (read, me) who still -need to work with DD1 hardware. - -Signed-off-by: David Gibson -(cherry picked from commit 1ed9c8af501f8d1bdf5a8725a038527be059f54d) -Signed-off-by: Laurent Vivier -Signed-off-by: Miroslav Rezanina - -Conflicts: - hw/ppc/spapr_cpu_core.c - target/ppc/cpu-models.c - -with downstream only commit: - - 0e72e616b2 Enable/disable devices for RHEL 7 - -introducing "#if .. #endif" in the CPU list - -And missing upstream commit: - - c5354f5 ppc: make cpu_model translation to type consistent - -changing all the CPU names to lower-case and then doing -case-insensitive matching. I've chosen to not backport this one -because it changes the behaviour of the interface (vs upstream 2.10). ---- - hw/ppc/spapr_cpu_core.c | 1 + - target/ppc/cpu-models.c | 6 ++++-- - target/ppc/cpu-models.h | 1 + - 3 files changed, 6 insertions(+), 2 deletions(-) - -diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c -index 400ab56..30c15d5 100644 ---- a/hw/ppc/spapr_cpu_core.c -+++ b/hw/ppc/spapr_cpu_core.c -@@ -308,6 +308,7 @@ static const char *spapr_core_models[] = { - "POWER8NVL_v1.0", - /* POWER9 */ - "POWER9_v1.0", -+ "POWER9_v2.0", - }; - - static Property spapr_cpu_core_properties[] = { -diff --git a/target/ppc/cpu-models.c b/target/ppc/cpu-models.c -index 08a1f59..975aa07 100644 ---- a/target/ppc/cpu-models.c -+++ b/target/ppc/cpu-models.c -@@ -1150,8 +1150,10 @@ - "PowerPC 970 v2.2") - #endif - -- POWERPC_DEF("POWER9_v1.0", CPU_POWERPC_POWER9_BASE, POWER9, -+ POWERPC_DEF("POWER9_v1.0", CPU_POWERPC_POWER9_DD1, POWER9, - "POWER9 v1.0") -+ POWERPC_DEF("POWER9_v2.0", CPU_POWERPC_POWER9_DD20, POWER9, -+ "POWER9 v2.0") - - #if 0 /* Disabled for Red Hat Enterprise Linux */ - POWERPC_DEF("970fx_v1.0", CPU_POWERPC_970FX_v10, 970, -@@ -1403,7 +1405,7 @@ PowerPCCPUAlias ppc_cpu_aliases[] = { - { "POWER8E", "POWER8E_v2.1" }, - { "POWER8", "POWER8_v2.0" }, - { "POWER8NVL", "POWER8NVL_v1.0" }, -- { "POWER9", "POWER9_v1.0" }, -+ { "POWER9", "POWER9_v2.0" }, - #if 0 /* Disabled for Red Hat Enterprise Linux */ - { "970", "970_v2.2" }, - { "970fx", "970fx_v3.1" }, -diff --git a/target/ppc/cpu-models.h b/target/ppc/cpu-models.h -index b563c45..fc1b1d2 100644 ---- a/target/ppc/cpu-models.h -+++ b/target/ppc/cpu-models.h -@@ -562,6 +562,7 @@ enum { - CPU_POWERPC_POWER8NVL_v10 = 0x004C0100, - CPU_POWERPC_POWER9_BASE = 0x004E0000, - CPU_POWERPC_POWER9_DD1 = 0x004E0100, -+ CPU_POWERPC_POWER9_DD20 = 0x004E1200, - CPU_POWERPC_970_v22 = 0x00390202, - CPU_POWERPC_970FX_v10 = 0x00391100, - CPU_POWERPC_970FX_v20 = 0x003C0200, --- -1.8.3.1 - diff --git a/SOURCES/kvm-target-ppc-Check-mask-when-setting-cap_ppc_safe_indi.patch b/SOURCES/kvm-target-ppc-Check-mask-when-setting-cap_ppc_safe_indi.patch deleted file mode 100644 index f54eb2f..0000000 --- a/SOURCES/kvm-target-ppc-Check-mask-when-setting-cap_ppc_safe_indi.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 97905eb55273dac61e4d6ff300638c0b133e0f06 Mon Sep 17 00:00:00 2001 -From: Suraj Jitindar Singh -Date: Tue, 13 Mar 2018 05:21:31 +0100 -Subject: [PATCH 09/17] target/ppc: Check mask when setting - cap_ppc_safe_indirect_branch - -RH-Author: Suraj Jitindar Singh -Message-id: <1520918499-27663-4-git-send-email-sursingh@redhat.com> -Patchwork-id: 79249 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 03/11] target/ppc: Check mask when setting cap_ppc_safe_indirect_branch -Bugzilla: 1554957 -RH-Acked-by: David Gibson -RH-Acked-by: Laurent Vivier -RH-Acked-by: Miroslav Rezanina - -From: Suraj Jitindar Singh - -Check the character and character_mask field when setting -cap_ppc_safe_indirect_branch based on the hypervisor response -to KVM_PPC_GET_CPU_CHAR. Previously the mask field wasn't checked -which was incorrect. - -Fixes: 8acc2ae5 (target/ppc/kvm: Add cap_ppc_safe_[cache/bounds_check/indirect_branch]) - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: David Gibson -(cherry picked from commit cb931c2108a59db0b4a22f0c439ee7362c4f95ab) - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1548919 - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: Miroslav Rezanina ---- - target/ppc/kvm.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c -index 7a7bc3b..4383953 100644 ---- a/target/ppc/kvm.c -+++ b/target/ppc/kvm.c -@@ -2511,7 +2511,7 @@ static void kvmppc_get_cpu_characteristics(KVMState *s) - cap_ppc_safe_bounds_check = 1; - } - /* Parse and set cap_ppc_safe_indirect_branch */ -- if (c.character & H_CPU_CHAR_BCCTRL_SERIALISED) { -+ if (c.character & c.character_mask & H_CPU_CHAR_BCCTRL_SERIALISED) { - cap_ppc_safe_indirect_branch = 2; - } - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-target-ppc-Clarify-compat-mode-max_threads-value.patch b/SOURCES/kvm-target-ppc-Clarify-compat-mode-max_threads-value.patch deleted file mode 100644 index 8ec069a..0000000 --- a/SOURCES/kvm-target-ppc-Clarify-compat-mode-max_threads-value.patch +++ /dev/null @@ -1,162 +0,0 @@ -From b25ff3cd5a8b561f58b0245115d61cde0572cbdc Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Fri, 19 Jan 2018 04:04:56 +0100 -Subject: [PATCH 16/21] target/ppc: Clarify compat mode max_threads value - -RH-Author: David Gibson -Message-id: <20180119040458.5629-3-dgibson@redhat.com> -Patchwork-id: 78676 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 2/4] target/ppc: Clarify compat mode max_threads value -Bugzilla: 1529243 -RH-Acked-by: Thomas Huth -RH-Acked-by: Laurent Vivier -RH-Acked-by: Miroslav Rezanina - -From: David Gibson - -We recently had some discussions that were sidetracked for a while, because -nearly everyone misapprehended the purpose of the 'max_threads' field in -the compatiblity modes table. It's all about guest expectations, not host -expectations or support (that's handled elsewhere). - -In an attempt to avoid a repeat of that confusion, rename the field to -'max_vthreads' and add an explanatory comment. - -Signed-off-by: David Gibson -Reviewed-by: Laurent Vivier -Reviewed-by: Greg Kurz -Reviewed-by: Jose Ricardo Ziviani -(cherry picked from commit abbc124753896f72e3715813ea20dd1924202ff0) -Signed-off-by: Miroslav Rezanina - -Conflicts: - hw/ppc/spapr.c - -Contextual conflict. - -Signed-off-by: David Gibson ---- - hw/ppc/spapr.c | 4 ++-- - target/ppc/compat.c | 25 +++++++++++++++++-------- - target/ppc/cpu.h | 2 +- - 3 files changed, 20 insertions(+), 11 deletions(-) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 66227c3..5233366 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -345,7 +345,7 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPRMachineState *spapr) - PowerPCCPU *cpu = POWERPC_CPU(cs); - DeviceClass *dc = DEVICE_GET_CLASS(cs); - int index = ppc_get_vcpu_dt_id(cpu); -- int compat_smt = MIN(smp_threads, ppc_compat_max_threads(cpu)); -+ int compat_smt = MIN(smp_threads, ppc_compat_max_vthreads(cpu)); - - if ((index % smt) != 0) { - continue; -@@ -506,7 +506,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, - size_t page_sizes_prop_size; - uint32_t vcpus_per_socket = smp_threads * smp_cores; - uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)}; -- int compat_smt = MIN(smp_threads, ppc_compat_max_threads(cpu)); -+ int compat_smt = MIN(smp_threads, ppc_compat_max_vthreads(cpu)); - sPAPRDRConnector *drc; - int drc_index; - uint32_t radix_AP_encodings[PPC_PAGE_SIZES_MAX_SZ]; -diff --git a/target/ppc/compat.c b/target/ppc/compat.c -index 94ff14a..33658fb 100644 ---- a/target/ppc/compat.c -+++ b/target/ppc/compat.c -@@ -32,7 +32,16 @@ typedef struct { - uint32_t pvr; - uint64_t pcr; - uint64_t pcr_level; -- int max_threads; -+ -+ /* -+ * Maximum allowed virtual threads per virtual core -+ * -+ * This is to stop older guests getting confused by seeing more -+ * threads than they think the cpu can support. Usually it's -+ * equal to the number of threads supported on bare metal -+ * hardware, but not always (see POWER9). -+ */ -+ int max_vthreads; - } CompatInfo; - - static const CompatInfo compat_table[] = { -@@ -45,28 +54,28 @@ static const CompatInfo compat_table[] = { - .pcr = PCR_COMPAT_3_00 | PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | - PCR_COMPAT_2_05 | PCR_TM_DIS | PCR_VSX_DIS, - .pcr_level = PCR_COMPAT_2_05, -- .max_threads = 2, -+ .max_vthreads = 2, - }, - { /* POWER7, ISA2.06 */ - .name = "power7", - .pvr = CPU_POWERPC_LOGICAL_2_06, - .pcr = PCR_COMPAT_3_00 | PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS, - .pcr_level = PCR_COMPAT_2_06, -- .max_threads = 4, -+ .max_vthreads = 4, - }, - { - .name = "power7+", - .pvr = CPU_POWERPC_LOGICAL_2_06_PLUS, - .pcr = PCR_COMPAT_3_00 | PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS, - .pcr_level = PCR_COMPAT_2_06, -- .max_threads = 4, -+ .max_vthreads = 4, - }, - { /* POWER8, ISA2.07 */ - .name = "power8", - .pvr = CPU_POWERPC_LOGICAL_2_07, - .pcr = PCR_COMPAT_3_00 | PCR_COMPAT_2_07, - .pcr_level = PCR_COMPAT_2_07, -- .max_threads = 8, -+ .max_vthreads = 8, - }, - { /* POWER9, ISA3.00 */ - .name = "power9", -@@ -80,7 +89,7 @@ static const CompatInfo compat_table[] = { - * confusing if half of the threads disappear from the guest - * if it announces it's POWER9 aware at CAS time. - */ -- .max_threads = 8, -+ .max_vthreads = 8, - }, - }; - -@@ -203,14 +212,14 @@ void ppc_set_compat_all(uint32_t compat_pvr, Error **errp) - } - } - --int ppc_compat_max_threads(PowerPCCPU *cpu) -+int ppc_compat_max_vthreads(PowerPCCPU *cpu) - { - const CompatInfo *compat = compat_by_pvr(cpu->compat_pvr); - int n_threads = CPU(cpu)->nr_threads; - - if (cpu->compat_pvr) { - g_assert(compat); -- n_threads = MIN(n_threads, compat->max_threads); -+ n_threads = MIN(n_threads, compat->max_vthreads); - } - - return n_threads; -diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h -index 6c770a2..9b107e4 100644 ---- a/target/ppc/cpu.h -+++ b/target/ppc/cpu.h -@@ -1374,7 +1374,7 @@ void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp); - #if !defined(CONFIG_USER_ONLY) - void ppc_set_compat_all(uint32_t compat_pvr, Error **errp); - #endif --int ppc_compat_max_threads(PowerPCCPU *cpu); -+int ppc_compat_max_vthreads(PowerPCCPU *cpu); - void ppc_compat_add_property(Object *obj, const char *name, - uint32_t *compat_pvr, const char *basedesc, - Error **errp); --- -1.8.3.1 - diff --git a/SOURCES/kvm-target-ppc-Don-t-require-private-l1d-cache-on-POWER8.patch b/SOURCES/kvm-target-ppc-Don-t-require-private-l1d-cache-on-POWER8.patch new file mode 100644 index 0000000..c89979f --- /dev/null +++ b/SOURCES/kvm-target-ppc-Don-t-require-private-l1d-cache-on-POWER8.patch @@ -0,0 +1,72 @@ +From 9d53600d84c407efde9e186b814badca245cc6ab Mon Sep 17 00:00:00 2001 +From: Suraj Jitindar Singh +Date: Thu, 21 Jun 2018 06:56:48 +0200 +Subject: [PATCH 53/54] target/ppc: Don't require private l1d cache on POWER8 + for cap_ppc_safe_cache + +RH-Author: Suraj Jitindar Singh +Message-id: <1529564209-30369-3-git-send-email-sursingh@redhat.com> +Patchwork-id: 80930 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 2/3] target/ppc: Don't require private l1d cache on POWER8 for cap_ppc_safe_cache +Bugzilla: 1560847 +RH-Acked-by: Laurent Vivier +RH-Acked-by: David Gibson +RH-Acked-by: Miroslav Rezanina + +From: Suraj Jitindar Singh + +For cap_ppc_safe_cache to be set to workaround, we require both a l1d +cache flush instruction and private l1d cache. + +On POWER8 don't require private l1d cache. This means a guest on a +POWER8 machine can make use of the cache flush workarounds. + +Signed-off-by: Suraj Jitindar Singh +Signed-off-by: David Gibson +(cherry picked from commit 072f416a53ead5211c987cb2068ee9dbd7ba06cc) + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1560847 + +Signed-off-by: Suraj Jitindar Singh +Signed-off-by: Miroslav Rezanina +--- + target/ppc/kvm.c | 19 ++++++++++++++++++- + 1 file changed, 18 insertions(+), 1 deletion(-) + +diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c +index d787032..192c40d 100644 +--- a/target/ppc/kvm.c ++++ b/target/ppc/kvm.c +@@ -2461,11 +2461,28 @@ bool kvmppc_has_cap_mmu_hash_v3(void) + return cap_mmu_hash_v3; + } + ++static bool kvmppc_power8_host(void) ++{ ++ bool ret = false; ++#ifdef TARGET_PPC64 ++ { ++ uint32_t base_pvr = CPU_POWERPC_POWER_SERVER_MASK & mfpvr(); ++ ret = (base_pvr == CPU_POWERPC_POWER8E_BASE) || ++ (base_pvr == CPU_POWERPC_POWER8NVL_BASE) || ++ (base_pvr == CPU_POWERPC_POWER8_BASE); ++ } ++#endif /* TARGET_PPC64 */ ++ return ret; ++} ++ + static int parse_cap_ppc_safe_cache(struct kvm_ppc_cpu_char c) + { ++ bool l1d_thread_priv_req = !kvmppc_power8_host(); ++ + if (~c.behaviour & c.behaviour_mask & H_CPU_BEHAV_L1D_FLUSH_PR) { + return 2; +- } else if ((c.character & c.character_mask & H_CPU_CHAR_L1D_THREAD_PRIV) && ++ } else if ((!l1d_thread_priv_req || ++ c.character & c.character_mask & H_CPU_CHAR_L1D_THREAD_PRIV) && + (c.character & c.character_mask + & (H_CPU_CHAR_L1D_FLUSH_ORI30 | H_CPU_CHAR_L1D_FLUSH_TRIG2))) { + return 1; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-target-ppc-Factor-out-the-parsing-in-kvmppc_get_cpu_.patch b/SOURCES/kvm-target-ppc-Factor-out-the-parsing-in-kvmppc_get_cpu_.patch new file mode 100644 index 0000000..56be789 --- /dev/null +++ b/SOURCES/kvm-target-ppc-Factor-out-the-parsing-in-kvmppc_get_cpu_.patch @@ -0,0 +1,113 @@ +From f9867a5df572d3b52fcd08b86878de9426354503 Mon Sep 17 00:00:00 2001 +From: Suraj Jitindar Singh +Date: Thu, 21 Jun 2018 06:56:47 +0200 +Subject: [PATCH 52/54] target/ppc: Factor out the parsing in + kvmppc_get_cpu_characteristics() + +RH-Author: Suraj Jitindar Singh +Message-id: <1529564209-30369-2-git-send-email-sursingh@redhat.com> +Patchwork-id: 80927 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/3] target/ppc: Factor out the parsing in kvmppc_get_cpu_characteristics() +Bugzilla: 1560847 +RH-Acked-by: Laurent Vivier +RH-Acked-by: David Gibson +RH-Acked-by: Miroslav Rezanina + +From: Suraj Jitindar Singh + +Factor out the parsing of struct kvm_ppc_cpu_char in +kvmppc_get_cpu_characteristics() into a separate function for each cap +for simplicity. + +Signed-off-by: Suraj Jitindar Singh +Signed-off-by: David Gibson +(cherry picked from commit 8fea70440eb0d095442de7e80d586a285cf96be5) + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1560847 + +Signed-off-by: Suraj Jitindar Singh +Signed-off-by: Miroslav Rezanina +--- + target/ppc/kvm.c | 59 +++++++++++++++++++++++++++++++++++++------------------- + 1 file changed, 39 insertions(+), 20 deletions(-) + +diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c +index 79a436a..d787032 100644 +--- a/target/ppc/kvm.c ++++ b/target/ppc/kvm.c +@@ -2461,6 +2461,41 @@ bool kvmppc_has_cap_mmu_hash_v3(void) + return cap_mmu_hash_v3; + } + ++static int parse_cap_ppc_safe_cache(struct kvm_ppc_cpu_char c) ++{ ++ if (~c.behaviour & c.behaviour_mask & H_CPU_BEHAV_L1D_FLUSH_PR) { ++ return 2; ++ } else if ((c.character & c.character_mask & H_CPU_CHAR_L1D_THREAD_PRIV) && ++ (c.character & c.character_mask ++ & (H_CPU_CHAR_L1D_FLUSH_ORI30 | H_CPU_CHAR_L1D_FLUSH_TRIG2))) { ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static int parse_cap_ppc_safe_bounds_check(struct kvm_ppc_cpu_char c) ++{ ++ if (~c.behaviour & c.behaviour_mask & H_CPU_BEHAV_BNDS_CHK_SPEC_BAR) { ++ return 2; ++ } else if (c.character & c.character_mask & H_CPU_CHAR_SPEC_BAR_ORI31) { ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static int parse_cap_ppc_safe_indirect_branch(struct kvm_ppc_cpu_char c) ++{ ++ if (c.character & c.character_mask & H_CPU_CHAR_CACHE_COUNT_DIS) { ++ return SPAPR_CAP_FIXED_CCD; ++ } else if (c.character & c.character_mask & H_CPU_CHAR_BCCTRL_SERIALISED) { ++ return SPAPR_CAP_FIXED_IBS; ++ } ++ ++ return 0; ++} ++ + static void kvmppc_get_cpu_characteristics(KVMState *s) + { + struct kvm_ppc_cpu_char c; +@@ -2479,26 +2514,10 @@ static void kvmppc_get_cpu_characteristics(KVMState *s) + if (ret < 0) { + return; + } +- /* Parse and set cap_ppc_safe_cache */ +- if (~c.behaviour & c.behaviour_mask & H_CPU_BEHAV_L1D_FLUSH_PR) { +- cap_ppc_safe_cache = 2; +- } else if ((c.character & c.character_mask & H_CPU_CHAR_L1D_THREAD_PRIV) && +- (c.character & c.character_mask +- & (H_CPU_CHAR_L1D_FLUSH_ORI30 | H_CPU_CHAR_L1D_FLUSH_TRIG2))) { +- cap_ppc_safe_cache = 1; +- } +- /* Parse and set cap_ppc_safe_bounds_check */ +- if (~c.behaviour & c.behaviour_mask & H_CPU_BEHAV_BNDS_CHK_SPEC_BAR) { +- cap_ppc_safe_bounds_check = 2; +- } else if (c.character & c.character_mask & H_CPU_CHAR_SPEC_BAR_ORI31) { +- cap_ppc_safe_bounds_check = 1; +- } +- /* Parse and set cap_ppc_safe_indirect_branch */ +- if (c.character & c.character_mask & H_CPU_CHAR_CACHE_COUNT_DIS) { +- cap_ppc_safe_indirect_branch = SPAPR_CAP_FIXED_CCD; +- } else if (c.character & c.character_mask & H_CPU_CHAR_BCCTRL_SERIALISED) { +- cap_ppc_safe_indirect_branch = SPAPR_CAP_FIXED_IBS; +- } ++ ++ cap_ppc_safe_cache = parse_cap_ppc_safe_cache(c); ++ cap_ppc_safe_bounds_check = parse_cap_ppc_safe_bounds_check(c); ++ cap_ppc_safe_indirect_branch = parse_cap_ppc_safe_indirect_branch(c); + } + + int kvmppc_get_cap_safe_cache(void) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-target-ppc-Fix-setting-of-cpu-compat_pvr-on-incoming.patch b/SOURCES/kvm-target-ppc-Fix-setting-of-cpu-compat_pvr-on-incoming.patch deleted file mode 100644 index ad5934a..0000000 --- a/SOURCES/kvm-target-ppc-Fix-setting-of-cpu-compat_pvr-on-incoming.patch +++ /dev/null @@ -1,63 +0,0 @@ -From ae27b925a8cda59917f47b834492fc77d341d898 Mon Sep 17 00:00:00 2001 -From: Suraj Jitindar Singh -Date: Tue, 5 Dec 2017 05:55:19 +0100 -Subject: [PATCH 14/21] target/ppc: Fix setting of cpu->compat_pvr on incoming - migration - -RH-Author: Suraj Jitindar Singh -Message-id: <1512453319-16676-3-git-send-email-sursingh@redhat.com> -Patchwork-id: 78133 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 2/2] target/ppc: Fix setting of cpu->compat_pvr on incoming migration -Bugzilla: 1517051 -RH-Acked-by: Laurent Vivier -RH-Acked-by: David Gibson -RH-Acked-by: Thomas Huth - -From: Suraj Jitindar Singh - -cpu->compat_pvr is used to store the current compat mode of the cpu. - -On the receiving side during incoming migration we check compatibility -with the compat mode by calling ppc_set_compat(). However we fail to set -the compat mode with the hypervisor since the "new" compat mode doesn't -differ from the current (due to a "cpu->compat_pvr != compat_pvr" check). -This means that kvm runs the vcpus without a compat mode, which is the -incorrect behaviour. The implication being that a compatibility mode -will never be in effect after migration. - -To fix this so that the compat mode is correctly set with the -hypervisor, store the desired compat mode and reset cpu->compat_pvr to -zero before calling ppc_set_compat(). - -Fixes: 5dfaa532 ("ppc: fix ppc_set_compat() with KVM PR") - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: David Gibson -(cherry picked from commit e07cc1929515cfb808b5c2fcc60c079e6be110cf) - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: Miroslav Rezanina ---- - target/ppc/machine.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/target/ppc/machine.c b/target/ppc/machine.c -index e36b710..760be64d 100644 ---- a/target/ppc/machine.c -+++ b/target/ppc/machine.c -@@ -235,9 +235,11 @@ static int cpu_post_load(void *opaque, int version_id) - - #if defined(TARGET_PPC64) - if (cpu->compat_pvr) { -+ uint32_t compat_pvr = cpu->compat_pvr; - Error *local_err = NULL; - -- ppc_set_compat(cpu, cpu->compat_pvr, &local_err); -+ cpu->compat_pvr = 0; -+ ppc_set_compat(cpu, compat_pvr, &local_err); - if (local_err) { - error_report_err(local_err); - return -1; --- -1.8.3.1 - diff --git a/SOURCES/kvm-target-ppc-Move-setting-of-patb_entry-on-hash-table-.patch b/SOURCES/kvm-target-ppc-Move-setting-of-patb_entry-on-hash-table-.patch deleted file mode 100644 index 29876ca..0000000 --- a/SOURCES/kvm-target-ppc-Move-setting-of-patb_entry-on-hash-table-.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 57adfa908abbf97d98a19724447565731f3f825f Mon Sep 17 00:00:00 2001 -From: Suraj Jitindar Singh -Date: Tue, 5 Dec 2017 05:55:18 +0100 -Subject: [PATCH 13/21] target/ppc: Move setting of patb_entry on hash table - init - -RH-Author: Suraj Jitindar Singh -Message-id: <1512453319-16676-2-git-send-email-sursingh@redhat.com> -Patchwork-id: 78134 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 1/2] target/ppc: Move setting of patb_entry on hash table init -Bugzilla: 1517051 -RH-Acked-by: Laurent Vivier -RH-Acked-by: David Gibson -RH-Acked-by: Thomas Huth - -From: Suraj Jitindar Singh - -The patb_entry is used to store the location of the process table in -guest memory. The msb is also used to indicate the mmu mode of the -guest, that is patb_entry & 1 << 63 ? radix_mode : hash_mode. - -Currently we set this to zero in spapr_setup_hpt_and_vrma() since if -this function gets called then we know we're hash. However some code -paths, such as setting up the hpt on incoming migration of a hash guest, -call spapr_reallocate_hpt() directly bypassing this higher level -function. Since we assume radix if the host is capable this results in -the msb in patb_entry being left set so in spapr_post_load() we call -kvmppc_configure_v3_mmu() and tell the host we're radix which as -expected means addresses cannot be translated once we actually run the cpu. - -To fix this move the zeroing of patb_entry into spapr_reallocate_hpt(). - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: David Gibson -(cherry picked from commit ee4d9ecc3675af1e68a9c00a8b338641898d613e) - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 8623996..e3dce84 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -1356,6 +1356,8 @@ void spapr_reallocate_hpt(sPAPRMachineState *spapr, int shift, - DIRTY_HPTE(HPTE(spapr->htab, i)); - } - } -+ /* We're setting up a hash table, so that means we're not radix */ -+ spapr->patb_entry = 0; - } - - void spapr_setup_hpt_and_vrma(sPAPRMachineState *spapr) -@@ -1375,8 +1377,6 @@ void spapr_setup_hpt_and_vrma(sPAPRMachineState *spapr) - spapr->rma_size = kvmppc_rma_size(spapr_node0_size(), - spapr->htab_shift); - } -- /* We're setting up a hash table, so that means we're not radix */ -- spapr->patb_entry = 0; - } - - static void find_unknown_sysbus_device(SysBusDevice *sbdev, void *opaque) --- -1.8.3.1 - diff --git a/SOURCES/kvm-target-ppc-Update-setting-of-cpu-features-to-account.patch b/SOURCES/kvm-target-ppc-Update-setting-of-cpu-features-to-account.patch deleted file mode 100644 index 996a12e..0000000 --- a/SOURCES/kvm-target-ppc-Update-setting-of-cpu-features-to-account.patch +++ /dev/null @@ -1,168 +0,0 @@ -From ba38a0071969c6a428cf165e31ec0e91b7167af8 Mon Sep 17 00:00:00 2001 -From: Suraj Jitindar Singh -Date: Fri, 24 Nov 2017 00:58:17 +0100 -Subject: [PATCH 12/15] target/ppc: Update setting of cpu features to account - for compat modes - -RH-Author: Suraj Jitindar Singh -Message-id: <1511485097-25676-3-git-send-email-sursingh@redhat.com> -Patchwork-id: 77847 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 2/2] target/ppc: Update setting of cpu features to account for compat modes -Bugzilla: 1396120 -RH-Acked-by: David Gibson -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth - -From: Suraj Jitindar Singh - -The device tree nodes ibm,arch-vec-5-platform-support and ibm,pa-features -are used to communicate features of the cpu to the guest operating -system. The properties of each of these are determined based on the -selected cpu model and the availability of hypervisor features. -Currently the compatibility mode of the cpu is not taken into account. - -The ibm,arch-vec-5-platform-support node is used to communicate the -level of support for various ISAv3 processor features to the guest -before CAS to inform the guests' request. The available mmu mode should -only be hash unless the cpu is a POWER9 which is not in a prePOWER9 -compat mode, in which case the available modes depend on the -accelerator and the hypervisor capabilities. - -The ibm,pa-featues node is used to communicate the level of cpu support -for various features to the guest os. This should only contain features -relevant to the operating mode of the processor, that is the selected -cpu model taking into account any compat mode. This means that the -compat mode should be taken into account when choosing the properties of -ibm,pa-features and they should match the compat mode selected, or the -cpu model selected if no compat mode. - -Update the setting of these cpu features in the device tree as described -above to properly take into account any compat mode. We use the -ppc_check_compat function which takes into account the current processor -model and the cpu compat mode. - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: David Gibson -(cherry picked from commit 7abd43baec0649002d32bbb1380e936bec6f5867) - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr.c | 43 +++++++++++++++++++++---------------------- - 1 file changed, 21 insertions(+), 22 deletions(-) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 42028ef..96df3a7 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -44,6 +44,7 @@ - #include "migration/register.h" - #include "mmu-hash64.h" - #include "mmu-book3s-v3.h" -+#include "cpu-models.h" - #include "qom/cpu.h" - - #include "hw/boards.h" -@@ -252,9 +253,10 @@ static int spapr_fixup_cpu_numa_dt(void *fdt, int offset, PowerPCCPU *cpu) - } - - /* Populate the "ibm,pa-features" property */ --static void spapr_populate_pa_features(CPUPPCState *env, void *fdt, int offset, -- bool legacy_guest) -+static void spapr_populate_pa_features(PowerPCCPU *cpu, void *fdt, int offset, -+ bool legacy_guest) - { -+ CPUPPCState *env = &cpu->env; - uint8_t pa_features_206[] = { 6, 0, - 0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 }; - uint8_t pa_features_207[] = { 24, 0, -@@ -287,23 +289,22 @@ static void spapr_populate_pa_features(CPUPPCState *env, void *fdt, int offset, - /* 60: NM atomic, 62: RNG */ - 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 60 - 65 */ - }; -- uint8_t *pa_features; -+ uint8_t *pa_features = NULL; - size_t pa_size; - -- switch (POWERPC_MMU_VER(env->mmu_model)) { -- case POWERPC_MMU_VER_2_06: -+ if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06, 0, cpu->compat_pvr)) { - pa_features = pa_features_206; - pa_size = sizeof(pa_features_206); -- break; -- case POWERPC_MMU_VER_2_07: -+ } -+ if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07, 0, cpu->compat_pvr)) { - pa_features = pa_features_207; - pa_size = sizeof(pa_features_207); -- break; -- case POWERPC_MMU_VER_3_00: -+ } -+ if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00, 0, cpu->compat_pvr)) { - pa_features = pa_features_300; - pa_size = sizeof(pa_features_300); -- break; -- default: -+ } -+ if (!pa_features) { - return; - } - -@@ -340,7 +341,6 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPRMachineState *spapr) - - CPU_FOREACH(cs) { - PowerPCCPU *cpu = POWERPC_CPU(cs); -- CPUPPCState *env = &cpu->env; - DeviceClass *dc = DEVICE_GET_CLASS(cs); - int index = ppc_get_vcpu_dt_id(cpu); - int compat_smt = MIN(smp_threads, ppc_compat_max_threads(cpu)); -@@ -385,7 +385,7 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPRMachineState *spapr) - return ret; - } - -- spapr_populate_pa_features(env, fdt, offset, -+ spapr_populate_pa_features(cpu, fdt, offset, - spapr->cas_legacy_guest_workaround); - } - return ret; -@@ -582,7 +582,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, - page_sizes_prop, page_sizes_prop_size))); - } - -- spapr_populate_pa_features(env, fdt, offset, false); -+ spapr_populate_pa_features(cpu, fdt, offset, false); - - _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", - cs->cpu_index / vcpus_per_socket))); -@@ -945,7 +945,11 @@ static void spapr_dt_ov5_platform_support(void *fdt, int chosen) - 26, 0x40, /* Radix options: GTSE == yes. */ - }; - -- if (kvm_enabled()) { -+ if (!ppc_check_compat(first_ppc_cpu, CPU_POWERPC_LOGICAL_3_00, 0, -+ first_ppc_cpu->compat_pvr)) { -+ /* If we're in a pre POWER9 compat mode then the guest should do hash */ -+ val[3] = 0x00; /* Hash */ -+ } else if (kvm_enabled()) { - if (kvmppc_has_cap_mmu_radix() && kvmppc_has_cap_mmu_hash_v3()) { - val[3] = 0x80; /* OV5_MMU_BOTH */ - } else if (kvmppc_has_cap_mmu_radix()) { -@@ -954,13 +958,8 @@ static void spapr_dt_ov5_platform_support(void *fdt, int chosen) - val[3] = 0x00; /* Hash */ - } - } else { -- if (first_ppc_cpu->env.mmu_model & POWERPC_MMU_V3) { -- /* V3 MMU supports both hash and radix (with dynamic switching) */ -- val[3] = 0xC0; -- } else { -- /* Otherwise we can only do hash */ -- val[3] = 0x00; -- } -+ /* V3 MMU supports both hash and radix in tcg (with dynamic switching) */ -+ val[3] = 0xC0; - } - _FDT(fdt_setprop(fdt, chosen, "ibm,arch-vec-5-platform-support", - val, sizeof(val))); --- -1.8.3.1 - diff --git a/SOURCES/kvm-target-ppc-correct-htab-shift-for-hash-on-radix.patch b/SOURCES/kvm-target-ppc-correct-htab-shift-for-hash-on-radix.patch deleted file mode 100644 index 2b162e9..0000000 --- a/SOURCES/kvm-target-ppc-correct-htab-shift-for-hash-on-radix.patch +++ /dev/null @@ -1,78 +0,0 @@ -From c1ed391fd7e14e16387f8d5e320b13157851db9a Mon Sep 17 00:00:00 2001 -From: Suraj Jitindar Singh -Date: Fri, 24 Nov 2017 00:58:16 +0100 -Subject: [PATCH 11/15] target/ppc: correct htab shift for hash on radix - -RH-Author: Suraj Jitindar Singh -Message-id: <1511485097-25676-2-git-send-email-sursingh@redhat.com> -Patchwork-id: 77845 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 1/2] target/ppc: correct htab shift for hash on radix -Bugzilla: 1396120 -RH-Acked-by: David Gibson -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth - -From: Sam Bobroff - -KVM HV will soon support running a guest in hash mode on a POWER9 host -running in radix mode (see [1]), however the guest currently fails to -boot. - -This is because the "htab_shift" value (the size of the MMU's hash -table) is added to the device tree before KVM has had a chance to -change it. If the host is in hash mode, KVM does not need to change it -and so the problem is not seen, but when the host is in radix mode a -change is required and we see a problem. - -To fix this, move the call spapr_setup_hpt_and_vrma() (where -htab_shift could be changed) up a little so that it's called before -spapr_h_cas_compose_response() (where htab_shift is added to the -device tree). - -Signed-off-by: Sam Bobroff - -[1] See http://www.spinics.net/lists/kvm-ppc/msg13057.html -Signed-off-by: David Gibson - -(cherry picked from commit e05fba5004676cd0fa7c47b623cb0a14ad1feed8) - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr_hcall.c | 13 ++++++------- - 1 file changed, 6 insertions(+), 7 deletions(-) - -diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c -index 92f1e21..b503299 100644 ---- a/hw/ppc/spapr_hcall.c -+++ b/hw/ppc/spapr_hcall.c -@@ -1609,6 +1609,12 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, - spapr->cas_legacy_guest_workaround = !spapr_ovec_test(ov1_guest, - OV1_PPC_3_00); - if (!spapr->cas_reboot) { -+ /* If ppc_spapr_reset() did not set up a HPT but one is necessary -+ * (because the guest isn't going to use radix) then set it up here. */ -+ if ((spapr->patb_entry & PATBE1_GR) && !guest_radix) { -+ /* legacy hash or new hash: */ -+ spapr_setup_hpt_and_vrma(spapr); -+ } - spapr->cas_reboot = - (spapr_h_cas_compose_response(spapr, args[1], args[2], - ov5_updates) != 0); -@@ -1617,13 +1623,6 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, - - if (spapr->cas_reboot) { - qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); -- } else { -- /* If ppc_spapr_reset() did not set up a HPT but one is necessary -- * (because the guest isn't going to use radix) then set it up here. */ -- if ((spapr->patb_entry & PATBE1_GR) && !guest_radix) { -- /* legacy hash or new hash: */ -- spapr_setup_hpt_and_vrma(spapr); -- } - } - - return H_SUCCESS; --- -1.8.3.1 - diff --git a/SOURCES/kvm-target-ppc-introduce-the-PPC_BIT-macro.patch b/SOURCES/kvm-target-ppc-introduce-the-PPC_BIT-macro.patch deleted file mode 100644 index 53cef0e..0000000 --- a/SOURCES/kvm-target-ppc-introduce-the-PPC_BIT-macro.patch +++ /dev/null @@ -1,190 +0,0 @@ -From 6c787760c9ce1b5101c29e43de38d8e1974be482 Mon Sep 17 00:00:00 2001 -From: Suraj Jitindar Singh -Date: Tue, 13 Feb 2018 04:12:28 +0100 -Subject: [PATCH 11/15] target/ppc: introduce the PPC_BIT() macro -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Suraj Jitindar Singh -Message-id: <1518495150-24134-8-git-send-email-sursingh@redhat.com> -Patchwork-id: 78989 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 7/9] target/ppc: introduce the PPC_BIT() macro -Bugzilla: 1532050 -RH-Acked-by: David Gibson -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth - -From: Cédric Le Goater - -and use them in a couple of obvious places. Other macros will be used -in the model of the XIVE interrupt controller. - -Signed-off-by: Cédric Le Goater -Signed-off-by: David Gibson -(cherry picked from commit 2a83f9976efa9a85e8ceb9d1035a68f25c321334) - -Conflicts: none - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1532050 - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: Miroslav Rezanina ---- - target/ppc/cpu.h | 105 +++++++++++++++++++++++++++++-------------------------- - 1 file changed, 56 insertions(+), 49 deletions(-) - -diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h -index 9b107e4..7453250 100644 ---- a/target/ppc/cpu.h -+++ b/target/ppc/cpu.h -@@ -87,6 +87,13 @@ - #define PPC_ELF_MACHINE EM_PPC - #endif - -+#define PPC_BIT(bit) (0x8000000000000000UL >> (bit)) -+#define PPC_BIT32(bit) (0x80000000UL >> (bit)) -+#define PPC_BIT8(bit) (0x80UL >> (bit)) -+#define PPC_BITMASK(bs, be) ((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs)) -+#define PPC_BITMASK32(bs, be) ((PPC_BIT32(bs) - PPC_BIT32(be)) | \ -+ PPC_BIT32(bs)) -+ - /*****************************************************************************/ - /* Exception vectors definitions */ - enum { -@@ -371,10 +378,10 @@ struct ppc_slb_t { - #define MSR_LE 0 /* Little-endian mode 1 hflags */ - - /* LPCR bits */ --#define LPCR_VPM0 (1ull << (63 - 0)) --#define LPCR_VPM1 (1ull << (63 - 1)) --#define LPCR_ISL (1ull << (63 - 2)) --#define LPCR_KBV (1ull << (63 - 3)) -+#define LPCR_VPM0 PPC_BIT(0) -+#define LPCR_VPM1 PPC_BIT(1) -+#define LPCR_ISL PPC_BIT(2) -+#define LPCR_KBV PPC_BIT(3) - #define LPCR_DPFD_SHIFT (63 - 11) - #define LPCR_DPFD (0x7ull << LPCR_DPFD_SHIFT) - #define LPCR_VRMASD_SHIFT (63 - 16) -@@ -382,41 +389,41 @@ struct ppc_slb_t { - /* P9: Power-saving mode Exit Cause Enable (Upper Section) Mask */ - #define LPCR_PECE_U_SHIFT (63 - 19) - #define LPCR_PECE_U_MASK (0x7ull << LPCR_PECE_U_SHIFT) --#define LPCR_HVEE (1ull << (63 - 17)) /* Hypervisor Virt Exit Enable */ -+#define LPCR_HVEE PPC_BIT(17) /* Hypervisor Virt Exit Enable */ - #define LPCR_RMLS_SHIFT (63 - 37) - #define LPCR_RMLS (0xfull << LPCR_RMLS_SHIFT) --#define LPCR_ILE (1ull << (63 - 38)) -+#define LPCR_ILE PPC_BIT(38) - #define LPCR_AIL_SHIFT (63 - 40) /* Alternate interrupt location */ - #define LPCR_AIL (3ull << LPCR_AIL_SHIFT) --#define LPCR_UPRT (1ull << (63 - 41)) /* Use Process Table */ --#define LPCR_EVIRT (1ull << (63 - 42)) /* Enhanced Virtualisation */ --#define LPCR_ONL (1ull << (63 - 45)) --#define LPCR_LD (1ull << (63 - 46)) /* Large Decrementer */ --#define LPCR_P7_PECE0 (1ull << (63 - 49)) --#define LPCR_P7_PECE1 (1ull << (63 - 50)) --#define LPCR_P7_PECE2 (1ull << (63 - 51)) --#define LPCR_P8_PECE0 (1ull << (63 - 47)) --#define LPCR_P8_PECE1 (1ull << (63 - 48)) --#define LPCR_P8_PECE2 (1ull << (63 - 49)) --#define LPCR_P8_PECE3 (1ull << (63 - 50)) --#define LPCR_P8_PECE4 (1ull << (63 - 51)) -+#define LPCR_UPRT PPC_BIT(41) /* Use Process Table */ -+#define LPCR_EVIRT PPC_BIT(42) /* Enhanced Virtualisation */ -+#define LPCR_ONL PPC_BIT(45) -+#define LPCR_LD PPC_BIT(46) /* Large Decrementer */ -+#define LPCR_P7_PECE0 PPC_BIT(49) -+#define LPCR_P7_PECE1 PPC_BIT(50) -+#define LPCR_P7_PECE2 PPC_BIT(51) -+#define LPCR_P8_PECE0 PPC_BIT(47) -+#define LPCR_P8_PECE1 PPC_BIT(48) -+#define LPCR_P8_PECE2 PPC_BIT(49) -+#define LPCR_P8_PECE3 PPC_BIT(50) -+#define LPCR_P8_PECE4 PPC_BIT(51) - /* P9: Power-saving mode Exit Cause Enable (Lower Section) Mask */ - #define LPCR_PECE_L_SHIFT (63 - 51) - #define LPCR_PECE_L_MASK (0x1full << LPCR_PECE_L_SHIFT) --#define LPCR_PDEE (1ull << (63 - 47)) /* Privileged Doorbell Exit EN */ --#define LPCR_HDEE (1ull << (63 - 48)) /* Hyperv Doorbell Exit Enable */ --#define LPCR_EEE (1ull << (63 - 49)) /* External Exit Enable */ --#define LPCR_DEE (1ull << (63 - 50)) /* Decrementer Exit Enable */ --#define LPCR_OEE (1ull << (63 - 51)) /* Other Exit Enable */ --#define LPCR_MER (1ull << (63 - 52)) --#define LPCR_GTSE (1ull << (63 - 53)) /* Guest Translation Shootdown */ --#define LPCR_TC (1ull << (63 - 54)) --#define LPCR_HEIC (1ull << (63 - 59)) /* HV Extern Interrupt Control */ --#define LPCR_LPES0 (1ull << (63 - 60)) --#define LPCR_LPES1 (1ull << (63 - 61)) --#define LPCR_RMI (1ull << (63 - 62)) --#define LPCR_HVICE (1ull << (63 - 62)) /* HV Virtualisation Int Enable */ --#define LPCR_HDICE (1ull << (63 - 63)) -+#define LPCR_PDEE PPC_BIT(47) /* Privileged Doorbell Exit EN */ -+#define LPCR_HDEE PPC_BIT(48) /* Hyperv Doorbell Exit Enable */ -+#define LPCR_EEE PPC_BIT(49) /* External Exit Enable */ -+#define LPCR_DEE PPC_BIT(50) /* Decrementer Exit Enable */ -+#define LPCR_OEE PPC_BIT(51) /* Other Exit Enable */ -+#define LPCR_MER PPC_BIT(52) -+#define LPCR_GTSE PPC_BIT(53) /* Guest Translation Shootdown */ -+#define LPCR_TC PPC_BIT(54) -+#define LPCR_HEIC PPC_BIT(59) /* HV Extern Interrupt Control */ -+#define LPCR_LPES0 PPC_BIT(60) -+#define LPCR_LPES1 PPC_BIT(61) -+#define LPCR_RMI PPC_BIT(62) -+#define LPCR_HVICE PPC_BIT(62) /* HV Virtualisation Int Enable */ -+#define LPCR_HDICE PPC_BIT(63) - - #define msr_sf ((env->msr >> MSR_SF) & 1) - #define msr_isf ((env->msr >> MSR_ISF) & 1) -@@ -507,22 +514,22 @@ struct ppc_slb_t { - #define FSCR_IC_TAR 8 - - /* Exception state register bits definition */ --#define ESR_PIL (1 << (63 - 36)) /* Illegal Instruction */ --#define ESR_PPR (1 << (63 - 37)) /* Privileged Instruction */ --#define ESR_PTR (1 << (63 - 38)) /* Trap */ --#define ESR_FP (1 << (63 - 39)) /* Floating-Point Operation */ --#define ESR_ST (1 << (63 - 40)) /* Store Operation */ --#define ESR_AP (1 << (63 - 44)) /* Auxiliary Processor Operation */ --#define ESR_PUO (1 << (63 - 45)) /* Unimplemented Operation */ --#define ESR_BO (1 << (63 - 46)) /* Byte Ordering */ --#define ESR_PIE (1 << (63 - 47)) /* Imprecise exception */ --#define ESR_DATA (1 << (63 - 53)) /* Data Access (Embedded page table) */ --#define ESR_TLBI (1 << (63 - 54)) /* TLB Ineligible (Embedded page table) */ --#define ESR_PT (1 << (63 - 55)) /* Page Table (Embedded page table) */ --#define ESR_SPV (1 << (63 - 56)) /* SPE/VMX operation */ --#define ESR_EPID (1 << (63 - 57)) /* External Process ID operation */ --#define ESR_VLEMI (1 << (63 - 58)) /* VLE operation */ --#define ESR_MIF (1 << (63 - 62)) /* Misaligned instruction (VLE) */ -+#define ESR_PIL PPC_BIT(36) /* Illegal Instruction */ -+#define ESR_PPR PPC_BIT(37) /* Privileged Instruction */ -+#define ESR_PTR PPC_BIT(38) /* Trap */ -+#define ESR_FP PPC_BIT(39) /* Floating-Point Operation */ -+#define ESR_ST PPC_BIT(40) /* Store Operation */ -+#define ESR_AP PPC_BIT(44) /* Auxiliary Processor Operation */ -+#define ESR_PUO PPC_BIT(45) /* Unimplemented Operation */ -+#define ESR_BO PPC_BIT(46) /* Byte Ordering */ -+#define ESR_PIE PPC_BIT(47) /* Imprecise exception */ -+#define ESR_DATA PPC_BIT(53) /* Data Access (Embedded page table) */ -+#define ESR_TLBI PPC_BIT(54) /* TLB Ineligible (Embedded page table) */ -+#define ESR_PT PPC_BIT(55) /* Page Table (Embedded page table) */ -+#define ESR_SPV PPC_BIT(56) /* SPE/VMX operation */ -+#define ESR_EPID PPC_BIT(57) /* External Process ID operation */ -+#define ESR_VLEMI PPC_BIT(58) /* VLE operation */ -+#define ESR_MIF PPC_BIT(62) /* Misaligned instruction (VLE) */ - - /* Transaction EXception And Summary Register bits */ - #define TEXASR_FAILURE_PERSISTENT (63 - 7) -@@ -1990,7 +1997,7 @@ void ppc_compat_add_property(Object *obj, const char *name, - #define HID0_DEEPNAP (1 << 24) /* pre-2.06 */ - #define HID0_DOZE (1 << 23) /* pre-2.06 */ - #define HID0_NAP (1 << 22) /* pre-2.06 */ --#define HID0_HILE (1ull << (63 - 19)) /* POWER8 */ -+#define HID0_HILE PPC_BIT(19) /* POWER8 */ - - /*****************************************************************************/ - /* PowerPC Instructions types definitions */ --- -1.8.3.1 - diff --git a/SOURCES/kvm-target-ppc-kvm-Add-cap_ppc_safe_-cache-bounds_check-.patch b/SOURCES/kvm-target-ppc-kvm-Add-cap_ppc_safe_-cache-bounds_check-.patch deleted file mode 100644 index 1103492..0000000 --- a/SOURCES/kvm-target-ppc-kvm-Add-cap_ppc_safe_-cache-bounds_check-.patch +++ /dev/null @@ -1,203 +0,0 @@ -From e8388e92e3bb6dbdd69ada6d7939e06e15875eeb Mon Sep 17 00:00:00 2001 -From: Suraj Jitindar Singh -Date: Tue, 13 Feb 2018 04:12:23 +0100 -Subject: [PATCH 06/15] target/ppc/kvm: Add - cap_ppc_safe_[cache/bounds_check/indirect_branch] - -RH-Author: Suraj Jitindar Singh -Message-id: <1518495150-24134-3-git-send-email-sursingh@redhat.com> -Patchwork-id: 78984 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 2/9] target/ppc/kvm: Add cap_ppc_safe_[cache/bounds_check/indirect_branch] -Bugzilla: 1532050 -RH-Acked-by: David Gibson -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth - -From: Suraj Jitindar Singh - -Add three new kvm capabilities used to represent the level of host support -for three corresponding workarounds. - -Host support for each of the capabilities is queried through the -new ioctl KVM_PPC_GET_CPU_CHAR which returns four uint64 quantities. The -first two, character and behaviour, represent the available -characteristics of the cpu and the behaviour of the cpu respectively. -The second two, c_mask and b_mask, represent the mask of known bits for -the character and beheviour dwords respectively. - -Signed-off-by: Suraj Jitindar Singh -Reviewed-by: David Gibson -[dwg: Correct some compile errors due to name change in final kernel - patch version] -Signed-off-by: David Gibson - -(cherry picked from commit 8acc2ae5e91681ceda3ff4cf946ebf163f6012e9) -Signed-off-by: Miroslav Rezanina - -Conflicts: - target/ppc/kvm.c - -Minor massage required due to lack of commit downstream: -2e9c10eb (ppc: spapr: use generic cpu_model parsing) - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1532050 - -Signed-off-by: Suraj Jitindar Singh ---- - include/hw/ppc/spapr.h | 12 +++++++++++ - target/ppc/kvm.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ - target/ppc/kvm_ppc.h | 18 ++++++++++++++++ - 3 files changed, 88 insertions(+) - -diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h -index 7156a70..6090f3d 100644 ---- a/include/hw/ppc/spapr.h -+++ b/include/hw/ppc/spapr.h -@@ -297,6 +297,18 @@ struct sPAPRMachineState { - #define H_DABRX_KERNEL (1ULL<<(63-62)) - #define H_DABRX_USER (1ULL<<(63-63)) - -+/* Values for KVM_PPC_GET_CPU_CHAR & H_GET_CPU_CHARACTERISTICS */ -+#define H_CPU_CHAR_SPEC_BAR_ORI31 PPC_BIT(0) -+#define H_CPU_CHAR_BCCTRL_SERIALISED PPC_BIT(1) -+#define H_CPU_CHAR_L1D_FLUSH_ORI30 PPC_BIT(2) -+#define H_CPU_CHAR_L1D_FLUSH_TRIG2 PPC_BIT(3) -+#define H_CPU_CHAR_L1D_THREAD_PRIV PPC_BIT(4) -+#define H_CPU_CHAR_HON_BRANCH_HINTS PPC_BIT(5) -+#define H_CPU_CHAR_THR_RECONF_TRIG PPC_BIT(6) -+#define H_CPU_BEHAV_FAVOUR_SECURITY PPC_BIT(0) -+#define H_CPU_BEHAV_L1D_FLUSH_PR PPC_BIT(1) -+#define H_CPU_BEHAV_BNDS_CHK_SPEC_BAR PPC_BIT(2) -+ - /* Each control block has to be on a 4K boundary */ - #define H_CB_ALIGNMENT 4096 - -diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c -index ce7e2ec..7a7bc3b 100644 ---- a/target/ppc/kvm.c -+++ b/target/ppc/kvm.c -@@ -92,6 +92,9 @@ static int cap_mmu_radix; - static int cap_mmu_hash_v3; - static int cap_resize_hpt; - static int cap_ppc_pvr_compat; -+static int cap_ppc_safe_cache; -+static int cap_ppc_safe_bounds_check; -+static int cap_ppc_safe_indirect_branch; - - static uint32_t debug_inst_opcode; - -@@ -124,6 +127,7 @@ static bool kvmppc_is_pr(KVMState *ks) - } - - static int kvm_ppc_register_host_cpu_type(void); -+static void kvmppc_get_cpu_characteristics(KVMState *s); - - int kvm_arch_init(MachineState *ms, KVMState *s) - { -@@ -150,6 +154,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) - cap_mmu_radix = kvm_vm_check_extension(s, KVM_CAP_PPC_MMU_RADIX); - cap_mmu_hash_v3 = kvm_vm_check_extension(s, KVM_CAP_PPC_MMU_HASH_V3); - cap_resize_hpt = kvm_vm_check_extension(s, KVM_CAP_SPAPR_RESIZE_HPT); -+ kvmppc_get_cpu_characteristics(s); - /* - * Note: setting it to false because there is not such capability - * in KVM at this moment. -@@ -2473,6 +2478,59 @@ bool kvmppc_has_cap_mmu_hash_v3(void) - return cap_mmu_hash_v3; - } - -+static void kvmppc_get_cpu_characteristics(KVMState *s) -+{ -+ struct kvm_ppc_cpu_char c; -+ int ret; -+ -+ /* Assume broken */ -+ cap_ppc_safe_cache = 0; -+ cap_ppc_safe_bounds_check = 0; -+ cap_ppc_safe_indirect_branch = 0; -+ -+ ret = kvm_vm_check_extension(s, KVM_CAP_PPC_GET_CPU_CHAR); -+ if (!ret) { -+ return; -+ } -+ ret = kvm_vm_ioctl(s, KVM_PPC_GET_CPU_CHAR, &c); -+ if (ret < 0) { -+ return; -+ } -+ /* Parse and set cap_ppc_safe_cache */ -+ if (~c.behaviour & c.behaviour_mask & H_CPU_BEHAV_L1D_FLUSH_PR) { -+ cap_ppc_safe_cache = 2; -+ } else if ((c.character & c.character_mask & H_CPU_CHAR_L1D_THREAD_PRIV) && -+ (c.character & c.character_mask -+ & (H_CPU_CHAR_L1D_FLUSH_ORI30 | H_CPU_CHAR_L1D_FLUSH_TRIG2))) { -+ cap_ppc_safe_cache = 1; -+ } -+ /* Parse and set cap_ppc_safe_bounds_check */ -+ if (~c.behaviour & c.behaviour_mask & H_CPU_BEHAV_BNDS_CHK_SPEC_BAR) { -+ cap_ppc_safe_bounds_check = 2; -+ } else if (c.character & c.character_mask & H_CPU_CHAR_SPEC_BAR_ORI31) { -+ cap_ppc_safe_bounds_check = 1; -+ } -+ /* Parse and set cap_ppc_safe_indirect_branch */ -+ if (c.character & H_CPU_CHAR_BCCTRL_SERIALISED) { -+ cap_ppc_safe_indirect_branch = 2; -+ } -+} -+ -+int kvmppc_get_cap_safe_cache(void) -+{ -+ return cap_ppc_safe_cache; -+} -+ -+int kvmppc_get_cap_safe_bounds_check(void) -+{ -+ return cap_ppc_safe_bounds_check; -+} -+ -+int kvmppc_get_cap_safe_indirect_branch(void) -+{ -+ return cap_ppc_safe_indirect_branch; -+} -+ - PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void) - { - uint32_t host_pvr = mfpvr(); -diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h -index e6711fc..9da92a9 100644 ---- a/target/ppc/kvm_ppc.h -+++ b/target/ppc/kvm_ppc.h -@@ -62,6 +62,9 @@ bool kvmppc_has_cap_fixup_hcalls(void); - bool kvmppc_has_cap_htm(void); - bool kvmppc_has_cap_mmu_radix(void); - bool kvmppc_has_cap_mmu_hash_v3(void); -+int kvmppc_get_cap_safe_cache(void); -+int kvmppc_get_cap_safe_bounds_check(void); -+int kvmppc_get_cap_safe_indirect_branch(void); - int kvmppc_enable_hwrng(void); - int kvmppc_put_books_sregs(PowerPCCPU *cpu); - PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void); -@@ -299,6 +302,21 @@ static inline bool kvmppc_has_cap_mmu_hash_v3(void) - return false; - } - -+static inline int kvmppc_get_cap_safe_cache(void) -+{ -+ return 0; -+} -+ -+static inline int kvmppc_get_cap_safe_bounds_check(void) -+{ -+ return 0; -+} -+ -+static inline int kvmppc_get_cap_safe_indirect_branch(void) -+{ -+ return 0; -+} -+ - static inline int kvmppc_enable_hwrng(void) - { - return -1; --- -1.8.3.1 - diff --git a/SOURCES/kvm-target-ppc-spapr-Add-H-Call-H_GET_CPU_CHARACTERISTIC.patch b/SOURCES/kvm-target-ppc-spapr-Add-H-Call-H_GET_CPU_CHARACTERISTIC.patch deleted file mode 100644 index 3323c48..0000000 --- a/SOURCES/kvm-target-ppc-spapr-Add-H-Call-H_GET_CPU_CHARACTERISTIC.patch +++ /dev/null @@ -1,128 +0,0 @@ -From d47dcee27b473fd94b4afdb21433d735ff9e51cd Mon Sep 17 00:00:00 2001 -From: Suraj Jitindar Singh -Date: Tue, 13 Feb 2018 04:12:29 +0100 -Subject: [PATCH 12/15] target/ppc/spapr: Add H-Call H_GET_CPU_CHARACTERISTICS - -RH-Author: Suraj Jitindar Singh -Message-id: <1518495150-24134-9-git-send-email-sursingh@redhat.com> -Patchwork-id: 78986 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 8/9] target/ppc/spapr: Add H-Call H_GET_CPU_CHARACTERISTICS -Bugzilla: 1532050 -RH-Acked-by: David Gibson -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth - -From: Suraj Jitindar Singh - -The new H-Call H_GET_CPU_CHARACTERISTICS is used by the guest to query -behaviours and available characteristics of the cpu. - -Implement the handler for this new H-Call which formulates its response -based on the setting of the spapr_caps cap-cfpc, cap-sbbc and cap-ibs. - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: David Gibson -(cherry picked from commit c59704b254734182c3202e0c261589ea2ccf485e) - -Conflicts: none - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1532050 - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr_hcall.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ - include/hw/ppc/spapr.h | 1 + - 2 files changed, 59 insertions(+) - -diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c -index 217358d..21247cd 100644 ---- a/hw/ppc/spapr_hcall.c -+++ b/hw/ppc/spapr_hcall.c -@@ -1629,6 +1629,60 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, - return H_SUCCESS; - } - -+static target_ulong h_get_cpu_characteristics(PowerPCCPU *cpu, -+ sPAPRMachineState *spapr, -+ target_ulong opcode, -+ target_ulong *args) -+{ -+ uint64_t characteristics = H_CPU_CHAR_HON_BRANCH_HINTS & -+ ~H_CPU_CHAR_THR_RECONF_TRIG; -+ uint64_t behaviour = H_CPU_BEHAV_FAVOUR_SECURITY; -+ uint8_t safe_cache = spapr_get_cap(spapr, SPAPR_CAP_CFPC); -+ uint8_t safe_bounds_check = spapr_get_cap(spapr, SPAPR_CAP_SBBC); -+ uint8_t safe_indirect_branch = spapr_get_cap(spapr, SPAPR_CAP_IBS); -+ -+ switch (safe_cache) { -+ case SPAPR_CAP_WORKAROUND: -+ characteristics |= H_CPU_CHAR_L1D_FLUSH_ORI30; -+ characteristics |= H_CPU_CHAR_L1D_FLUSH_TRIG2; -+ characteristics |= H_CPU_CHAR_L1D_THREAD_PRIV; -+ behaviour |= H_CPU_BEHAV_L1D_FLUSH_PR; -+ break; -+ case SPAPR_CAP_FIXED: -+ break; -+ default: /* broken */ -+ assert(safe_cache == SPAPR_CAP_BROKEN); -+ behaviour |= H_CPU_BEHAV_L1D_FLUSH_PR; -+ break; -+ } -+ -+ switch (safe_bounds_check) { -+ case SPAPR_CAP_WORKAROUND: -+ characteristics |= H_CPU_CHAR_SPEC_BAR_ORI31; -+ behaviour |= H_CPU_BEHAV_BNDS_CHK_SPEC_BAR; -+ break; -+ case SPAPR_CAP_FIXED: -+ break; -+ default: /* broken */ -+ assert(safe_bounds_check == SPAPR_CAP_BROKEN); -+ behaviour |= H_CPU_BEHAV_BNDS_CHK_SPEC_BAR; -+ break; -+ } -+ -+ switch (safe_indirect_branch) { -+ case SPAPR_CAP_FIXED: -+ characteristics |= H_CPU_CHAR_BCCTRL_SERIALISED; -+ default: /* broken */ -+ assert(safe_indirect_branch == SPAPR_CAP_BROKEN); -+ break; -+ } -+ -+ args[0] = characteristics; -+ args[1] = behaviour; -+ -+ return H_SUCCESS; -+} -+ - static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1]; - static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1]; - -@@ -1708,6 +1762,10 @@ static void hypercall_register_types(void) - spapr_register_hypercall(H_INVALIDATE_PID, h_invalidate_pid); - spapr_register_hypercall(H_REGISTER_PROC_TBL, h_register_process_table); - -+ /* hcall-get-cpu-characteristics */ -+ spapr_register_hypercall(H_GET_CPU_CHARACTERISTICS, -+ h_get_cpu_characteristics); -+ - /* "debugger" hcalls (also used by SLOF). Note: We do -not- differenciate - * here between the "CI" and the "CACHE" variants, they will use whatever - * mapping attributes qemu is using. When using KVM, the kernel will -diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h -index f7f01f3..375b2ba 100644 ---- a/include/hw/ppc/spapr.h -+++ b/include/hw/ppc/spapr.h -@@ -406,6 +406,7 @@ struct sPAPRMachineState { - #define H_GET_HCA_INFO 0x1B8 - #define H_GET_PERF_COUNT 0x1BC - #define H_MANAGE_TRACE 0x1C0 -+#define H_GET_CPU_CHARACTERISTICS 0x1C8 - #define H_FREE_LOGICAL_LAN_BUFFER 0x1D4 - #define H_QUERY_INT_STATE 0x1E4 - #define H_POLL_PENDING 0x1D8 --- -1.8.3.1 - diff --git a/SOURCES/kvm-target-ppc-spapr_caps-Add-macro-to-generate-spapr_ca.patch b/SOURCES/kvm-target-ppc-spapr_caps-Add-macro-to-generate-spapr_ca.patch deleted file mode 100644 index 6a24397..0000000 --- a/SOURCES/kvm-target-ppc-spapr_caps-Add-macro-to-generate-spapr_ca.patch +++ /dev/null @@ -1,133 +0,0 @@ -From 1f48270b951f370528fc7f9e6e76b25ed422ac77 Mon Sep 17 00:00:00 2001 -From: Suraj Jitindar Singh -Date: Tue, 13 Feb 2018 04:12:22 +0100 -Subject: [PATCH 05/15] target/ppc/spapr_caps: Add macro to generate spapr_caps - migration vmstate - -RH-Author: Suraj Jitindar Singh -Message-id: <1518495150-24134-2-git-send-email-sursingh@redhat.com> -Patchwork-id: 78983 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 1/9] target/ppc/spapr_caps: Add macro to generate spapr_caps migration vmstate -Bugzilla: 1532050 -RH-Acked-by: David Gibson -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth - -From: Suraj Jitindar Singh - -The vmstate description and the contained needed function for migration -of spapr_caps is the same for each cap, with the name of the cap -substituted. As such introduce a macro to allow for easier generation of -these. - -Convert the three existing spapr_caps (htm, vsx, and dfp) to use this -macro. - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: David Gibson -(cherry picked from commit 1f63ebaa91f73f469c8f107dbd266cabdbea3a40) - -Conflicts: None - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1532050 - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr_caps.c | 78 +++++++++++++++++------------------------------------ - 1 file changed, 24 insertions(+), 54 deletions(-) - -diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c -index d5c9ce7..5d52969 100644 ---- a/hw/ppc/spapr_caps.c -+++ b/hw/ppc/spapr_caps.c -@@ -228,62 +228,32 @@ int spapr_caps_post_migration(sPAPRMachineState *spapr) - return ok ? 0 : -EINVAL; - } - --static bool spapr_cap_htm_needed(void *opaque) --{ -- sPAPRMachineState *spapr = opaque; -- -- return spapr->cmd_line_caps[SPAPR_CAP_HTM] && -- (spapr->eff.caps[SPAPR_CAP_HTM] != spapr->def.caps[SPAPR_CAP_HTM]); --} -- --const VMStateDescription vmstate_spapr_cap_htm = { -- .name = "spapr/cap/htm", -- .version_id = 1, -- .minimum_version_id = 1, -- .needed = spapr_cap_htm_needed, -- .fields = (VMStateField[]) { -- VMSTATE_UINT8(mig.caps[SPAPR_CAP_HTM], sPAPRMachineState), -- VMSTATE_END_OF_LIST() -- }, --}; -- --static bool spapr_cap_vsx_needed(void *opaque) --{ -- sPAPRMachineState *spapr = opaque; -- -- return spapr->cmd_line_caps[SPAPR_CAP_VSX] && -- (spapr->eff.caps[SPAPR_CAP_VSX] != spapr->def.caps[SPAPR_CAP_VSX]); -+/* Used to generate the migration field and needed function for a spapr cap */ -+#define SPAPR_CAP_MIG_STATE(cap, ccap) \ -+static bool spapr_cap_##cap##_needed(void *opaque) \ -+{ \ -+ sPAPRMachineState *spapr = opaque; \ -+ \ -+ return spapr->cmd_line_caps[SPAPR_CAP_##ccap] && \ -+ (spapr->eff.caps[SPAPR_CAP_##ccap] != \ -+ spapr->def.caps[SPAPR_CAP_##ccap]); \ -+} \ -+ \ -+const VMStateDescription vmstate_spapr_cap_##cap = { \ -+ .name = "spapr/cap/" #cap, \ -+ .version_id = 1, \ -+ .minimum_version_id = 1, \ -+ .needed = spapr_cap_##cap##_needed, \ -+ .fields = (VMStateField[]) { \ -+ VMSTATE_UINT8(mig.caps[SPAPR_CAP_##ccap], \ -+ sPAPRMachineState), \ -+ VMSTATE_END_OF_LIST() \ -+ }, \ - } - --const VMStateDescription vmstate_spapr_cap_vsx = { -- .name = "spapr/cap/vsx", -- .version_id = 1, -- .minimum_version_id = 1, -- .needed = spapr_cap_vsx_needed, -- .fields = (VMStateField[]) { -- VMSTATE_UINT8(mig.caps[SPAPR_CAP_VSX], sPAPRMachineState), -- VMSTATE_END_OF_LIST() -- }, --}; -- --static bool spapr_cap_dfp_needed(void *opaque) --{ -- sPAPRMachineState *spapr = opaque; -- -- return spapr->cmd_line_caps[SPAPR_CAP_DFP] && -- (spapr->eff.caps[SPAPR_CAP_DFP] != spapr->def.caps[SPAPR_CAP_DFP]); --} -- --const VMStateDescription vmstate_spapr_cap_dfp = { -- .name = "spapr/cap/dfp", -- .version_id = 1, -- .minimum_version_id = 1, -- .needed = spapr_cap_dfp_needed, -- .fields = (VMStateField[]) { -- VMSTATE_UINT8(mig.caps[SPAPR_CAP_DFP], sPAPRMachineState), -- VMSTATE_END_OF_LIST() -- }, --}; -+SPAPR_CAP_MIG_STATE(htm, HTM); -+SPAPR_CAP_MIG_STATE(vsx, VSX); -+SPAPR_CAP_MIG_STATE(dfp, DFP); - - void spapr_caps_reset(sPAPRMachineState *spapr) - { --- -1.8.3.1 - diff --git a/SOURCES/kvm-target-ppc-spapr_caps-Add-new-tristate-cap-safe_boun.patch b/SOURCES/kvm-target-ppc-spapr_caps-Add-new-tristate-cap-safe_boun.patch deleted file mode 100644 index e881dbe..0000000 --- a/SOURCES/kvm-target-ppc-spapr_caps-Add-new-tristate-cap-safe_boun.patch +++ /dev/null @@ -1,130 +0,0 @@ -From 410393e052e3e3e26e3d7fc5b9f806c182f10508 Mon Sep 17 00:00:00 2001 -From: Suraj Jitindar Singh -Date: Tue, 13 Feb 2018 04:12:26 +0100 -Subject: [PATCH 09/15] target/ppc/spapr_caps: Add new tristate cap - safe_bounds_check - -RH-Author: Suraj Jitindar Singh -Message-id: <1518495150-24134-6-git-send-email-sursingh@redhat.com> -Patchwork-id: 78982 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 5/9] target/ppc/spapr_caps: Add new tristate cap safe_bounds_check -Bugzilla: 1532050 -RH-Acked-by: David Gibson -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth - -From: Suraj Jitindar Singh - -Add new tristate cap cap-sbbc to represent the speculation barrier -bounds checking capability. - -Signed-off-by: Suraj Jitindar Singh -Reviewed-by: David Gibson -Signed-off-by: David Gibson -(cherry picked from commit 09114fd8179977e4157b36aab2e3d68eaf08adca) - -Conflicts: none - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1532050 - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr.c | 2 ++ - hw/ppc/spapr_caps.c | 21 +++++++++++++++++++++ - include/hw/ppc/spapr.h | 5 ++++- - 3 files changed, 27 insertions(+), 1 deletion(-) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 31a5460..2dae180 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -1743,6 +1743,7 @@ static const VMStateDescription vmstate_spapr = { - &vmstate_spapr_cap_vsx, - &vmstate_spapr_cap_dfp, - &vmstate_spapr_cap_cfpc, -+ &vmstate_spapr_cap_sbbc, - NULL - } - }; -@@ -3699,6 +3700,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) - smc->default_caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_ON; - smc->default_caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_ON; - smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN; -+ smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN; - spapr_caps_add_properties(smc, &error_abort); - } - -diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c -index d53da63..ce1f74f 100644 ---- a/hw/ppc/spapr_caps.c -+++ b/hw/ppc/spapr_caps.c -@@ -191,6 +191,17 @@ static void cap_safe_cache_apply(sPAPRMachineState *spapr, uint8_t val, - } - } - -+static void cap_safe_bounds_check_apply(sPAPRMachineState *spapr, uint8_t val, -+ Error **errp) -+{ -+ if (tcg_enabled() && val) { -+ /* TODO - for now only allow broken for TCG */ -+ error_setg(errp, "Requested safe bounds check capability level not supported by tcg, try a different value for cap-sbbc"); -+ } else if (kvm_enabled() && (val > kvmppc_get_cap_safe_bounds_check())) { -+ error_setg(errp, "Requested safe bounds check capability level not supported by kvm, try a different value for cap-sbbc"); -+ } -+} -+ - #define VALUE_DESC_TRISTATE " (broken, workaround, fixed)" - - sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = { -@@ -230,6 +241,15 @@ sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = { - .type = "string", - .apply = cap_safe_cache_apply, - }, -+ [SPAPR_CAP_SBBC] = { -+ .name = "sbbc", -+ .description = "Speculation Barrier Bounds Checking" VALUE_DESC_TRISTATE, -+ .index = SPAPR_CAP_SBBC, -+ .get = spapr_cap_get_tristate, -+ .set = spapr_cap_set_tristate, -+ .type = "string", -+ .apply = cap_safe_bounds_check_apply, -+ }, - }; - - static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr, -@@ -336,6 +356,7 @@ SPAPR_CAP_MIG_STATE(htm, HTM); - SPAPR_CAP_MIG_STATE(vsx, VSX); - SPAPR_CAP_MIG_STATE(dfp, DFP); - SPAPR_CAP_MIG_STATE(cfpc, CFPC); -+SPAPR_CAP_MIG_STATE(sbbc, SBBC); - - void spapr_caps_reset(sPAPRMachineState *spapr) - { -diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h -index 442b35b..38a8e72 100644 ---- a/include/hw/ppc/spapr.h -+++ b/include/hw/ppc/spapr.h -@@ -62,8 +62,10 @@ typedef enum { - #define SPAPR_CAP_DFP 0x02 - /* Cache Flush on Privilege Change */ - #define SPAPR_CAP_CFPC 0x03 -+/* Speculation Barrier Bounds Checking */ -+#define SPAPR_CAP_SBBC 0x04 - /* Num Caps */ --#define SPAPR_CAP_NUM (SPAPR_CAP_CFPC + 1) -+#define SPAPR_CAP_NUM (SPAPR_CAP_SBBC + 1) - - /* - * Capability Values -@@ -765,6 +767,7 @@ extern const VMStateDescription vmstate_spapr_cap_htm; - extern const VMStateDescription vmstate_spapr_cap_vsx; - extern const VMStateDescription vmstate_spapr_cap_dfp; - extern const VMStateDescription vmstate_spapr_cap_cfpc; -+extern const VMStateDescription vmstate_spapr_cap_sbbc; - - static inline uint8_t spapr_get_cap(sPAPRMachineState *spapr, int cap) - { --- -1.8.3.1 - diff --git a/SOURCES/kvm-target-ppc-spapr_caps-Add-new-tristate-cap-safe_cach.patch b/SOURCES/kvm-target-ppc-spapr_caps-Add-new-tristate-cap-safe_cach.patch deleted file mode 100644 index e8deabf..0000000 --- a/SOURCES/kvm-target-ppc-spapr_caps-Add-new-tristate-cap-safe_cach.patch +++ /dev/null @@ -1,158 +0,0 @@ -From bbf51e75c92f870d0637cbb3025fc3f4da9d40f2 Mon Sep 17 00:00:00 2001 -From: Suraj Jitindar Singh -Date: Tue, 13 Feb 2018 04:12:25 +0100 -Subject: [PATCH 08/15] target/ppc/spapr_caps: Add new tristate cap safe_cache - -RH-Author: Suraj Jitindar Singh -Message-id: <1518495150-24134-5-git-send-email-sursingh@redhat.com> -Patchwork-id: 78987 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 4/9] target/ppc/spapr_caps: Add new tristate cap safe_cache -Bugzilla: 1532050 -RH-Acked-by: David Gibson -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth - -From: Suraj Jitindar Singh - -Add new tristate cap cap-cfpc to represent the cache flush on privilege -change capability. - -Signed-off-by: Suraj Jitindar Singh -Reviewed-by: David Gibson -Signed-off-by: David Gibson -(cherry picked from commit 8f38eaf8f9dd194c9961cf76c675724930ce4570) - -Conflicts: none - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1532050 - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr.c | 2 ++ - hw/ppc/spapr_caps.c | 36 ++++++++++++++++++++++++++---------- - include/hw/ppc/spapr.h | 5 ++++- - 3 files changed, 32 insertions(+), 11 deletions(-) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 2b991d8..31a5460 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -1742,6 +1742,7 @@ static const VMStateDescription vmstate_spapr = { - &vmstate_spapr_cap_htm, - &vmstate_spapr_cap_vsx, - &vmstate_spapr_cap_dfp, -+ &vmstate_spapr_cap_cfpc, - NULL - } - }; -@@ -3697,6 +3698,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) - smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF; - smc->default_caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_ON; - smc->default_caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_ON; -+ smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN; - spapr_caps_add_properties(smc, &error_abort); - } - -diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c -index d6f82b1..d53da63 100644 ---- a/hw/ppc/spapr_caps.c -+++ b/hw/ppc/spapr_caps.c -@@ -73,11 +73,8 @@ static void spapr_cap_set_bool(Object *obj, Visitor *v, const char *name, - spapr->eff.caps[cap->index] = value ? SPAPR_CAP_ON : SPAPR_CAP_OFF; - } - --static void __attribute__ ((unused)) spapr_cap_get_tristate(Object *obj, -- Visitor *v, -- const char *name, -- void *opaque, -- Error **errp) -+static void spapr_cap_get_tristate(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) - { - sPAPRCapabilityInfo *cap = opaque; - sPAPRMachineState *spapr = SPAPR_MACHINE(obj); -@@ -103,11 +100,8 @@ static void __attribute__ ((unused)) spapr_cap_get_tristate(Object *obj, - g_free(val); - } - --static void __attribute__ ((unused)) spapr_cap_set_tristate(Object *obj, -- Visitor *v, -- const char *name, -- void *opaque, -- Error **errp) -+static void spapr_cap_set_tristate(Object *obj, Visitor *v, const char *name, -+ void *opaque, Error **errp) - { - sPAPRCapabilityInfo *cap = opaque; - sPAPRMachineState *spapr = SPAPR_MACHINE(obj); -@@ -186,6 +180,18 @@ static void cap_dfp_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp) - } - } - -+static void cap_safe_cache_apply(sPAPRMachineState *spapr, uint8_t val, -+ Error **errp) -+{ -+ if (tcg_enabled() && val) { -+ /* TODO - for now only allow broken for TCG */ -+ error_setg(errp, "Requested safe cache capability level not supported by tcg, try a different value for cap-cfpc"); -+ } else if (kvm_enabled() && (val > kvmppc_get_cap_safe_cache())) { -+ error_setg(errp, "Requested safe cache capability level not supported by kvm, try a different value for cap-cfpc"); -+ } -+} -+ -+#define VALUE_DESC_TRISTATE " (broken, workaround, fixed)" - - sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = { - [SPAPR_CAP_HTM] = { -@@ -215,6 +221,15 @@ sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = { - .type = "bool", - .apply = cap_dfp_apply, - }, -+ [SPAPR_CAP_CFPC] = { -+ .name = "cfpc", -+ .description = "Cache Flush on Privilege Change" VALUE_DESC_TRISTATE, -+ .index = SPAPR_CAP_CFPC, -+ .get = spapr_cap_get_tristate, -+ .set = spapr_cap_set_tristate, -+ .type = "string", -+ .apply = cap_safe_cache_apply, -+ }, - }; - - static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr, -@@ -320,6 +335,7 @@ const VMStateDescription vmstate_spapr_cap_##cap = { \ - SPAPR_CAP_MIG_STATE(htm, HTM); - SPAPR_CAP_MIG_STATE(vsx, VSX); - SPAPR_CAP_MIG_STATE(dfp, DFP); -+SPAPR_CAP_MIG_STATE(cfpc, CFPC); - - void spapr_caps_reset(sPAPRMachineState *spapr) - { -diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h -index abe0011..442b35b 100644 ---- a/include/hw/ppc/spapr.h -+++ b/include/hw/ppc/spapr.h -@@ -60,8 +60,10 @@ typedef enum { - #define SPAPR_CAP_VSX 0x01 - /* Decimal Floating Point */ - #define SPAPR_CAP_DFP 0x02 -+/* Cache Flush on Privilege Change */ -+#define SPAPR_CAP_CFPC 0x03 - /* Num Caps */ --#define SPAPR_CAP_NUM (SPAPR_CAP_DFP + 1) -+#define SPAPR_CAP_NUM (SPAPR_CAP_CFPC + 1) - - /* - * Capability Values -@@ -762,6 +764,7 @@ int spapr_caps_pre_save(void *opaque); - extern const VMStateDescription vmstate_spapr_cap_htm; - extern const VMStateDescription vmstate_spapr_cap_vsx; - extern const VMStateDescription vmstate_spapr_cap_dfp; -+extern const VMStateDescription vmstate_spapr_cap_cfpc; - - static inline uint8_t spapr_get_cap(sPAPRMachineState *spapr, int cap) - { --- -1.8.3.1 - diff --git a/SOURCES/kvm-target-ppc-spapr_caps-Add-new-tristate-cap-safe_indi.patch b/SOURCES/kvm-target-ppc-spapr_caps-Add-new-tristate-cap-safe_indi.patch deleted file mode 100644 index 298e1d5..0000000 --- a/SOURCES/kvm-target-ppc-spapr_caps-Add-new-tristate-cap-safe_indi.patch +++ /dev/null @@ -1,130 +0,0 @@ -From 29fa2de37ac3bbd6087d7350d1923fb8143bd365 Mon Sep 17 00:00:00 2001 -From: Suraj Jitindar Singh -Date: Tue, 13 Feb 2018 04:12:27 +0100 -Subject: [PATCH 10/15] target/ppc/spapr_caps: Add new tristate cap - safe_indirect_branch - -RH-Author: Suraj Jitindar Singh -Message-id: <1518495150-24134-7-git-send-email-sursingh@redhat.com> -Patchwork-id: 78990 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 6/9] target/ppc/spapr_caps: Add new tristate cap safe_indirect_branch -Bugzilla: 1532050 -RH-Acked-by: David Gibson -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth - -From: Suraj Jitindar Singh - -Add new tristate cap cap-ibs to represent the indirect branch -serialisation capability. - -Signed-off-by: Suraj Jitindar Singh -Reviewed-by: David Gibson -Signed-off-by: David Gibson -(cherry picked from commit 4be8d4e7d935fc8919d61f53a0f0fb7230052bb3) - -Conflicts: none - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1532050 - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr.c | 2 ++ - hw/ppc/spapr_caps.c | 21 +++++++++++++++++++++ - include/hw/ppc/spapr.h | 5 ++++- - 3 files changed, 27 insertions(+), 1 deletion(-) - -diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c -index 2dae180..c71ffac 100644 ---- a/hw/ppc/spapr.c -+++ b/hw/ppc/spapr.c -@@ -1744,6 +1744,7 @@ static const VMStateDescription vmstate_spapr = { - &vmstate_spapr_cap_dfp, - &vmstate_spapr_cap_cfpc, - &vmstate_spapr_cap_sbbc, -+ &vmstate_spapr_cap_ibs, - NULL - } - }; -@@ -3701,6 +3702,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) - smc->default_caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_ON; - smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN; - smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN; -+ smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN; - spapr_caps_add_properties(smc, &error_abort); - } - -diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c -index ce1f74f..62efdae 100644 ---- a/hw/ppc/spapr_caps.c -+++ b/hw/ppc/spapr_caps.c -@@ -202,6 +202,17 @@ static void cap_safe_bounds_check_apply(sPAPRMachineState *spapr, uint8_t val, - } - } - -+static void cap_safe_indirect_branch_apply(sPAPRMachineState *spapr, -+ uint8_t val, Error **errp) -+{ -+ if (tcg_enabled() && val) { -+ /* TODO - for now only allow broken for TCG */ -+ error_setg(errp, "Requested safe indirect branch capability level not supported by tcg, try a different value for cap-ibs"); -+ } else if (kvm_enabled() && (val > kvmppc_get_cap_safe_indirect_branch())) { -+ error_setg(errp, "Requested safe indirect branch capability level not supported by kvm, try a different value for cap-ibs"); -+ } -+} -+ - #define VALUE_DESC_TRISTATE " (broken, workaround, fixed)" - - sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = { -@@ -250,6 +261,15 @@ sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = { - .type = "string", - .apply = cap_safe_bounds_check_apply, - }, -+ [SPAPR_CAP_IBS] = { -+ .name = "ibs", -+ .description = "Indirect Branch Serialisation" VALUE_DESC_TRISTATE, -+ .index = SPAPR_CAP_IBS, -+ .get = spapr_cap_get_tristate, -+ .set = spapr_cap_set_tristate, -+ .type = "string", -+ .apply = cap_safe_indirect_branch_apply, -+ }, - }; - - static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr, -@@ -357,6 +377,7 @@ SPAPR_CAP_MIG_STATE(vsx, VSX); - SPAPR_CAP_MIG_STATE(dfp, DFP); - SPAPR_CAP_MIG_STATE(cfpc, CFPC); - SPAPR_CAP_MIG_STATE(sbbc, SBBC); -+SPAPR_CAP_MIG_STATE(ibs, IBS); - - void spapr_caps_reset(sPAPRMachineState *spapr) - { -diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h -index 38a8e72..f7f01f3 100644 ---- a/include/hw/ppc/spapr.h -+++ b/include/hw/ppc/spapr.h -@@ -64,8 +64,10 @@ typedef enum { - #define SPAPR_CAP_CFPC 0x03 - /* Speculation Barrier Bounds Checking */ - #define SPAPR_CAP_SBBC 0x04 -+/* Indirect Branch Serialisation */ -+#define SPAPR_CAP_IBS 0x05 - /* Num Caps */ --#define SPAPR_CAP_NUM (SPAPR_CAP_SBBC + 1) -+#define SPAPR_CAP_NUM (SPAPR_CAP_IBS + 1) - - /* - * Capability Values -@@ -768,6 +770,7 @@ extern const VMStateDescription vmstate_spapr_cap_vsx; - extern const VMStateDescription vmstate_spapr_cap_dfp; - extern const VMStateDescription vmstate_spapr_cap_cfpc; - extern const VMStateDescription vmstate_spapr_cap_sbbc; -+extern const VMStateDescription vmstate_spapr_cap_ibs; - - static inline uint8_t spapr_get_cap(sPAPRMachineState *spapr, int cap) - { --- -1.8.3.1 - diff --git a/SOURCES/kvm-target-ppc-spapr_caps-Add-support-for-tristate-spapr.patch b/SOURCES/kvm-target-ppc-spapr_caps-Add-support-for-tristate-spapr.patch deleted file mode 100644 index c3259d0..0000000 --- a/SOURCES/kvm-target-ppc-spapr_caps-Add-support-for-tristate-spapr.patch +++ /dev/null @@ -1,135 +0,0 @@ -From ea039b07c94712a8ffb92b0a6e515f7c354d2219 Mon Sep 17 00:00:00 2001 -From: Suraj Jitindar Singh -Date: Tue, 13 Feb 2018 04:12:24 +0100 -Subject: [PATCH 07/15] target/ppc/spapr_caps: Add support for tristate - spapr_capabilities - -RH-Author: Suraj Jitindar Singh -Message-id: <1518495150-24134-4-git-send-email-sursingh@redhat.com> -Patchwork-id: 78991 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH 3/9] target/ppc/spapr_caps: Add support for tristate spapr_capabilities -Bugzilla: 1532050 -RH-Acked-by: David Gibson -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth - -From: Suraj Jitindar Singh - -spapr_caps are used to represent the level of support for various -capabilities related to the spapr machine type. Currently there is -only support for boolean capabilities. - -Add support for tristate capabilities by implementing their get/set -functions. These capabilities can have the values 0, 1 or 2 -corresponding to broken, workaround and fixed. - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: David Gibson -(cherry picked from commit 6898aed77f4636c3e77af9c12631f583f22cb5db) - -Conflicts: none - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1532050 - -Signed-off-by: Suraj Jitindar Singh -Signed-off-by: Miroslav Rezanina ---- - hw/ppc/spapr_caps.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++ - include/hw/ppc/spapr.h | 4 +++ - 2 files changed, 70 insertions(+) - -diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c -index 5d52969..d6f82b1 100644 ---- a/hw/ppc/spapr_caps.c -+++ b/hw/ppc/spapr_caps.c -@@ -73,6 +73,72 @@ static void spapr_cap_set_bool(Object *obj, Visitor *v, const char *name, - spapr->eff.caps[cap->index] = value ? SPAPR_CAP_ON : SPAPR_CAP_OFF; - } - -+static void __attribute__ ((unused)) spapr_cap_get_tristate(Object *obj, -+ Visitor *v, -+ const char *name, -+ void *opaque, -+ Error **errp) -+{ -+ sPAPRCapabilityInfo *cap = opaque; -+ sPAPRMachineState *spapr = SPAPR_MACHINE(obj); -+ char *val = NULL; -+ uint8_t value = spapr_get_cap(spapr, cap->index); -+ -+ switch (value) { -+ case SPAPR_CAP_BROKEN: -+ val = g_strdup("broken"); -+ break; -+ case SPAPR_CAP_WORKAROUND: -+ val = g_strdup("workaround"); -+ break; -+ case SPAPR_CAP_FIXED: -+ val = g_strdup("fixed"); -+ break; -+ default: -+ error_setg(errp, "Invalid value (%d) for cap-%s", value, cap->name); -+ return; -+ } -+ -+ visit_type_str(v, name, &val, errp); -+ g_free(val); -+} -+ -+static void __attribute__ ((unused)) spapr_cap_set_tristate(Object *obj, -+ Visitor *v, -+ const char *name, -+ void *opaque, -+ Error **errp) -+{ -+ sPAPRCapabilityInfo *cap = opaque; -+ sPAPRMachineState *spapr = SPAPR_MACHINE(obj); -+ char *val; -+ Error *local_err = NULL; -+ uint8_t value; -+ -+ visit_type_str(v, name, &val, &local_err); -+ if (local_err) { -+ error_propagate(errp, local_err); -+ return; -+ } -+ -+ if (!strcasecmp(val, "broken")) { -+ value = SPAPR_CAP_BROKEN; -+ } else if (!strcasecmp(val, "workaround")) { -+ value = SPAPR_CAP_WORKAROUND; -+ } else if (!strcasecmp(val, "fixed")) { -+ value = SPAPR_CAP_FIXED; -+ } else { -+ error_setg(errp, "Invalid capability mode \"%s\" for cap-%s", val, -+ cap->name); -+ goto out; -+ } -+ -+ spapr->cmd_line_caps[cap->index] = true; -+ spapr->eff.caps[cap->index] = value; -+out: -+ g_free(val); -+} -+ - static void cap_htm_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp) - { - if (!val) { -diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h -index 6090f3d..abe0011 100644 ---- a/include/hw/ppc/spapr.h -+++ b/include/hw/ppc/spapr.h -@@ -69,6 +69,10 @@ typedef enum { - /* Bool Caps */ - #define SPAPR_CAP_OFF 0x00 - #define SPAPR_CAP_ON 0x01 -+/* Broken | Workaround | Fixed Caps */ -+#define SPAPR_CAP_BROKEN 0x00 -+#define SPAPR_CAP_WORKAROUND 0x01 -+#define SPAPR_CAP_FIXED 0x02 - - typedef struct sPAPRCapabilities sPAPRCapabilities; - struct sPAPRCapabilities { --- -1.8.3.1 - diff --git a/SOURCES/kvm-tcg-workaround-branch-instruction-overflow-in-tcg_ou.patch b/SOURCES/kvm-tcg-workaround-branch-instruction-overflow-in-tcg_ou.patch new file mode 100644 index 0000000..00e7bf3 --- /dev/null +++ b/SOURCES/kvm-tcg-workaround-branch-instruction-overflow-in-tcg_ou.patch @@ -0,0 +1,102 @@ +From 1ef4307f6e1299d337bc925ea7bbea41c2f99706 Mon Sep 17 00:00:00 2001 +From: Laurent Vivier +Date: Fri, 4 May 2018 09:38:55 +0200 +Subject: [PATCH 06/13] tcg: workaround branch instruction overflow in + tcg_out_qemu_ld/st + +RH-Author: Laurent Vivier +Message-id: <20180504093855.30922-1-lvivier@redhat.com> +Patchwork-id: 80025 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH] tcg: workaround branch instruction overflow in tcg_out_qemu_ld/st +Bugzilla: 1574577 +RH-Acked-by: Serhii Popovych +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Miroslav Rezanina + +ppc64 uses a BC instruction to call the tcg_out_qemu_ld/st +slow path. BC instruction uses a relative address encoded +on 14 bits. + +The slow path functions are added at the end of the generated +instructions buffer, in the reverse order of the callers. +So more we have slow path functions more the distance between +the caller (BC) and the function increases. + +This patch changes the behavior to generate the functions in +the same order of the callers. + +Cc: qemu-stable@nongnu.org +Fixes: 15fa08f845 ("tcg: Dynamically allocate TCGOps") +Signed-off-by: Laurent Vivier +Message-Id: <20180429235840.16659-1-lvivier@redhat.com> +Signed-off-by: Richard Henderson +(cherry picked from commit 6001f7729e12dd1d810291e4cbf83cee8e07441d) +Signed-off-by: Laurent Vivier +Signed-off-by: Miroslav Rezanina +--- + tcg/tcg-ldst.inc.c | 8 ++++---- + tcg/tcg.c | 2 +- + tcg/tcg.h | 2 +- + 3 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/tcg/tcg-ldst.inc.c b/tcg/tcg-ldst.inc.c +index 0e14cf4..47f41b9 100644 +--- a/tcg/tcg-ldst.inc.c ++++ b/tcg/tcg-ldst.inc.c +@@ -30,7 +30,7 @@ typedef struct TCGLabelQemuLdst { + TCGReg datahi_reg; /* reg index for high word to be loaded or stored */ + tcg_insn_unit *raddr; /* gen code addr of the next IR of qemu_ld/st IR */ + tcg_insn_unit *label_ptr[2]; /* label pointers to be updated */ +- struct TCGLabelQemuLdst *next; ++ QSIMPLEQ_ENTRY(TCGLabelQemuLdst) next; + } TCGLabelQemuLdst; + + +@@ -46,7 +46,7 @@ static bool tcg_out_ldst_finalize(TCGContext *s) + TCGLabelQemuLdst *lb; + + /* qemu_ld/st slow paths */ +- for (lb = s->ldst_labels; lb != NULL; lb = lb->next) { ++ QSIMPLEQ_FOREACH(lb, &s->ldst_labels, next) { + if (lb->is_ld) { + tcg_out_qemu_ld_slow_path(s, lb); + } else { +@@ -72,7 +72,7 @@ static inline TCGLabelQemuLdst *new_ldst_label(TCGContext *s) + { + TCGLabelQemuLdst *l = tcg_malloc(sizeof(*l)); + +- l->next = s->ldst_labels; +- s->ldst_labels = l; ++ QSIMPLEQ_INSERT_TAIL(&s->ldst_labels, l, next); ++ + return l; + } +diff --git a/tcg/tcg.c b/tcg/tcg.c +index bb24526..b84850b 100644 +--- a/tcg/tcg.c ++++ b/tcg/tcg.c +@@ -3324,7 +3324,7 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb) + s->code_ptr = tb->tc.ptr; + + #ifdef TCG_TARGET_NEED_LDST_LABELS +- s->ldst_labels = NULL; ++ QSIMPLEQ_INIT(&s->ldst_labels); + #endif + #ifdef TCG_TARGET_NEED_POOL_LABELS + s->pool_labels = NULL; +diff --git a/tcg/tcg.h b/tcg/tcg.h +index 30896ca..a3076c5 100644 +--- a/tcg/tcg.h ++++ b/tcg/tcg.h +@@ -699,7 +699,7 @@ struct TCGContext { + + /* These structures are private to tcg-target.inc.c. */ + #ifdef TCG_TARGET_NEED_LDST_LABELS +- struct TCGLabelQemuLdst *ldst_labels; ++ QSIMPLEQ_HEAD(ldst_labels, TCGLabelQemuLdst) ldst_labels; + #endif + #ifdef TCG_TARGET_NEED_POOL_LABELS + struct TCGLabelPoolData *pool_labels; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-test-bdrv-drain-AIO_WAIT_WHILE-in-job-.commit-.abort.patch b/SOURCES/kvm-test-bdrv-drain-AIO_WAIT_WHILE-in-job-.commit-.abort.patch new file mode 100644 index 0000000..9d87885 --- /dev/null +++ b/SOURCES/kvm-test-bdrv-drain-AIO_WAIT_WHILE-in-job-.commit-.abort.patch @@ -0,0 +1,239 @@ +From 1b85fbf7ed7119dac8bc0fedfb019d0ce991d07d Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:40 +0200 +Subject: [PATCH 49/49] test-bdrv-drain: AIO_WAIT_WHILE() in job .commit/.abort + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-43-kwolf@redhat.com> +Patchwork-id: 82193 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 42/42] test-bdrv-drain: AIO_WAIT_WHILE() in job .commit/.abort +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This adds tests for calling AIO_WAIT_WHILE() in the .commit and .abort +callbacks. Both reasons why .abort could be called for a single job are +tested: Either .run or .prepare could return an error. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +Signed-off-by: Miroslav Rezanina +--- + tests/test-bdrv-drain.c | 116 +++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 104 insertions(+), 12 deletions(-) + +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index f4b57f7..d6202b2 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -784,6 +784,8 @@ static void test_iothread_drain_subtree(void) + + typedef struct TestBlockJob { + BlockJob common; ++ int run_ret; ++ int prepare_ret; + bool should_complete; + } TestBlockJob; + +@@ -793,7 +795,23 @@ static int test_job_prepare(Job *job) + + /* Provoke an AIO_WAIT_WHILE() call to verify there is no deadlock */ + blk_flush(s->common.blk); +- return 0; ++ return s->prepare_ret; ++} ++ ++static void test_job_commit(Job *job) ++{ ++ TestBlockJob *s = container_of(job, TestBlockJob, common.job); ++ ++ /* Provoke an AIO_WAIT_WHILE() call to verify there is no deadlock */ ++ blk_flush(s->common.blk); ++} ++ ++static void test_job_abort(Job *job) ++{ ++ TestBlockJob *s = container_of(job, TestBlockJob, common.job); ++ ++ /* Provoke an AIO_WAIT_WHILE() call to verify there is no deadlock */ ++ blk_flush(s->common.blk); + } + + static int coroutine_fn test_job_run(Job *job, Error **errp) +@@ -809,7 +827,7 @@ static int coroutine_fn test_job_run(Job *job, Error **errp) + job_pause_point(&s->common.job); + } + +- return 0; ++ return s->run_ret; + } + + static void test_job_complete(Job *job, Error **errp) +@@ -827,14 +845,24 @@ BlockJobDriver test_job_driver = { + .run = test_job_run, + .complete = test_job_complete, + .prepare = test_job_prepare, ++ .commit = test_job_commit, ++ .abort = test_job_abort, + }, + }; + +-static void test_blockjob_common(enum drain_type drain_type, bool use_iothread) ++enum test_job_result { ++ TEST_JOB_SUCCESS, ++ TEST_JOB_FAIL_RUN, ++ TEST_JOB_FAIL_PREPARE, ++}; ++ ++static void test_blockjob_common(enum drain_type drain_type, bool use_iothread, ++ enum test_job_result result) + { + BlockBackend *blk_src, *blk_target; + BlockDriverState *src, *target; + BlockJob *job; ++ TestBlockJob *tjob; + IOThread *iothread = NULL; + AioContext *ctx; + int ret; +@@ -858,9 +886,23 @@ static void test_blockjob_common(enum drain_type drain_type, bool use_iothread) + blk_insert_bs(blk_target, target, &error_abort); + + aio_context_acquire(ctx); +- job = block_job_create("job0", &test_job_driver, NULL, src, 0, BLK_PERM_ALL, +- 0, 0, NULL, NULL, &error_abort); ++ tjob = block_job_create("job0", &test_job_driver, NULL, src, ++ 0, BLK_PERM_ALL, ++ 0, 0, NULL, NULL, &error_abort); ++ job = &tjob->common; + block_job_add_bdrv(job, "target", target, 0, BLK_PERM_ALL, &error_abort); ++ ++ switch (result) { ++ case TEST_JOB_SUCCESS: ++ break; ++ case TEST_JOB_FAIL_RUN: ++ tjob->run_ret = -EIO; ++ break; ++ case TEST_JOB_FAIL_PREPARE: ++ tjob->prepare_ret = -EIO; ++ break; ++ } ++ + job_start(&job->job); + aio_context_release(ctx); + +@@ -918,7 +960,7 @@ static void test_blockjob_common(enum drain_type drain_type, bool use_iothread) + + aio_context_acquire(ctx); + ret = job_complete_sync(&job->job, &error_abort); +- g_assert_cmpint(ret, ==, 0); ++ g_assert_cmpint(ret, ==, (result == TEST_JOB_SUCCESS ? 0 : -EIO)); + + if (use_iothread) { + blk_set_aio_context(blk_src, qemu_get_aio_context()); +@@ -937,32 +979,68 @@ static void test_blockjob_common(enum drain_type drain_type, bool use_iothread) + + static void test_blockjob_drain_all(void) + { +- test_blockjob_common(BDRV_DRAIN_ALL, false); ++ test_blockjob_common(BDRV_DRAIN_ALL, false, TEST_JOB_SUCCESS); + } + + static void test_blockjob_drain(void) + { +- test_blockjob_common(BDRV_DRAIN, false); ++ test_blockjob_common(BDRV_DRAIN, false, TEST_JOB_SUCCESS); + } + + static void test_blockjob_drain_subtree(void) + { +- test_blockjob_common(BDRV_SUBTREE_DRAIN, false); ++ test_blockjob_common(BDRV_SUBTREE_DRAIN, false, TEST_JOB_SUCCESS); ++} ++ ++static void test_blockjob_error_drain_all(void) ++{ ++ test_blockjob_common(BDRV_DRAIN_ALL, false, TEST_JOB_FAIL_RUN); ++ test_blockjob_common(BDRV_DRAIN_ALL, false, TEST_JOB_FAIL_PREPARE); ++} ++ ++static void test_blockjob_error_drain(void) ++{ ++ test_blockjob_common(BDRV_DRAIN, false, TEST_JOB_FAIL_RUN); ++ test_blockjob_common(BDRV_DRAIN, false, TEST_JOB_FAIL_PREPARE); ++} ++ ++static void test_blockjob_error_drain_subtree(void) ++{ ++ test_blockjob_common(BDRV_SUBTREE_DRAIN, false, TEST_JOB_FAIL_RUN); ++ test_blockjob_common(BDRV_SUBTREE_DRAIN, false, TEST_JOB_FAIL_PREPARE); + } + + static void test_blockjob_iothread_drain_all(void) + { +- test_blockjob_common(BDRV_DRAIN_ALL, true); ++ test_blockjob_common(BDRV_DRAIN_ALL, true, TEST_JOB_SUCCESS); + } + + static void test_blockjob_iothread_drain(void) + { +- test_blockjob_common(BDRV_DRAIN, true); ++ test_blockjob_common(BDRV_DRAIN, true, TEST_JOB_SUCCESS); + } + + static void test_blockjob_iothread_drain_subtree(void) + { +- test_blockjob_common(BDRV_SUBTREE_DRAIN, true); ++ test_blockjob_common(BDRV_SUBTREE_DRAIN, true, TEST_JOB_SUCCESS); ++} ++ ++static void test_blockjob_iothread_error_drain_all(void) ++{ ++ test_blockjob_common(BDRV_DRAIN_ALL, true, TEST_JOB_FAIL_RUN); ++ test_blockjob_common(BDRV_DRAIN_ALL, true, TEST_JOB_FAIL_PREPARE); ++} ++ ++static void test_blockjob_iothread_error_drain(void) ++{ ++ test_blockjob_common(BDRV_DRAIN, true, TEST_JOB_FAIL_RUN); ++ test_blockjob_common(BDRV_DRAIN, true, TEST_JOB_FAIL_PREPARE); ++} ++ ++static void test_blockjob_iothread_error_drain_subtree(void) ++{ ++ test_blockjob_common(BDRV_SUBTREE_DRAIN, true, TEST_JOB_FAIL_RUN); ++ test_blockjob_common(BDRV_SUBTREE_DRAIN, true, TEST_JOB_FAIL_PREPARE); + } + + +@@ -1433,6 +1511,13 @@ int main(int argc, char **argv) + g_test_add_func("/bdrv-drain/blockjob/drain_subtree", + test_blockjob_drain_subtree); + ++ g_test_add_func("/bdrv-drain/blockjob/error/drain_all", ++ test_blockjob_error_drain_all); ++ g_test_add_func("/bdrv-drain/blockjob/error/drain", ++ test_blockjob_error_drain); ++ g_test_add_func("/bdrv-drain/blockjob/error/drain_subtree", ++ test_blockjob_error_drain_subtree); ++ + g_test_add_func("/bdrv-drain/blockjob/iothread/drain_all", + test_blockjob_iothread_drain_all); + g_test_add_func("/bdrv-drain/blockjob/iothread/drain", +@@ -1440,6 +1525,13 @@ int main(int argc, char **argv) + g_test_add_func("/bdrv-drain/blockjob/iothread/drain_subtree", + test_blockjob_iothread_drain_subtree); + ++ g_test_add_func("/bdrv-drain/blockjob/iothread/error/drain_all", ++ test_blockjob_iothread_error_drain_all); ++ g_test_add_func("/bdrv-drain/blockjob/iothread/error/drain", ++ test_blockjob_iothread_error_drain); ++ g_test_add_func("/bdrv-drain/blockjob/iothread/error/drain_subtree", ++ test_blockjob_iothread_error_drain_subtree); ++ + g_test_add_func("/bdrv-drain/deletion/drain", test_delete_by_drain); + g_test_add_func("/bdrv-drain/detach/drain_all", test_detach_by_drain_all); + g_test_add_func("/bdrv-drain/detach/drain", test_detach_by_drain); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-test-bdrv-drain-Add-test-for-node-deletion.patch b/SOURCES/kvm-test-bdrv-drain-Add-test-for-node-deletion.patch new file mode 100644 index 0000000..2bcb07a --- /dev/null +++ b/SOURCES/kvm-test-bdrv-drain-Add-test-for-node-deletion.patch @@ -0,0 +1,226 @@ +From e830be5d2de1d07f54b741f7a6e8bdea357bf044 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:07 +0200 +Subject: [PATCH 16/49] test-bdrv-drain: Add test for node deletion + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-10-kwolf@redhat.com> +Patchwork-id: 82162 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 09/42] test-bdrv-drain: Add test for node deletion +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +From: Max Reitz + +This patch adds two bdrv-drain tests for what happens if some BDS goes +away during the drainage. + +The basic idea is that you have a parent BDS with some child nodes. +Then, you drain one of the children. Because of that, the party who +actually owns the parent decides to (A) delete it, or (B) detach all its +children from it -- both while the child is still being drained. + +A real-world case where this can happen is the mirror block job, which +may exit if you drain one of its children. + +Signed-off-by: Max Reitz +Signed-off-by: Kevin Wolf +(cherry picked from commit 4c8158e359d194394c64acd21caf5e3f3f3141c2) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/test-bdrv-drain.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 169 insertions(+) + +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index 49786ea..8918a94 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -792,6 +792,172 @@ static void test_blockjob_drain_subtree(void) + test_blockjob_common(BDRV_SUBTREE_DRAIN); + } + ++ ++typedef struct BDRVTestTopState { ++ BdrvChild *wait_child; ++} BDRVTestTopState; ++ ++static void bdrv_test_top_close(BlockDriverState *bs) ++{ ++ BdrvChild *c, *next_c; ++ QLIST_FOREACH_SAFE(c, &bs->children, next, next_c) { ++ bdrv_unref_child(bs, c); ++ } ++} ++ ++static int coroutine_fn bdrv_test_top_co_preadv(BlockDriverState *bs, ++ uint64_t offset, uint64_t bytes, ++ QEMUIOVector *qiov, int flags) ++{ ++ BDRVTestTopState *tts = bs->opaque; ++ return bdrv_co_preadv(tts->wait_child, offset, bytes, qiov, flags); ++} ++ ++static BlockDriver bdrv_test_top_driver = { ++ .format_name = "test_top_driver", ++ .instance_size = sizeof(BDRVTestTopState), ++ ++ .bdrv_close = bdrv_test_top_close, ++ .bdrv_co_preadv = bdrv_test_top_co_preadv, ++ ++ .bdrv_child_perm = bdrv_format_default_perms, ++}; ++ ++typedef struct TestCoDeleteByDrainData { ++ BlockBackend *blk; ++ bool detach_instead_of_delete; ++ bool done; ++} TestCoDeleteByDrainData; ++ ++static void coroutine_fn test_co_delete_by_drain(void *opaque) ++{ ++ TestCoDeleteByDrainData *dbdd = opaque; ++ BlockBackend *blk = dbdd->blk; ++ BlockDriverState *bs = blk_bs(blk); ++ BDRVTestTopState *tts = bs->opaque; ++ void *buffer = g_malloc(65536); ++ QEMUIOVector qiov; ++ struct iovec iov = { ++ .iov_base = buffer, ++ .iov_len = 65536, ++ }; ++ ++ qemu_iovec_init_external(&qiov, &iov, 1); ++ ++ /* Pretend some internal write operation from parent to child. ++ * Important: We have to read from the child, not from the parent! ++ * Draining works by first propagating it all up the tree to the ++ * root and then waiting for drainage from root to the leaves ++ * (protocol nodes). If we have a request waiting on the root, ++ * everything will be drained before we go back down the tree, but ++ * we do not want that. We want to be in the middle of draining ++ * when this following requests returns. */ ++ bdrv_co_preadv(tts->wait_child, 0, 65536, &qiov, 0); ++ ++ g_assert_cmpint(bs->refcnt, ==, 1); ++ ++ if (!dbdd->detach_instead_of_delete) { ++ blk_unref(blk); ++ } else { ++ BdrvChild *c, *next_c; ++ QLIST_FOREACH_SAFE(c, &bs->children, next, next_c) { ++ bdrv_unref_child(bs, c); ++ } ++ } ++ ++ dbdd->done = true; ++} ++ ++/** ++ * Test what happens when some BDS has some children, you drain one of ++ * them and this results in the BDS being deleted. ++ * ++ * If @detach_instead_of_delete is set, the BDS is not going to be ++ * deleted but will only detach all of its children. ++ */ ++static void do_test_delete_by_drain(bool detach_instead_of_delete) ++{ ++ BlockBackend *blk; ++ BlockDriverState *bs, *child_bs, *null_bs; ++ BDRVTestTopState *tts; ++ TestCoDeleteByDrainData dbdd; ++ Coroutine *co; ++ ++ bs = bdrv_new_open_driver(&bdrv_test_top_driver, "top", BDRV_O_RDWR, ++ &error_abort); ++ bs->total_sectors = 65536 >> BDRV_SECTOR_BITS; ++ tts = bs->opaque; ++ ++ null_bs = bdrv_open("null-co://", NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL, ++ &error_abort); ++ bdrv_attach_child(bs, null_bs, "null-child", &child_file, &error_abort); ++ ++ /* This child will be the one to pass to requests through to, and ++ * it will stall until a drain occurs */ ++ child_bs = bdrv_new_open_driver(&bdrv_test, "child", BDRV_O_RDWR, ++ &error_abort); ++ child_bs->total_sectors = 65536 >> BDRV_SECTOR_BITS; ++ /* Takes our reference to child_bs */ ++ tts->wait_child = bdrv_attach_child(bs, child_bs, "wait-child", &child_file, ++ &error_abort); ++ ++ /* This child is just there to be deleted ++ * (for detach_instead_of_delete == true) */ ++ null_bs = bdrv_open("null-co://", NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL, ++ &error_abort); ++ bdrv_attach_child(bs, null_bs, "null-child", &child_file, &error_abort); ++ ++ blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); ++ blk_insert_bs(blk, bs, &error_abort); ++ ++ /* Referenced by blk now */ ++ bdrv_unref(bs); ++ ++ g_assert_cmpint(bs->refcnt, ==, 1); ++ g_assert_cmpint(child_bs->refcnt, ==, 1); ++ g_assert_cmpint(null_bs->refcnt, ==, 1); ++ ++ ++ dbdd = (TestCoDeleteByDrainData){ ++ .blk = blk, ++ .detach_instead_of_delete = detach_instead_of_delete, ++ .done = false, ++ }; ++ co = qemu_coroutine_create(test_co_delete_by_drain, &dbdd); ++ qemu_coroutine_enter(co); ++ ++ /* Drain the child while the read operation is still pending. ++ * This should result in the operation finishing and ++ * test_co_delete_by_drain() resuming. Thus, @bs will be deleted ++ * and the coroutine will exit while this drain operation is still ++ * in progress. */ ++ bdrv_ref(child_bs); ++ bdrv_drain(child_bs); ++ bdrv_unref(child_bs); ++ ++ while (!dbdd.done) { ++ aio_poll(qemu_get_aio_context(), true); ++ } ++ ++ if (detach_instead_of_delete) { ++ /* Here, the reference has not passed over to the coroutine, ++ * so we have to delete the BB ourselves */ ++ blk_unref(blk); ++ } ++} ++ ++ ++static void test_delete_by_drain(void) ++{ ++ do_test_delete_by_drain(false); ++} ++ ++static void test_detach_by_drain(void) ++{ ++ do_test_delete_by_drain(true); ++} ++ ++ + int main(int argc, char **argv) + { + int ret; +@@ -839,6 +1005,9 @@ int main(int argc, char **argv) + g_test_add_func("/bdrv-drain/blockjob/drain_subtree", + test_blockjob_drain_subtree); + ++ g_test_add_func("/bdrv-drain/deletion", test_delete_by_drain); ++ g_test_add_func("/bdrv-drain/detach", test_detach_by_drain); ++ + ret = g_test_run(); + qemu_event_destroy(&done_event); + return ret; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-test-bdrv-drain-Drain-with-block-jobs-in-an-I-O-thre.patch b/SOURCES/kvm-test-bdrv-drain-Drain-with-block-jobs-in-an-I-O-thre.patch new file mode 100644 index 0000000..b3e32b2 --- /dev/null +++ b/SOURCES/kvm-test-bdrv-drain-Drain-with-block-jobs-in-an-I-O-thre.patch @@ -0,0 +1,206 @@ +From 226e66779d3cc43409b08618d2bbdf160c6d42d8 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:27 +0200 +Subject: [PATCH 36/49] test-bdrv-drain: Drain with block jobs in an I/O thread + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-30-kwolf@redhat.com> +Patchwork-id: 82182 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 29/42] test-bdrv-drain: Drain with block jobs in an I/O thread +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This extends the existing drain test with a block job to include +variants where the block job runs in a different AioContext. + +Signed-off-by: Kevin Wolf +Reviewed-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + tests/test-bdrv-drain.c | 92 +++++++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 86 insertions(+), 6 deletions(-) + +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index 9bcb3c7..3cf3ba3 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -174,6 +174,28 @@ static void do_drain_end(enum drain_type drain_type, BlockDriverState *bs) + } + } + ++static void do_drain_begin_unlocked(enum drain_type drain_type, BlockDriverState *bs) ++{ ++ if (drain_type != BDRV_DRAIN_ALL) { ++ aio_context_acquire(bdrv_get_aio_context(bs)); ++ } ++ do_drain_begin(drain_type, bs); ++ if (drain_type != BDRV_DRAIN_ALL) { ++ aio_context_release(bdrv_get_aio_context(bs)); ++ } ++} ++ ++static void do_drain_end_unlocked(enum drain_type drain_type, BlockDriverState *bs) ++{ ++ if (drain_type != BDRV_DRAIN_ALL) { ++ aio_context_acquire(bdrv_get_aio_context(bs)); ++ } ++ do_drain_end(drain_type, bs); ++ if (drain_type != BDRV_DRAIN_ALL) { ++ aio_context_release(bdrv_get_aio_context(bs)); ++ } ++} ++ + static void test_drv_cb_common(enum drain_type drain_type, bool recursive) + { + BlockBackend *blk; +@@ -785,11 +807,13 @@ BlockJobDriver test_job_driver = { + }, + }; + +-static void test_blockjob_common(enum drain_type drain_type) ++static void test_blockjob_common(enum drain_type drain_type, bool use_iothread) + { + BlockBackend *blk_src, *blk_target; + BlockDriverState *src, *target; + BlockJob *job; ++ IOThread *iothread = NULL; ++ AioContext *ctx; + int ret; + + src = bdrv_new_open_driver(&bdrv_test, "source", BDRV_O_RDWR, +@@ -797,21 +821,31 @@ static void test_blockjob_common(enum drain_type drain_type) + blk_src = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); + blk_insert_bs(blk_src, src, &error_abort); + ++ if (use_iothread) { ++ iothread = iothread_new(); ++ ctx = iothread_get_aio_context(iothread); ++ blk_set_aio_context(blk_src, ctx); ++ } else { ++ ctx = qemu_get_aio_context(); ++ } ++ + target = bdrv_new_open_driver(&bdrv_test, "target", BDRV_O_RDWR, + &error_abort); + blk_target = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); + blk_insert_bs(blk_target, target, &error_abort); + ++ aio_context_acquire(ctx); + job = block_job_create("job0", &test_job_driver, NULL, src, 0, BLK_PERM_ALL, + 0, 0, NULL, NULL, &error_abort); + block_job_add_bdrv(job, "target", target, 0, BLK_PERM_ALL, &error_abort); + job_start(&job->job); ++ aio_context_release(ctx); + + g_assert_cmpint(job->job.pause_count, ==, 0); + g_assert_false(job->job.paused); + g_assert_true(job->job.busy); /* We're in job_sleep_ns() */ + +- do_drain_begin(drain_type, src); ++ do_drain_begin_unlocked(drain_type, src); + + if (drain_type == BDRV_DRAIN_ALL) { + /* bdrv_drain_all() drains both src and target */ +@@ -822,7 +856,14 @@ static void test_blockjob_common(enum drain_type drain_type) + g_assert_true(job->job.paused); + g_assert_false(job->job.busy); /* The job is paused */ + +- do_drain_end(drain_type, src); ++ do_drain_end_unlocked(drain_type, src); ++ ++ if (use_iothread) { ++ /* paused is reset in the I/O thread, wait for it */ ++ while (job->job.paused) { ++ aio_poll(qemu_get_aio_context(), false); ++ } ++ } + + g_assert_cmpint(job->job.pause_count, ==, 0); + g_assert_false(job->job.paused); +@@ -841,32 +882,64 @@ static void test_blockjob_common(enum drain_type drain_type) + + do_drain_end(drain_type, target); + ++ if (use_iothread) { ++ /* paused is reset in the I/O thread, wait for it */ ++ while (job->job.paused) { ++ aio_poll(qemu_get_aio_context(), false); ++ } ++ } ++ + g_assert_cmpint(job->job.pause_count, ==, 0); + g_assert_false(job->job.paused); + g_assert_true(job->job.busy); /* We're in job_sleep_ns() */ + ++ aio_context_acquire(ctx); + ret = job_complete_sync(&job->job, &error_abort); + g_assert_cmpint(ret, ==, 0); + ++ if (use_iothread) { ++ blk_set_aio_context(blk_src, qemu_get_aio_context()); ++ } ++ aio_context_release(ctx); ++ + blk_unref(blk_src); + blk_unref(blk_target); + bdrv_unref(src); + bdrv_unref(target); ++ ++ if (iothread) { ++ iothread_join(iothread); ++ } + } + + static void test_blockjob_drain_all(void) + { +- test_blockjob_common(BDRV_DRAIN_ALL); ++ test_blockjob_common(BDRV_DRAIN_ALL, false); + } + + static void test_blockjob_drain(void) + { +- test_blockjob_common(BDRV_DRAIN); ++ test_blockjob_common(BDRV_DRAIN, false); + } + + static void test_blockjob_drain_subtree(void) + { +- test_blockjob_common(BDRV_SUBTREE_DRAIN); ++ test_blockjob_common(BDRV_SUBTREE_DRAIN, false); ++} ++ ++static void test_blockjob_iothread_drain_all(void) ++{ ++ test_blockjob_common(BDRV_DRAIN_ALL, true); ++} ++ ++static void test_blockjob_iothread_drain(void) ++{ ++ test_blockjob_common(BDRV_DRAIN, true); ++} ++ ++static void test_blockjob_iothread_drain_subtree(void) ++{ ++ test_blockjob_common(BDRV_SUBTREE_DRAIN, true); + } + + +@@ -1337,6 +1410,13 @@ int main(int argc, char **argv) + g_test_add_func("/bdrv-drain/blockjob/drain_subtree", + test_blockjob_drain_subtree); + ++ g_test_add_func("/bdrv-drain/blockjob/iothread/drain_all", ++ test_blockjob_iothread_drain_all); ++ g_test_add_func("/bdrv-drain/blockjob/iothread/drain", ++ test_blockjob_iothread_drain); ++ g_test_add_func("/bdrv-drain/blockjob/iothread/drain_subtree", ++ test_blockjob_iothread_drain_subtree); ++ + g_test_add_func("/bdrv-drain/deletion/drain", test_delete_by_drain); + g_test_add_func("/bdrv-drain/detach/drain_all", test_detach_by_drain_all); + g_test_add_func("/bdrv-drain/detach/drain", test_detach_by_drain); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-test-bdrv-drain-Fix-outdated-comments.patch b/SOURCES/kvm-test-bdrv-drain-Fix-outdated-comments.patch new file mode 100644 index 0000000..ea1af43 --- /dev/null +++ b/SOURCES/kvm-test-bdrv-drain-Fix-outdated-comments.patch @@ -0,0 +1,67 @@ +From afdf8a5ba72ac761081edba383699bd45968349e Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 21 Sep 2018 12:46:28 +0200 +Subject: [PATCH 1/3] test-bdrv-drain: Fix outdated comments + +RH-Author: Kevin Wolf +Message-id: <20180921124630.29036-2-kwolf@redhat.com> +Patchwork-id: 82232 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 1/3] test-bdrv-drain: Fix outdated comments +Bugzilla: 1618584 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Eric Blake +RH-Acked-by: John Snow + +Commit 89bd030533e changed the test case from using job_sleep_ns() to +using qemu_co_sleep_ns() instead. Also, block_job_sleep_ns() became +job_sleep_ns() in commit 5d43e86e11f. + +In both cases, some comments in the test case were not updated. Do that +now. + +Reported-by: Max Reitz +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/test-bdrv-drain.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index d6202b2..7e7ba9b 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -820,9 +820,9 @@ static int coroutine_fn test_job_run(Job *job, Error **errp) + + job_transition_to_ready(&s->common.job); + while (!s->should_complete) { +- /* Avoid block_job_sleep_ns() because it marks the job as !busy. We +- * want to emulate some actual activity (probably some I/O) here so +- * that drain has to wait for this acitivity to stop. */ ++ /* Avoid job_sleep_ns() because it marks the job as !busy. We want to ++ * emulate some actual activity (probably some I/O) here so that drain ++ * has to wait for this activity to stop. */ + qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000); + job_pause_point(&s->common.job); + } +@@ -908,7 +908,7 @@ static void test_blockjob_common(enum drain_type drain_type, bool use_iothread, + + g_assert_cmpint(job->job.pause_count, ==, 0); + g_assert_false(job->job.paused); +- g_assert_true(job->job.busy); /* We're in job_sleep_ns() */ ++ g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */ + + do_drain_begin_unlocked(drain_type, src); + +@@ -956,7 +956,7 @@ static void test_blockjob_common(enum drain_type drain_type, bool use_iothread, + + g_assert_cmpint(job->job.pause_count, ==, 0); + g_assert_false(job->job.paused); +- g_assert_true(job->job.busy); /* We're in job_sleep_ns() */ ++ g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */ + + aio_context_acquire(ctx); + ret = job_complete_sync(&job->job, &error_abort); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-test-bdrv-drain-Graph-change-through-parent-callback.patch b/SOURCES/kvm-test-bdrv-drain-Graph-change-through-parent-callback.patch new file mode 100644 index 0000000..6515809 --- /dev/null +++ b/SOURCES/kvm-test-bdrv-drain-Graph-change-through-parent-callback.patch @@ -0,0 +1,173 @@ +From d365fdc837cbf347d8575592aeb96097b6a85923 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:11 +0200 +Subject: [PATCH 20/49] test-bdrv-drain: Graph change through parent callback + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-14-kwolf@redhat.com> +Patchwork-id: 82165 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 13/42] test-bdrv-drain: Graph change through parent callback +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +Signed-off-by: Kevin Wolf +(cherry picked from commit 231281ab42dad2b407b941e36ad11cbc6586e937) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/test-bdrv-drain.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 130 insertions(+) + +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index 38706b0..f786326 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -977,6 +977,135 @@ static void test_detach_by_drain_subtree(void) + } + + ++struct detach_by_parent_data { ++ BlockDriverState *parent_b; ++ BdrvChild *child_b; ++ BlockDriverState *c; ++ BdrvChild *child_c; ++}; ++ ++static void detach_by_parent_aio_cb(void *opaque, int ret) ++{ ++ struct detach_by_parent_data *data = opaque; ++ ++ g_assert_cmpint(ret, ==, 0); ++ bdrv_unref_child(data->parent_b, data->child_b); ++ ++ bdrv_ref(data->c); ++ data->child_c = bdrv_attach_child(data->parent_b, data->c, "PB-C", ++ &child_file, &error_abort); ++} ++ ++/* ++ * Initial graph: ++ * ++ * PA PB ++ * \ / \ ++ * A B C ++ * ++ * PA has a pending write request whose callback changes the child nodes of PB: ++ * It removes B and adds C instead. The subtree of PB is drained, which will ++ * indirectly drain the write request, too. ++ */ ++static void test_detach_by_parent_cb(void) ++{ ++ BlockBackend *blk; ++ BlockDriverState *parent_a, *parent_b, *a, *b, *c; ++ BdrvChild *child_a, *child_b; ++ BlockAIOCB *acb; ++ struct detach_by_parent_data data; ++ ++ QEMUIOVector qiov; ++ struct iovec iov = { ++ .iov_base = NULL, ++ .iov_len = 0, ++ }; ++ qemu_iovec_init_external(&qiov, &iov, 1); ++ ++ /* Create all involved nodes */ ++ parent_a = bdrv_new_open_driver(&bdrv_test, "parent-a", BDRV_O_RDWR, ++ &error_abort); ++ parent_b = bdrv_new_open_driver(&bdrv_test, "parent-b", 0, ++ &error_abort); ++ ++ a = bdrv_new_open_driver(&bdrv_test, "a", BDRV_O_RDWR, &error_abort); ++ b = bdrv_new_open_driver(&bdrv_test, "b", BDRV_O_RDWR, &error_abort); ++ c = bdrv_new_open_driver(&bdrv_test, "c", BDRV_O_RDWR, &error_abort); ++ ++ /* blk is a BB for parent-a */ ++ blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); ++ blk_insert_bs(blk, parent_a, &error_abort); ++ bdrv_unref(parent_a); ++ ++ /* Set child relationships */ ++ bdrv_ref(b); ++ bdrv_ref(a); ++ child_b = bdrv_attach_child(parent_b, b, "PB-B", &child_file, &error_abort); ++ child_a = bdrv_attach_child(parent_b, a, "PB-A", &child_backing, &error_abort); ++ ++ bdrv_ref(a); ++ bdrv_attach_child(parent_a, a, "PA-A", &child_file, &error_abort); ++ ++ g_assert_cmpint(parent_a->refcnt, ==, 1); ++ g_assert_cmpint(parent_b->refcnt, ==, 1); ++ g_assert_cmpint(a->refcnt, ==, 3); ++ g_assert_cmpint(b->refcnt, ==, 2); ++ g_assert_cmpint(c->refcnt, ==, 1); ++ ++ g_assert(QLIST_FIRST(&parent_b->children) == child_a); ++ g_assert(QLIST_NEXT(child_a, next) == child_b); ++ g_assert(QLIST_NEXT(child_b, next) == NULL); ++ ++ /* Start the evil write request */ ++ data = (struct detach_by_parent_data) { ++ .parent_b = parent_b, ++ .child_b = child_b, ++ .c = c, ++ }; ++ acb = blk_aio_preadv(blk, 0, &qiov, 0, detach_by_parent_aio_cb, &data); ++ g_assert(acb != NULL); ++ ++ /* Drain and check the expected result */ ++ bdrv_subtree_drained_begin(parent_b); ++ ++ g_assert(data.child_c != NULL); ++ ++ g_assert_cmpint(parent_a->refcnt, ==, 1); ++ g_assert_cmpint(parent_b->refcnt, ==, 1); ++ g_assert_cmpint(a->refcnt, ==, 3); ++ g_assert_cmpint(b->refcnt, ==, 1); ++ g_assert_cmpint(c->refcnt, ==, 2); ++ ++ g_assert(QLIST_FIRST(&parent_b->children) == data.child_c); ++ g_assert(QLIST_NEXT(data.child_c, next) == child_a); ++ g_assert(QLIST_NEXT(child_a, next) == NULL); ++ ++ g_assert_cmpint(parent_a->quiesce_counter, ==, 1); ++ g_assert_cmpint(parent_b->quiesce_counter, ==, 1); ++ g_assert_cmpint(a->quiesce_counter, ==, 1); ++ g_assert_cmpint(b->quiesce_counter, ==, 0); ++ g_assert_cmpint(c->quiesce_counter, ==, 1); ++ ++ bdrv_subtree_drained_end(parent_b); ++ ++ bdrv_unref(parent_b); ++ blk_unref(blk); ++ ++ /* XXX Once bdrv_close() unref's children instead of just detaching them, ++ * this won't be necessary any more. */ ++ bdrv_unref(a); ++ bdrv_unref(a); ++ bdrv_unref(c); ++ ++ g_assert_cmpint(a->refcnt, ==, 1); ++ g_assert_cmpint(b->refcnt, ==, 1); ++ g_assert_cmpint(c->refcnt, ==, 1); ++ bdrv_unref(a); ++ bdrv_unref(b); ++ bdrv_unref(c); ++} ++ ++ + int main(int argc, char **argv) + { + int ret; +@@ -1027,6 +1156,7 @@ int main(int argc, char **argv) + g_test_add_func("/bdrv-drain/deletion/drain", test_delete_by_drain); + g_test_add_func("/bdrv-drain/detach/drain", test_detach_by_drain); + g_test_add_func("/bdrv-drain/detach/drain_subtree", test_detach_by_drain_subtree); ++ g_test_add_func("/bdrv-drain/detach/parent_cb", test_detach_by_parent_cb); + + ret = g_test_run(); + qemu_event_destroy(&done_event); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-test-bdrv-drain-Test-AIO_WAIT_WHILE-in-completion-ca.patch b/SOURCES/kvm-test-bdrv-drain-Test-AIO_WAIT_WHILE-in-completion-ca.patch new file mode 100644 index 0000000..3136aa3 --- /dev/null +++ b/SOURCES/kvm-test-bdrv-drain-Test-AIO_WAIT_WHILE-in-completion-ca.patch @@ -0,0 +1,58 @@ +From c6dae9ed2996e40bfdcf6c680bd481c43182fb3d Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:30 +0200 +Subject: [PATCH 39/49] test-bdrv-drain: Test AIO_WAIT_WHILE() in completion + callback + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-33-kwolf@redhat.com> +Patchwork-id: 82181 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 32/42] test-bdrv-drain: Test AIO_WAIT_WHILE() in completion callback +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This is a regression test for a deadlock that occurred in block job +completion callbacks (via job_defer_to_main_loop) because the AioContext +lock was taken twice: once in job_finish_sync() and then again in +job_defer_to_main_loop_bh(). This would cause AIO_WAIT_WHILE() to hang. + +Signed-off-by: Kevin Wolf +Reviewed-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + tests/test-bdrv-drain.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index 3cf3ba3..05f3b55 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -774,6 +774,15 @@ typedef struct TestBlockJob { + bool should_complete; + } TestBlockJob; + ++static int test_job_prepare(Job *job) ++{ ++ TestBlockJob *s = container_of(job, TestBlockJob, common.job); ++ ++ /* Provoke an AIO_WAIT_WHILE() call to verify there is no deadlock */ ++ blk_flush(s->common.blk); ++ return 0; ++} ++ + static int coroutine_fn test_job_run(Job *job, Error **errp) + { + TestBlockJob *s = container_of(job, TestBlockJob, common.job); +@@ -804,6 +813,7 @@ BlockJobDriver test_job_driver = { + .drain = block_job_drain, + .run = test_job_run, + .complete = test_job_complete, ++ .prepare = test_job_prepare, + }, + }; + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-test-bdrv-drain-Test-bdrv_append-to-drained-node.patch b/SOURCES/kvm-test-bdrv-drain-Test-bdrv_append-to-drained-node.patch new file mode 100644 index 0000000..ccd0efe --- /dev/null +++ b/SOURCES/kvm-test-bdrv-drain-Test-bdrv_append-to-drained-node.patch @@ -0,0 +1,86 @@ +From 55be3bf080a5b4768b88c1bc37b0867031add03d Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:20 +0200 +Subject: [PATCH 29/49] test-bdrv-drain: Test bdrv_append() to drained node + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-23-kwolf@redhat.com> +Patchwork-id: 82174 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 22/42] test-bdrv-drain: Test bdrv_append() to drained node +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +Signed-off-by: Kevin Wolf +(cherry picked from commit b994c5bc515fe611885113e7cfa7e87817bfd4e2) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/test-bdrv-drain.c | 43 +++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 43 insertions(+) + +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index 1c8162f..9bcb3c7 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -1245,6 +1245,47 @@ static void test_detach_by_driver_cb(void) + test_detach_indirect(false); + } + ++static void test_append_to_drained(void) ++{ ++ BlockBackend *blk; ++ BlockDriverState *base, *overlay; ++ BDRVTestState *base_s, *overlay_s; ++ ++ blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); ++ base = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort); ++ base_s = base->opaque; ++ blk_insert_bs(blk, base, &error_abort); ++ ++ overlay = bdrv_new_open_driver(&bdrv_test, "overlay", BDRV_O_RDWR, ++ &error_abort); ++ overlay_s = overlay->opaque; ++ ++ do_drain_begin(BDRV_DRAIN, base); ++ g_assert_cmpint(base->quiesce_counter, ==, 1); ++ g_assert_cmpint(base_s->drain_count, ==, 1); ++ g_assert_cmpint(base->in_flight, ==, 0); ++ ++ /* Takes ownership of overlay, so we don't have to unref it later */ ++ bdrv_append(overlay, base, &error_abort); ++ g_assert_cmpint(base->in_flight, ==, 0); ++ g_assert_cmpint(overlay->in_flight, ==, 0); ++ ++ g_assert_cmpint(base->quiesce_counter, ==, 1); ++ g_assert_cmpint(base_s->drain_count, ==, 1); ++ g_assert_cmpint(overlay->quiesce_counter, ==, 1); ++ g_assert_cmpint(overlay_s->drain_count, ==, 1); ++ ++ do_drain_end(BDRV_DRAIN, base); ++ ++ g_assert_cmpint(base->quiesce_counter, ==, 0); ++ g_assert_cmpint(base_s->drain_count, ==, 0); ++ g_assert_cmpint(overlay->quiesce_counter, ==, 0); ++ g_assert_cmpint(overlay_s->drain_count, ==, 0); ++ ++ bdrv_unref(base); ++ blk_unref(blk); ++} ++ + int main(int argc, char **argv) + { + int ret; +@@ -1303,6 +1344,8 @@ int main(int argc, char **argv) + g_test_add_func("/bdrv-drain/detach/parent_cb", test_detach_by_parent_cb); + g_test_add_func("/bdrv-drain/detach/driver_cb", test_detach_by_driver_cb); + ++ g_test_add_func("/bdrv-drain/attach/drain", test_append_to_drained); ++ + ret = g_test_run(); + qemu_event_destroy(&done_event); + return ret; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-test-bdrv-drain-Test-draining-job-source-child-and-p.patch b/SOURCES/kvm-test-bdrv-drain-Test-draining-job-source-child-and-p.patch new file mode 100644 index 0000000..1266558 --- /dev/null +++ b/SOURCES/kvm-test-bdrv-drain-Test-draining-job-source-child-and-p.patch @@ -0,0 +1,185 @@ +From 36cd4342651561d7dda8bccc0520a35ca505c466 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 21 Sep 2018 12:46:30 +0200 +Subject: [PATCH 3/3] test-bdrv-drain: Test draining job source child and + parent + +RH-Author: Kevin Wolf +Message-id: <20180921124630.29036-4-kwolf@redhat.com> +Patchwork-id: 82233 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 3/3] test-bdrv-drain: Test draining job source child and parent +Bugzilla: 1618584 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Paolo Bonzini +RH-Acked-by: John Snow + +For the block job drain test, don't only test draining the source and +the target node, but create a backing chain for the source +(source_backing <- source <- source_overlay) and test draining each of +the nodes in it. + +When using iothreads, the source node (and therefore the job) is in a +different AioContext than the drain, which happens from the main +thread. This way, the main thread waits in AIO_WAIT_WHILE() for the +iothread to make process and aio_wait_kick() is required to notify it. +The test validates that calling bdrv_wakeup() for a child or a parent +node will actually notify AIO_WAIT_WHILE() instead of letting it hang. + +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/test-bdrv-drain.c | 77 ++++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 69 insertions(+), 8 deletions(-) + +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index 7e7ba9b..8641b54 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -786,6 +786,7 @@ typedef struct TestBlockJob { + BlockJob common; + int run_ret; + int prepare_ret; ++ bool running; + bool should_complete; + } TestBlockJob; + +@@ -818,12 +819,17 @@ static int coroutine_fn test_job_run(Job *job, Error **errp) + { + TestBlockJob *s = container_of(job, TestBlockJob, common.job); + ++ /* We are running the actual job code past the pause point in ++ * job_co_entry(). */ ++ s->running = true; ++ + job_transition_to_ready(&s->common.job); + while (!s->should_complete) { + /* Avoid job_sleep_ns() because it marks the job as !busy. We want to + * emulate some actual activity (probably some I/O) here so that drain + * has to wait for this activity to stop. */ +- qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000); ++ qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 1000000); ++ + job_pause_point(&s->common.job); + } + +@@ -856,11 +862,19 @@ enum test_job_result { + TEST_JOB_FAIL_PREPARE, + }; + +-static void test_blockjob_common(enum drain_type drain_type, bool use_iothread, +- enum test_job_result result) ++enum test_job_drain_node { ++ TEST_JOB_DRAIN_SRC, ++ TEST_JOB_DRAIN_SRC_CHILD, ++ TEST_JOB_DRAIN_SRC_PARENT, ++}; ++ ++static void test_blockjob_common_drain_node(enum drain_type drain_type, ++ bool use_iothread, ++ enum test_job_result result, ++ enum test_job_drain_node drain_node) + { + BlockBackend *blk_src, *blk_target; +- BlockDriverState *src, *target; ++ BlockDriverState *src, *src_backing, *src_overlay, *target, *drain_bs; + BlockJob *job; + TestBlockJob *tjob; + IOThread *iothread = NULL; +@@ -869,8 +883,32 @@ static void test_blockjob_common(enum drain_type drain_type, bool use_iothread, + + src = bdrv_new_open_driver(&bdrv_test, "source", BDRV_O_RDWR, + &error_abort); ++ src_backing = bdrv_new_open_driver(&bdrv_test, "source-backing", ++ BDRV_O_RDWR, &error_abort); ++ src_overlay = bdrv_new_open_driver(&bdrv_test, "source-overlay", ++ BDRV_O_RDWR, &error_abort); ++ ++ bdrv_set_backing_hd(src_overlay, src, &error_abort); ++ bdrv_unref(src); ++ bdrv_set_backing_hd(src, src_backing, &error_abort); ++ bdrv_unref(src_backing); ++ + blk_src = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); +- blk_insert_bs(blk_src, src, &error_abort); ++ blk_insert_bs(blk_src, src_overlay, &error_abort); ++ ++ switch (drain_node) { ++ case TEST_JOB_DRAIN_SRC: ++ drain_bs = src; ++ break; ++ case TEST_JOB_DRAIN_SRC_CHILD: ++ drain_bs = src_backing; ++ break; ++ case TEST_JOB_DRAIN_SRC_PARENT: ++ drain_bs = src_overlay; ++ break; ++ default: ++ g_assert_not_reached(); ++ } + + if (use_iothread) { + iothread = iothread_new(); +@@ -906,11 +944,21 @@ static void test_blockjob_common(enum drain_type drain_type, bool use_iothread, + job_start(&job->job); + aio_context_release(ctx); + ++ if (use_iothread) { ++ /* job_co_entry() is run in the I/O thread, wait for the actual job ++ * code to start (we don't want to catch the job in the pause point in ++ * job_co_entry(). */ ++ while (!tjob->running) { ++ aio_poll(qemu_get_aio_context(), false); ++ } ++ } ++ + g_assert_cmpint(job->job.pause_count, ==, 0); + g_assert_false(job->job.paused); ++ g_assert_true(tjob->running); + g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */ + +- do_drain_begin_unlocked(drain_type, src); ++ do_drain_begin_unlocked(drain_type, drain_bs); + + if (drain_type == BDRV_DRAIN_ALL) { + /* bdrv_drain_all() drains both src and target */ +@@ -921,7 +969,7 @@ static void test_blockjob_common(enum drain_type drain_type, bool use_iothread, + g_assert_true(job->job.paused); + g_assert_false(job->job.busy); /* The job is paused */ + +- do_drain_end_unlocked(drain_type, src); ++ do_drain_end_unlocked(drain_type, drain_bs); + + if (use_iothread) { + /* paused is reset in the I/O thread, wait for it */ +@@ -969,7 +1017,7 @@ static void test_blockjob_common(enum drain_type drain_type, bool use_iothread, + + blk_unref(blk_src); + blk_unref(blk_target); +- bdrv_unref(src); ++ bdrv_unref(src_overlay); + bdrv_unref(target); + + if (iothread) { +@@ -977,6 +1025,19 @@ static void test_blockjob_common(enum drain_type drain_type, bool use_iothread, + } + } + ++static void test_blockjob_common(enum drain_type drain_type, bool use_iothread, ++ enum test_job_result result) ++{ ++ test_blockjob_common_drain_node(drain_type, use_iothread, result, ++ TEST_JOB_DRAIN_SRC); ++ test_blockjob_common_drain_node(drain_type, use_iothread, result, ++ TEST_JOB_DRAIN_SRC_CHILD); ++ if (drain_type == BDRV_SUBTREE_DRAIN) { ++ test_blockjob_common_drain_node(drain_type, use_iothread, result, ++ TEST_JOB_DRAIN_SRC_PARENT); ++ } ++} ++ + static void test_blockjob_drain_all(void) + { + test_blockjob_common(BDRV_DRAIN_ALL, false, TEST_JOB_SUCCESS); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-test-bdrv-drain-Test-graph-changes-in-drain_all-sect.patch b/SOURCES/kvm-test-bdrv-drain-Test-graph-changes-in-drain_all-sect.patch new file mode 100644 index 0000000..72f2039 --- /dev/null +++ b/SOURCES/kvm-test-bdrv-drain-Test-graph-changes-in-drain_all-sect.patch @@ -0,0 +1,151 @@ +From d6a8d5cf2b3c225eeb8e6deed9103baf638982dd Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:18 +0200 +Subject: [PATCH 27/49] test-bdrv-drain: Test graph changes in drain_all + section + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-21-kwolf@redhat.com> +Patchwork-id: 82172 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 20/42] test-bdrv-drain: Test graph changes in drain_all section +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This tests both adding and remove a node between bdrv_drain_all_begin() +and bdrv_drain_all_end(), and enabled the existing detach test for +drain_all. + +Signed-off-by: Kevin Wolf +(cherry picked from commit 19f7a7e574a099dca13120441fbe723cea9c1dc2) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/test-bdrv-drain.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 73 insertions(+), 2 deletions(-) + +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index c4aa913..1c8162f 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -452,7 +452,7 @@ static void test_multiparent(void) + blk_unref(blk_b); + } + +-static void test_graph_change(void) ++static void test_graph_change_drain_subtree(void) + { + BlockBackend *blk_a, *blk_b; + BlockDriverState *bs_a, *bs_b, *backing; +@@ -531,6 +531,63 @@ static void test_graph_change(void) + blk_unref(blk_b); + } + ++static void test_graph_change_drain_all(void) ++{ ++ BlockBackend *blk_a, *blk_b; ++ BlockDriverState *bs_a, *bs_b; ++ BDRVTestState *a_s, *b_s; ++ ++ /* Create node A with a BlockBackend */ ++ blk_a = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); ++ bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR, ++ &error_abort); ++ a_s = bs_a->opaque; ++ blk_insert_bs(blk_a, bs_a, &error_abort); ++ ++ g_assert_cmpint(bs_a->quiesce_counter, ==, 0); ++ g_assert_cmpint(a_s->drain_count, ==, 0); ++ ++ /* Call bdrv_drain_all_begin() */ ++ bdrv_drain_all_begin(); ++ ++ g_assert_cmpint(bs_a->quiesce_counter, ==, 1); ++ g_assert_cmpint(a_s->drain_count, ==, 1); ++ ++ /* Create node B with a BlockBackend */ ++ blk_b = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); ++ bs_b = bdrv_new_open_driver(&bdrv_test, "test-node-b", BDRV_O_RDWR, ++ &error_abort); ++ b_s = bs_b->opaque; ++ blk_insert_bs(blk_b, bs_b, &error_abort); ++ ++ g_assert_cmpint(bs_a->quiesce_counter, ==, 1); ++ g_assert_cmpint(bs_b->quiesce_counter, ==, 1); ++ g_assert_cmpint(a_s->drain_count, ==, 1); ++ g_assert_cmpint(b_s->drain_count, ==, 1); ++ ++ /* Unref and finally delete node A */ ++ blk_unref(blk_a); ++ ++ g_assert_cmpint(bs_a->quiesce_counter, ==, 1); ++ g_assert_cmpint(bs_b->quiesce_counter, ==, 1); ++ g_assert_cmpint(a_s->drain_count, ==, 1); ++ g_assert_cmpint(b_s->drain_count, ==, 1); ++ ++ bdrv_unref(bs_a); ++ ++ g_assert_cmpint(bs_b->quiesce_counter, ==, 1); ++ g_assert_cmpint(b_s->drain_count, ==, 1); ++ ++ /* End the drained section */ ++ bdrv_drain_all_end(); ++ ++ g_assert_cmpint(bs_b->quiesce_counter, ==, 0); ++ g_assert_cmpint(b_s->drain_count, ==, 0); ++ ++ bdrv_unref(bs_b); ++ blk_unref(blk_b); ++} ++ + struct test_iothread_data { + BlockDriverState *bs; + enum drain_type drain_type; +@@ -966,6 +1023,10 @@ static void do_test_delete_by_drain(bool detach_instead_of_delete, + bdrv_subtree_drained_begin(bs); + bdrv_subtree_drained_end(bs); + break; ++ case BDRV_DRAIN_ALL: ++ bdrv_drain_all_begin(); ++ bdrv_drain_all_end(); ++ break; + default: + g_assert_not_reached(); + } +@@ -986,6 +1047,11 @@ static void test_delete_by_drain(void) + do_test_delete_by_drain(false, BDRV_DRAIN); + } + ++static void test_detach_by_drain_all(void) ++{ ++ do_test_delete_by_drain(true, BDRV_DRAIN_ALL); ++} ++ + static void test_detach_by_drain(void) + { + do_test_delete_by_drain(true, BDRV_DRAIN); +@@ -1214,7 +1280,11 @@ int main(int argc, char **argv) + + g_test_add_func("/bdrv-drain/nested", test_nested); + g_test_add_func("/bdrv-drain/multiparent", test_multiparent); +- g_test_add_func("/bdrv-drain/graph-change", test_graph_change); ++ ++ g_test_add_func("/bdrv-drain/graph-change/drain_subtree", ++ test_graph_change_drain_subtree); ++ g_test_add_func("/bdrv-drain/graph-change/drain_all", ++ test_graph_change_drain_all); + + g_test_add_func("/bdrv-drain/iothread/drain_all", test_iothread_drain_all); + g_test_add_func("/bdrv-drain/iothread/drain", test_iothread_drain); +@@ -1227,6 +1297,7 @@ int main(int argc, char **argv) + test_blockjob_drain_subtree); + + g_test_add_func("/bdrv-drain/deletion/drain", test_delete_by_drain); ++ g_test_add_func("/bdrv-drain/detach/drain_all", test_detach_by_drain_all); + g_test_add_func("/bdrv-drain/detach/drain", test_detach_by_drain); + g_test_add_func("/bdrv-drain/detach/drain_subtree", test_detach_by_drain_subtree); + g_test_add_func("/bdrv-drain/detach/parent_cb", test_detach_by_parent_cb); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-test-bdrv-drain-Test-nested-poll-in-bdrv_drain_poll_.patch b/SOURCES/kvm-test-bdrv-drain-Test-nested-poll-in-bdrv_drain_poll_.patch new file mode 100644 index 0000000..0b45207 --- /dev/null +++ b/SOURCES/kvm-test-bdrv-drain-Test-nested-poll-in-bdrv_drain_poll_.patch @@ -0,0 +1,62 @@ +From 8c657cb165e931b4eb6f3675495240437b0c1cb1 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:38 +0200 +Subject: [PATCH 47/49] test-bdrv-drain: Test nested poll in + bdrv_drain_poll_top_level() + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-41-kwolf@redhat.com> +Patchwork-id: 82189 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 40/42] test-bdrv-drain: Test nested poll in bdrv_drain_poll_top_level() +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This is a regression test for a deadlock that could occur in callbacks +called from the aio_poll() in bdrv_drain_poll_top_level(). The +AioContext lock wasn't released and therefore would be taken a second +time in the callback. This would cause a possible AIO_WAIT_WHILE() in +the callback to hang. + +Signed-off-by: Kevin Wolf +Reviewed-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + tests/test-bdrv-drain.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index 05f3b55..f4b57f7 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -636,6 +636,17 @@ static void test_iothread_aio_cb(void *opaque, int ret) + qemu_event_set(&done_event); + } + ++static void test_iothread_main_thread_bh(void *opaque) ++{ ++ struct test_iothread_data *data = opaque; ++ ++ /* Test that the AioContext is not yet locked in a random BH that is ++ * executed during drain, otherwise this would deadlock. */ ++ aio_context_acquire(bdrv_get_aio_context(data->bs)); ++ bdrv_flush(data->bs); ++ aio_context_release(bdrv_get_aio_context(data->bs)); ++} ++ + /* + * Starts an AIO request on a BDS that runs in the AioContext of iothread 1. + * The request involves a BH on iothread 2 before it can complete. +@@ -705,6 +716,8 @@ static void test_iothread_common(enum drain_type drain_type, int drain_thread) + aio_context_acquire(ctx_a); + } + ++ aio_bh_schedule_oneshot(ctx_a, test_iothread_main_thread_bh, &data); ++ + /* The request is running on the IOThread a. Draining its block device + * will make sure that it has completed as far as the BDS is concerned, + * but the drain in this thread can continue immediately after +-- +1.8.3.1 + diff --git a/SOURCES/kvm-test-bdrv-drain-Test-node-deletion-in-subtree-recurs.patch b/SOURCES/kvm-test-bdrv-drain-Test-node-deletion-in-subtree-recurs.patch new file mode 100644 index 0000000..023ea3e --- /dev/null +++ b/SOURCES/kvm-test-bdrv-drain-Test-node-deletion-in-subtree-recurs.patch @@ -0,0 +1,106 @@ +From 7a587bf1f9cac772532a41e31202fd7ef8646928 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:09 +0200 +Subject: [PATCH 18/49] test-bdrv-drain: Test node deletion in subtree + recursion + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-12-kwolf@redhat.com> +Patchwork-id: 82159 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 11/42] test-bdrv-drain: Test node deletion in subtree recursion +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +If bdrv_do_drained_begin() polls during its subtree recursion, the graph +can change and mess up the bs->children iteration. Test that this +doesn't happen. + +Signed-off-by: Kevin Wolf +(cherry picked from commit ebd31837618cdc7bda83090773dcdd87475d55b7) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/test-bdrv-drain.c | 38 +++++++++++++++++++++++++++++--------- + 1 file changed, 29 insertions(+), 9 deletions(-) + +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index 8918a94..38706b0 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -875,7 +875,8 @@ static void coroutine_fn test_co_delete_by_drain(void *opaque) + * If @detach_instead_of_delete is set, the BDS is not going to be + * deleted but will only detach all of its children. + */ +-static void do_test_delete_by_drain(bool detach_instead_of_delete) ++static void do_test_delete_by_drain(bool detach_instead_of_delete, ++ enum drain_type drain_type) + { + BlockBackend *blk; + BlockDriverState *bs, *child_bs, *null_bs; +@@ -931,9 +932,23 @@ static void do_test_delete_by_drain(bool detach_instead_of_delete) + * test_co_delete_by_drain() resuming. Thus, @bs will be deleted + * and the coroutine will exit while this drain operation is still + * in progress. */ +- bdrv_ref(child_bs); +- bdrv_drain(child_bs); +- bdrv_unref(child_bs); ++ switch (drain_type) { ++ case BDRV_DRAIN: ++ bdrv_ref(child_bs); ++ bdrv_drain(child_bs); ++ bdrv_unref(child_bs); ++ break; ++ case BDRV_SUBTREE_DRAIN: ++ /* Would have to ref/unref bs here for !detach_instead_of_delete, but ++ * then the whole test becomes pointless because the graph changes ++ * don't occur during the drain any more. */ ++ assert(detach_instead_of_delete); ++ bdrv_subtree_drained_begin(bs); ++ bdrv_subtree_drained_end(bs); ++ break; ++ default: ++ g_assert_not_reached(); ++ } + + while (!dbdd.done) { + aio_poll(qemu_get_aio_context(), true); +@@ -946,15 +961,19 @@ static void do_test_delete_by_drain(bool detach_instead_of_delete) + } + } + +- + static void test_delete_by_drain(void) + { +- do_test_delete_by_drain(false); ++ do_test_delete_by_drain(false, BDRV_DRAIN); + } + + static void test_detach_by_drain(void) + { +- do_test_delete_by_drain(true); ++ do_test_delete_by_drain(true, BDRV_DRAIN); ++} ++ ++static void test_detach_by_drain_subtree(void) ++{ ++ do_test_delete_by_drain(true, BDRV_SUBTREE_DRAIN); + } + + +@@ -1005,8 +1024,9 @@ int main(int argc, char **argv) + g_test_add_func("/bdrv-drain/blockjob/drain_subtree", + test_blockjob_drain_subtree); + +- g_test_add_func("/bdrv-drain/deletion", test_delete_by_drain); +- g_test_add_func("/bdrv-drain/detach", test_detach_by_drain); ++ g_test_add_func("/bdrv-drain/deletion/drain", test_delete_by_drain); ++ g_test_add_func("/bdrv-drain/detach/drain", test_detach_by_drain); ++ g_test_add_func("/bdrv-drain/detach/drain_subtree", test_detach_by_drain_subtree); + + ret = g_test_run(); + qemu_event_destroy(&done_event); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-test-bdrv-drain-Test-that-bdrv_drain_invoke-doesn-t-.patch b/SOURCES/kvm-test-bdrv-drain-Test-that-bdrv_drain_invoke-doesn-t-.patch new file mode 100644 index 0000000..43255ea --- /dev/null +++ b/SOURCES/kvm-test-bdrv-drain-Test-that-bdrv_drain_invoke-doesn-t-.patch @@ -0,0 +1,252 @@ +From eae61f64dccec3d6e32a7ba8d934da629fdd8595 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:13 +0200 +Subject: [PATCH 22/49] test-bdrv-drain: Test that bdrv_drain_invoke() doesn't + poll + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-16-kwolf@redhat.com> +Patchwork-id: 82167 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 15/42] test-bdrv-drain: Test that bdrv_drain_invoke() doesn't poll +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +This adds a test case that goes wrong if bdrv_drain_invoke() calls +aio_poll(). + +Signed-off-by: Kevin Wolf +(cherry picked from commit 57320ca961c2e8488e1884b4ebbcb929b6901dc6) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/test-bdrv-drain.c | 102 +++++++++++++++++++++++++++++++++++++++++------- + 1 file changed, 88 insertions(+), 14 deletions(-) + +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index f786326..c4aa913 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -34,12 +34,16 @@ static QemuEvent done_event; + typedef struct BDRVTestState { + int drain_count; + AioContext *bh_indirection_ctx; ++ bool sleep_in_drain_begin; + } BDRVTestState; + + static void coroutine_fn bdrv_test_co_drain_begin(BlockDriverState *bs) + { + BDRVTestState *s = bs->opaque; + s->drain_count++; ++ if (s->sleep_in_drain_begin) { ++ qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000); ++ } + } + + static void coroutine_fn bdrv_test_co_drain_end(BlockDriverState *bs) +@@ -80,6 +84,22 @@ static int coroutine_fn bdrv_test_co_preadv(BlockDriverState *bs, + return 0; + } + ++static void bdrv_test_child_perm(BlockDriverState *bs, BdrvChild *c, ++ const BdrvChildRole *role, ++ BlockReopenQueue *reopen_queue, ++ uint64_t perm, uint64_t shared, ++ uint64_t *nperm, uint64_t *nshared) ++{ ++ /* bdrv_format_default_perms() accepts only these two, so disguise ++ * detach_by_driver_cb_role as one of them. */ ++ if (role != &child_file && role != &child_backing) { ++ role = &child_file; ++ } ++ ++ bdrv_format_default_perms(bs, c, role, reopen_queue, perm, shared, ++ nperm, nshared); ++} ++ + static BlockDriver bdrv_test = { + .format_name = "test", + .instance_size = sizeof(BDRVTestState), +@@ -90,7 +110,7 @@ static BlockDriver bdrv_test = { + .bdrv_co_drain_begin = bdrv_test_co_drain_begin, + .bdrv_co_drain_end = bdrv_test_co_drain_end, + +- .bdrv_child_perm = bdrv_format_default_perms, ++ .bdrv_child_perm = bdrv_test_child_perm, + }; + + static void aio_ret_cb(void *opaque, int ret) +@@ -982,13 +1002,14 @@ struct detach_by_parent_data { + BdrvChild *child_b; + BlockDriverState *c; + BdrvChild *child_c; ++ bool by_parent_cb; + }; ++static struct detach_by_parent_data detach_by_parent_data; + +-static void detach_by_parent_aio_cb(void *opaque, int ret) ++static void detach_indirect_bh(void *opaque) + { + struct detach_by_parent_data *data = opaque; + +- g_assert_cmpint(ret, ==, 0); + bdrv_unref_child(data->parent_b, data->child_b); + + bdrv_ref(data->c); +@@ -996,6 +1017,25 @@ static void detach_by_parent_aio_cb(void *opaque, int ret) + &child_file, &error_abort); + } + ++static void detach_by_parent_aio_cb(void *opaque, int ret) ++{ ++ struct detach_by_parent_data *data = &detach_by_parent_data; ++ ++ g_assert_cmpint(ret, ==, 0); ++ if (data->by_parent_cb) { ++ detach_indirect_bh(data); ++ } ++} ++ ++static void detach_by_driver_cb_drained_begin(BdrvChild *child) ++{ ++ aio_bh_schedule_oneshot(qemu_get_current_aio_context(), ++ detach_indirect_bh, &detach_by_parent_data); ++ child_file.drained_begin(child); ++} ++ ++static BdrvChildRole detach_by_driver_cb_role; ++ + /* + * Initial graph: + * +@@ -1003,17 +1043,25 @@ static void detach_by_parent_aio_cb(void *opaque, int ret) + * \ / \ + * A B C + * +- * PA has a pending write request whose callback changes the child nodes of PB: +- * It removes B and adds C instead. The subtree of PB is drained, which will +- * indirectly drain the write request, too. ++ * by_parent_cb == true: Test that parent callbacks don't poll ++ * ++ * PA has a pending write request whose callback changes the child nodes of ++ * PB: It removes B and adds C instead. The subtree of PB is drained, which ++ * will indirectly drain the write request, too. ++ * ++ * by_parent_cb == false: Test that bdrv_drain_invoke() doesn't poll ++ * ++ * PA's BdrvChildRole has a .drained_begin callback that schedules a BH ++ * that does the same graph change. If bdrv_drain_invoke() calls it, the ++ * state is messed up, but if it is only polled in the single ++ * BDRV_POLL_WHILE() at the end of the drain, this should work fine. + */ +-static void test_detach_by_parent_cb(void) ++static void test_detach_indirect(bool by_parent_cb) + { + BlockBackend *blk; + BlockDriverState *parent_a, *parent_b, *a, *b, *c; + BdrvChild *child_a, *child_b; + BlockAIOCB *acb; +- struct detach_by_parent_data data; + + QEMUIOVector qiov; + struct iovec iov = { +@@ -1022,6 +1070,12 @@ static void test_detach_by_parent_cb(void) + }; + qemu_iovec_init_external(&qiov, &iov, 1); + ++ if (!by_parent_cb) { ++ detach_by_driver_cb_role = child_file; ++ detach_by_driver_cb_role.drained_begin = ++ detach_by_driver_cb_drained_begin; ++ } ++ + /* Create all involved nodes */ + parent_a = bdrv_new_open_driver(&bdrv_test, "parent-a", BDRV_O_RDWR, + &error_abort); +@@ -1037,6 +1091,13 @@ static void test_detach_by_parent_cb(void) + blk_insert_bs(blk, parent_a, &error_abort); + bdrv_unref(parent_a); + ++ /* If we want to get bdrv_drain_invoke() to call aio_poll(), the driver ++ * callback must not return immediately. */ ++ if (!by_parent_cb) { ++ BDRVTestState *s = parent_a->opaque; ++ s->sleep_in_drain_begin = true; ++ } ++ + /* Set child relationships */ + bdrv_ref(b); + bdrv_ref(a); +@@ -1044,7 +1105,9 @@ static void test_detach_by_parent_cb(void) + child_a = bdrv_attach_child(parent_b, a, "PB-A", &child_backing, &error_abort); + + bdrv_ref(a); +- bdrv_attach_child(parent_a, a, "PA-A", &child_file, &error_abort); ++ bdrv_attach_child(parent_a, a, "PA-A", ++ by_parent_cb ? &child_file : &detach_by_driver_cb_role, ++ &error_abort); + + g_assert_cmpint(parent_a->refcnt, ==, 1); + g_assert_cmpint(parent_b->refcnt, ==, 1); +@@ -1057,18 +1120,19 @@ static void test_detach_by_parent_cb(void) + g_assert(QLIST_NEXT(child_b, next) == NULL); + + /* Start the evil write request */ +- data = (struct detach_by_parent_data) { ++ detach_by_parent_data = (struct detach_by_parent_data) { + .parent_b = parent_b, + .child_b = child_b, + .c = c, ++ .by_parent_cb = by_parent_cb, + }; +- acb = blk_aio_preadv(blk, 0, &qiov, 0, detach_by_parent_aio_cb, &data); ++ acb = blk_aio_preadv(blk, 0, &qiov, 0, detach_by_parent_aio_cb, NULL); + g_assert(acb != NULL); + + /* Drain and check the expected result */ + bdrv_subtree_drained_begin(parent_b); + +- g_assert(data.child_c != NULL); ++ g_assert(detach_by_parent_data.child_c != NULL); + + g_assert_cmpint(parent_a->refcnt, ==, 1); + g_assert_cmpint(parent_b->refcnt, ==, 1); +@@ -1076,8 +1140,8 @@ static void test_detach_by_parent_cb(void) + g_assert_cmpint(b->refcnt, ==, 1); + g_assert_cmpint(c->refcnt, ==, 2); + +- g_assert(QLIST_FIRST(&parent_b->children) == data.child_c); +- g_assert(QLIST_NEXT(data.child_c, next) == child_a); ++ g_assert(QLIST_FIRST(&parent_b->children) == detach_by_parent_data.child_c); ++ g_assert(QLIST_NEXT(detach_by_parent_data.child_c, next) == child_a); + g_assert(QLIST_NEXT(child_a, next) == NULL); + + g_assert_cmpint(parent_a->quiesce_counter, ==, 1); +@@ -1105,6 +1169,15 @@ static void test_detach_by_parent_cb(void) + bdrv_unref(c); + } + ++static void test_detach_by_parent_cb(void) ++{ ++ test_detach_indirect(true); ++} ++ ++static void test_detach_by_driver_cb(void) ++{ ++ test_detach_indirect(false); ++} + + int main(int argc, char **argv) + { +@@ -1157,6 +1230,7 @@ int main(int argc, char **argv) + g_test_add_func("/bdrv-drain/detach/drain", test_detach_by_drain); + g_test_add_func("/bdrv-drain/detach/drain_subtree", test_detach_by_drain_subtree); + g_test_add_func("/bdrv-drain/detach/parent_cb", test_detach_by_parent_cb); ++ g_test_add_func("/bdrv-drain/detach/driver_cb", test_detach_by_driver_cb); + + ret = g_test_run(); + qemu_event_destroy(&done_event); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-test-bdrv-drain-bdrv_drain-works-with-cross-AioConte.patch b/SOURCES/kvm-test-bdrv-drain-bdrv_drain-works-with-cross-AioConte.patch new file mode 100644 index 0000000..fb6ca25 --- /dev/null +++ b/SOURCES/kvm-test-bdrv-drain-bdrv_drain-works-with-cross-AioConte.patch @@ -0,0 +1,297 @@ +From 6ad2df3cb4ec0fbabc5d3e1beab138a071415bba Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:54:59 +0200 +Subject: [PATCH 08/49] test-bdrv-drain: bdrv_drain() works with + cross-AioContext events + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-2-kwolf@redhat.com> +Patchwork-id: 82152 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 01/42] test-bdrv-drain: bdrv_drain() works with cross-AioContext events +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +As long as nobody keeps the other I/O thread from working, there is no +reason why bdrv_drain() wouldn't work with cross-AioContext events. The +key is that the root request we're waiting for is in the AioContext +we're polling (which it always is for bdrv_drain()) so that aio_poll() +is woken up in the end. + +Add a test case that shows that it works. Remove the comment in +bdrv_drain() that claims otherwise. + +Signed-off-by: Kevin Wolf +(cherry picked from commit bb6756895459f181e2f25e877d3d7a10c297b5c8) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/io.c | 4 -- + tests/test-bdrv-drain.c | 187 +++++++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 186 insertions(+), 5 deletions(-) + +diff --git a/block/io.c b/block/io.c +index bb617de..7e0a169 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -369,10 +369,6 @@ void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent) + * + * Note that unlike bdrv_drain_all(), the caller must hold the BlockDriverState + * AioContext. +- * +- * Only this BlockDriverState's AioContext is run, so in-flight requests must +- * not depend on events in other AioContexts. In that case, use +- * bdrv_drain_all() instead. + */ + void coroutine_fn bdrv_co_drain(BlockDriverState *bs) + { +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index 403446e..dee0a10 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -27,9 +27,13 @@ + #include "block/blockjob_int.h" + #include "sysemu/block-backend.h" + #include "qapi/error.h" ++#include "iothread.h" ++ ++static QemuEvent done_event; + + typedef struct BDRVTestState { + int drain_count; ++ AioContext *bh_indirection_ctx; + } BDRVTestState; + + static void coroutine_fn bdrv_test_co_drain_begin(BlockDriverState *bs) +@@ -50,16 +54,29 @@ static void bdrv_test_close(BlockDriverState *bs) + g_assert_cmpint(s->drain_count, >, 0); + } + ++static void co_reenter_bh(void *opaque) ++{ ++ aio_co_wake(opaque); ++} ++ + static int coroutine_fn bdrv_test_co_preadv(BlockDriverState *bs, + uint64_t offset, uint64_t bytes, + QEMUIOVector *qiov, int flags) + { ++ BDRVTestState *s = bs->opaque; ++ + /* We want this request to stay until the polling loop in drain waits for + * it to complete. We need to sleep a while as bdrv_drain_invoke() comes + * first and polls its result, too, but it shouldn't accidentally complete + * this request yet. */ + qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000); + ++ if (s->bh_indirection_ctx) { ++ aio_bh_schedule_oneshot(s->bh_indirection_ctx, co_reenter_bh, ++ qemu_coroutine_self()); ++ qemu_coroutine_yield(); ++ } ++ + return 0; + } + +@@ -490,6 +507,164 @@ static void test_graph_change(void) + blk_unref(blk_b); + } + ++struct test_iothread_data { ++ BlockDriverState *bs; ++ enum drain_type drain_type; ++ int *aio_ret; ++}; ++ ++static void test_iothread_drain_entry(void *opaque) ++{ ++ struct test_iothread_data *data = opaque; ++ ++ aio_context_acquire(bdrv_get_aio_context(data->bs)); ++ do_drain_begin(data->drain_type, data->bs); ++ g_assert_cmpint(*data->aio_ret, ==, 0); ++ do_drain_end(data->drain_type, data->bs); ++ aio_context_release(bdrv_get_aio_context(data->bs)); ++ ++ qemu_event_set(&done_event); ++} ++ ++static void test_iothread_aio_cb(void *opaque, int ret) ++{ ++ int *aio_ret = opaque; ++ *aio_ret = ret; ++ qemu_event_set(&done_event); ++} ++ ++/* ++ * Starts an AIO request on a BDS that runs in the AioContext of iothread 1. ++ * The request involves a BH on iothread 2 before it can complete. ++ * ++ * @drain_thread = 0 means that do_drain_begin/end are called from the main ++ * thread, @drain_thread = 1 means that they are called from iothread 1. Drain ++ * for this BDS cannot be called from iothread 2 because only the main thread ++ * may do cross-AioContext polling. ++ */ ++static void test_iothread_common(enum drain_type drain_type, int drain_thread) ++{ ++ BlockBackend *blk; ++ BlockDriverState *bs; ++ BDRVTestState *s; ++ BlockAIOCB *acb; ++ int aio_ret; ++ struct test_iothread_data data; ++ ++ IOThread *a = iothread_new(); ++ IOThread *b = iothread_new(); ++ AioContext *ctx_a = iothread_get_aio_context(a); ++ AioContext *ctx_b = iothread_get_aio_context(b); ++ ++ QEMUIOVector qiov; ++ struct iovec iov = { ++ .iov_base = NULL, ++ .iov_len = 0, ++ }; ++ qemu_iovec_init_external(&qiov, &iov, 1); ++ ++ /* bdrv_drain_all() may only be called from the main loop thread */ ++ if (drain_type == BDRV_DRAIN_ALL && drain_thread != 0) { ++ goto out; ++ } ++ ++ blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); ++ bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR, ++ &error_abort); ++ s = bs->opaque; ++ blk_insert_bs(blk, bs, &error_abort); ++ ++ blk_set_aio_context(blk, ctx_a); ++ aio_context_acquire(ctx_a); ++ ++ s->bh_indirection_ctx = ctx_b; ++ ++ aio_ret = -EINPROGRESS; ++ if (drain_thread == 0) { ++ acb = blk_aio_preadv(blk, 0, &qiov, 0, test_iothread_aio_cb, &aio_ret); ++ } else { ++ acb = blk_aio_preadv(blk, 0, &qiov, 0, aio_ret_cb, &aio_ret); ++ } ++ g_assert(acb != NULL); ++ g_assert_cmpint(aio_ret, ==, -EINPROGRESS); ++ ++ aio_context_release(ctx_a); ++ ++ data = (struct test_iothread_data) { ++ .bs = bs, ++ .drain_type = drain_type, ++ .aio_ret = &aio_ret, ++ }; ++ ++ switch (drain_thread) { ++ case 0: ++ if (drain_type != BDRV_DRAIN_ALL) { ++ aio_context_acquire(ctx_a); ++ } ++ ++ /* The request is running on the IOThread a. Draining its block device ++ * will make sure that it has completed as far as the BDS is concerned, ++ * but the drain in this thread can continue immediately after ++ * bdrv_dec_in_flight() and aio_ret might be assigned only slightly ++ * later. */ ++ qemu_event_reset(&done_event); ++ do_drain_begin(drain_type, bs); ++ g_assert_cmpint(bs->in_flight, ==, 0); ++ ++ if (drain_type != BDRV_DRAIN_ALL) { ++ aio_context_release(ctx_a); ++ } ++ qemu_event_wait(&done_event); ++ if (drain_type != BDRV_DRAIN_ALL) { ++ aio_context_acquire(ctx_a); ++ } ++ ++ g_assert_cmpint(aio_ret, ==, 0); ++ do_drain_end(drain_type, bs); ++ ++ if (drain_type != BDRV_DRAIN_ALL) { ++ aio_context_release(ctx_a); ++ } ++ break; ++ case 1: ++ qemu_event_reset(&done_event); ++ aio_bh_schedule_oneshot(ctx_a, test_iothread_drain_entry, &data); ++ qemu_event_wait(&done_event); ++ break; ++ default: ++ g_assert_not_reached(); ++ } ++ ++ aio_context_acquire(ctx_a); ++ blk_set_aio_context(blk, qemu_get_aio_context()); ++ aio_context_release(ctx_a); ++ ++ bdrv_unref(bs); ++ blk_unref(blk); ++ ++out: ++ iothread_join(a); ++ iothread_join(b); ++} ++ ++static void test_iothread_drain_all(void) ++{ ++ test_iothread_common(BDRV_DRAIN_ALL, 0); ++ test_iothread_common(BDRV_DRAIN_ALL, 1); ++} ++ ++static void test_iothread_drain(void) ++{ ++ test_iothread_common(BDRV_DRAIN, 0); ++ test_iothread_common(BDRV_DRAIN, 1); ++} ++ ++static void test_iothread_drain_subtree(void) ++{ ++ test_iothread_common(BDRV_SUBTREE_DRAIN, 0); ++ test_iothread_common(BDRV_SUBTREE_DRAIN, 1); ++} ++ + + typedef struct TestBlockJob { + BlockJob common; +@@ -613,10 +788,13 @@ static void test_blockjob_drain_subtree(void) + + int main(int argc, char **argv) + { ++ int ret; ++ + bdrv_init(); + qemu_init_main_loop(&error_abort); + + g_test_init(&argc, &argv, NULL); ++ qemu_event_init(&done_event, false); + + g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all); + g_test_add_func("/bdrv-drain/driver-cb/drain", test_drv_cb_drain); +@@ -643,10 +821,17 @@ int main(int argc, char **argv) + g_test_add_func("/bdrv-drain/multiparent", test_multiparent); + g_test_add_func("/bdrv-drain/graph-change", test_graph_change); + ++ g_test_add_func("/bdrv-drain/iothread/drain_all", test_iothread_drain_all); ++ g_test_add_func("/bdrv-drain/iothread/drain", test_iothread_drain); ++ g_test_add_func("/bdrv-drain/iothread/drain_subtree", ++ test_iothread_drain_subtree); ++ + g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all); + g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain); + g_test_add_func("/bdrv-drain/blockjob/drain_subtree", + test_blockjob_drain_subtree); + +- return g_test_run(); ++ ret = g_test_run(); ++ qemu_event_destroy(&done_event); ++ return ret; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-test-blockjob-Acquire-AioContext-around-job_cancel_s.patch b/SOURCES/kvm-test-blockjob-Acquire-AioContext-around-job_cancel_s.patch new file mode 100644 index 0000000..2e22827 --- /dev/null +++ b/SOURCES/kvm-test-blockjob-Acquire-AioContext-around-job_cancel_s.patch @@ -0,0 +1,85 @@ +From db5e1dfac375e869234340036cd232313c6d4d7b Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:28 +0200 +Subject: [PATCH 37/49] test-blockjob: Acquire AioContext around + job_cancel_sync() + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-31-kwolf@redhat.com> +Patchwork-id: 82183 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 30/42] test-blockjob: Acquire AioContext around job_cancel_sync() +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +All callers in QEMU proper hold the AioContext lock when calling +job_finish_sync(). test-blockjob should do the same when it calls the +function indirectly through job_cancel_sync(). + +Signed-off-by: Kevin Wolf +Reviewed-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + include/qemu/job.h | 6 ++++++ + tests/test-blockjob.c | 6 ++++++ + 2 files changed, 12 insertions(+) + +diff --git a/include/qemu/job.h b/include/qemu/job.h +index 407d549..35ac7a9 100644 +--- a/include/qemu/job.h ++++ b/include/qemu/job.h +@@ -509,6 +509,8 @@ void job_user_cancel(Job *job, bool force, Error **errp); + * + * Returns the return value from the job if the job actually completed + * during the call, or -ECANCELED if it was canceled. ++ * ++ * Callers must hold the AioContext lock of job->aio_context. + */ + int job_cancel_sync(Job *job); + +@@ -526,6 +528,8 @@ void job_cancel_sync_all(void); + * function). + * + * Returns the return value from the job. ++ * ++ * Callers must hold the AioContext lock of job->aio_context. + */ + int job_complete_sync(Job *job, Error **errp); + +@@ -551,6 +555,8 @@ void job_dismiss(Job **job, Error **errp); + * + * Returns 0 if the job is successfully completed, -ECANCELED if the job was + * cancelled before completing, and -errno in other error cases. ++ * ++ * Callers must hold the AioContext lock of job->aio_context. + */ + int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp); + +diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c +index de4c1c2..652d1e8 100644 +--- a/tests/test-blockjob.c ++++ b/tests/test-blockjob.c +@@ -223,6 +223,10 @@ static void cancel_common(CancelJob *s) + BlockJob *job = &s->common; + BlockBackend *blk = s->blk; + JobStatus sts = job->job.status; ++ AioContext *ctx; ++ ++ ctx = job->job.aio_context; ++ aio_context_acquire(ctx); + + job_cancel_sync(&job->job); + if (sts != JOB_STATUS_CREATED && sts != JOB_STATUS_CONCLUDED) { +@@ -232,6 +236,8 @@ static void cancel_common(CancelJob *s) + assert(job->job.status == JOB_STATUS_NULL); + job_unref(&job->job); + destroy_blk(blk); ++ ++ aio_context_release(ctx); + } + + static void test_cancel_created(void) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-tests-blockjob-replace-Blockjob-with-Job.patch b/SOURCES/kvm-tests-blockjob-replace-Blockjob-with-Job.patch new file mode 100644 index 0000000..fd94af3 --- /dev/null +++ b/SOURCES/kvm-tests-blockjob-replace-Blockjob-with-Job.patch @@ -0,0 +1,233 @@ +From 4003c681cac2102b3c493e2f1a7f9af7e88e0d38 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 10 Sep 2018 18:17:55 +0200 +Subject: [PATCH 17/25] tests/blockjob: replace Blockjob with Job + +RH-Author: John Snow +Message-id: <20180910181803.11781-18-jsnow@redhat.com> +Patchwork-id: 82103 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 17/25] tests/blockjob: replace Blockjob with Job +Bugzilla: 1626061 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +These tests don't actually test blockjobs anymore, they test +generic Job lifetimes. Change the types accordingly. + +Signed-off-by: John Snow +Reviewed-by: Max Reitz +Message-id: 20180906130225.5118-9-jsnow@redhat.com +Reviewed-by: Jeff Cody +Signed-off-by: Max Reitz +(cherry picked from commit 15fcc3513802c74838075048c6f2d9e58780ba06) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/test-blockjob.c | 98 ++++++++++++++++++++++++++------------------------- + 1 file changed, 50 insertions(+), 48 deletions(-) + +diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c +index ad4a65b..8e8b680 100644 +--- a/tests/test-blockjob.c ++++ b/tests/test-blockjob.c +@@ -206,18 +206,20 @@ static const BlockJobDriver test_cancel_driver = { + }, + }; + +-static CancelJob *create_common(BlockJob **pjob) ++static CancelJob *create_common(Job **pjob) + { + BlockBackend *blk; +- BlockJob *job; ++ Job *job; ++ BlockJob *bjob; + CancelJob *s; + + blk = create_blk(NULL); +- job = mk_job(blk, "Steve", &test_cancel_driver, true, +- JOB_MANUAL_FINALIZE | JOB_MANUAL_DISMISS); +- job_ref(&job->job); +- assert(job->job.status == JOB_STATUS_CREATED); +- s = container_of(job, CancelJob, common); ++ bjob = mk_job(blk, "Steve", &test_cancel_driver, true, ++ JOB_MANUAL_FINALIZE | JOB_MANUAL_DISMISS); ++ job = &bjob->job; ++ job_ref(job); ++ assert(job->status == JOB_STATUS_CREATED); ++ s = container_of(bjob, CancelJob, common); + s->blk = blk; + + *pjob = job; +@@ -242,7 +244,7 @@ static void cancel_common(CancelJob *s) + + static void test_cancel_created(void) + { +- BlockJob *job; ++ Job *job; + CancelJob *s; + + s = create_common(&job); +@@ -251,119 +253,119 @@ static void test_cancel_created(void) + + static void test_cancel_running(void) + { +- BlockJob *job; ++ Job *job; + CancelJob *s; + + s = create_common(&job); + +- job_start(&job->job); +- assert(job->job.status == JOB_STATUS_RUNNING); ++ job_start(job); ++ assert(job->status == JOB_STATUS_RUNNING); + + cancel_common(s); + } + + static void test_cancel_paused(void) + { +- BlockJob *job; ++ Job *job; + CancelJob *s; + + s = create_common(&job); + +- job_start(&job->job); +- assert(job->job.status == JOB_STATUS_RUNNING); ++ job_start(job); ++ assert(job->status == JOB_STATUS_RUNNING); + +- job_user_pause(&job->job, &error_abort); +- job_enter(&job->job); +- assert(job->job.status == JOB_STATUS_PAUSED); ++ job_user_pause(job, &error_abort); ++ job_enter(job); ++ assert(job->status == JOB_STATUS_PAUSED); + + cancel_common(s); + } + + static void test_cancel_ready(void) + { +- BlockJob *job; ++ Job *job; + CancelJob *s; + + s = create_common(&job); + +- job_start(&job->job); +- assert(job->job.status == JOB_STATUS_RUNNING); ++ job_start(job); ++ assert(job->status == JOB_STATUS_RUNNING); + + s->should_converge = true; +- job_enter(&job->job); +- assert(job->job.status == JOB_STATUS_READY); ++ job_enter(job); ++ assert(job->status == JOB_STATUS_READY); + + cancel_common(s); + } + + static void test_cancel_standby(void) + { +- BlockJob *job; ++ Job *job; + CancelJob *s; + + s = create_common(&job); + +- job_start(&job->job); +- assert(job->job.status == JOB_STATUS_RUNNING); ++ job_start(job); ++ assert(job->status == JOB_STATUS_RUNNING); + + s->should_converge = true; +- job_enter(&job->job); +- assert(job->job.status == JOB_STATUS_READY); ++ job_enter(job); ++ assert(job->status == JOB_STATUS_READY); + +- job_user_pause(&job->job, &error_abort); +- job_enter(&job->job); +- assert(job->job.status == JOB_STATUS_STANDBY); ++ job_user_pause(job, &error_abort); ++ job_enter(job); ++ assert(job->status == JOB_STATUS_STANDBY); + + cancel_common(s); + } + + static void test_cancel_pending(void) + { +- BlockJob *job; ++ Job *job; + CancelJob *s; + + s = create_common(&job); + +- job_start(&job->job); +- assert(job->job.status == JOB_STATUS_RUNNING); ++ job_start(job); ++ assert(job->status == JOB_STATUS_RUNNING); + + s->should_converge = true; +- job_enter(&job->job); +- assert(job->job.status == JOB_STATUS_READY); ++ job_enter(job); ++ assert(job->status == JOB_STATUS_READY); + +- job_complete(&job->job, &error_abort); +- job_enter(&job->job); ++ job_complete(job, &error_abort); ++ job_enter(job); + while (!s->completed) { + aio_poll(qemu_get_aio_context(), true); + } +- assert(job->job.status == JOB_STATUS_PENDING); ++ assert(job->status == JOB_STATUS_PENDING); + + cancel_common(s); + } + + static void test_cancel_concluded(void) + { +- BlockJob *job; ++ Job *job; + CancelJob *s; + + s = create_common(&job); + +- job_start(&job->job); +- assert(job->job.status == JOB_STATUS_RUNNING); ++ job_start(job); ++ assert(job->status == JOB_STATUS_RUNNING); + + s->should_converge = true; +- job_enter(&job->job); +- assert(job->job.status == JOB_STATUS_READY); ++ job_enter(job); ++ assert(job->status == JOB_STATUS_READY); + +- job_complete(&job->job, &error_abort); +- job_enter(&job->job); ++ job_complete(job, &error_abort); ++ job_enter(job); + while (!s->completed) { + aio_poll(qemu_get_aio_context(), true); + } +- assert(job->job.status == JOB_STATUS_PENDING); ++ assert(job->status == JOB_STATUS_PENDING); + +- job_finalize(&job->job, &error_abort); +- assert(job->job.status == JOB_STATUS_CONCLUDED); ++ job_finalize(job, &error_abort); ++ assert(job->status == JOB_STATUS_CONCLUDED); + + cancel_common(s); + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-tests-test-bdrv-drain-bdrv_drain_all-works-in-corout.patch b/SOURCES/kvm-tests-test-bdrv-drain-bdrv_drain_all-works-in-corout.patch new file mode 100644 index 0000000..b31ed76 --- /dev/null +++ b/SOURCES/kvm-tests-test-bdrv-drain-bdrv_drain_all-works-in-corout.patch @@ -0,0 +1,83 @@ +From 0ace323e4037200dc16bda1d77bbdc4f2711a658 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:03 +0200 +Subject: [PATCH 12/49] tests/test-bdrv-drain: bdrv_drain_all() works in + coroutines now + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-6-kwolf@redhat.com> +Patchwork-id: 82156 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 05/42] tests/test-bdrv-drain: bdrv_drain_all() works in coroutines now +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +Since we use bdrv_do_drained_begin/end() for bdrv_drain_all_begin/end(), +coroutine context is automatically left with a BH, preventing the +deadlocks that made bdrv_drain_all*() unsafe in coroutine context. Now +that we even removed the old polling code as dead code, it's obvious +that it's compatible now. + +Enable the coroutine test cases for bdrv_drain_all(). + +Signed-off-by: Kevin Wolf +Reviewed-by: Stefan Hajnoczi +(cherry picked from commit 6d0252f2f9cb49925deb1c41101462c9481dfc90) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + tests/test-bdrv-drain.c | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c +index f1276a1..f5d85c9 100644 +--- a/tests/test-bdrv-drain.c ++++ b/tests/test-bdrv-drain.c +@@ -233,6 +233,11 @@ static void test_drv_cb_drain_subtree(void) + test_drv_cb_common(BDRV_SUBTREE_DRAIN, true); + } + ++static void test_drv_cb_co_drain_all(void) ++{ ++ call_in_coroutine(test_drv_cb_drain_all); ++} ++ + static void test_drv_cb_co_drain(void) + { + call_in_coroutine(test_drv_cb_drain); +@@ -289,6 +294,11 @@ static void test_quiesce_drain_subtree(void) + test_quiesce_common(BDRV_SUBTREE_DRAIN, true); + } + ++static void test_quiesce_co_drain_all(void) ++{ ++ call_in_coroutine(test_quiesce_drain_all); ++} ++ + static void test_quiesce_co_drain(void) + { + call_in_coroutine(test_quiesce_drain); +@@ -795,7 +805,8 @@ int main(int argc, char **argv) + g_test_add_func("/bdrv-drain/driver-cb/drain_subtree", + test_drv_cb_drain_subtree); + +- // XXX bdrv_drain_all() doesn't work in coroutine context ++ g_test_add_func("/bdrv-drain/driver-cb/co/drain_all", ++ test_drv_cb_co_drain_all); + g_test_add_func("/bdrv-drain/driver-cb/co/drain", test_drv_cb_co_drain); + g_test_add_func("/bdrv-drain/driver-cb/co/drain_subtree", + test_drv_cb_co_drain_subtree); +@@ -806,7 +817,8 @@ int main(int argc, char **argv) + g_test_add_func("/bdrv-drain/quiesce/drain_subtree", + test_quiesce_drain_subtree); + +- // XXX bdrv_drain_all() doesn't work in coroutine context ++ g_test_add_func("/bdrv-drain/quiesce/co/drain_all", ++ test_quiesce_co_drain_all); + g_test_add_func("/bdrv-drain/quiesce/co/drain", test_quiesce_co_drain); + g_test_add_func("/bdrv-drain/quiesce/co/drain_subtree", + test_quiesce_co_drain_subtree); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-tests-test-blockjob-remove-exit-callback.patch b/SOURCES/kvm-tests-test-blockjob-remove-exit-callback.patch new file mode 100644 index 0000000..3273f47 --- /dev/null +++ b/SOURCES/kvm-tests-test-blockjob-remove-exit-callback.patch @@ -0,0 +1,88 @@ +From b7db3ff5fc3664af536364f8274ed4826566b1dd Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 10 Sep 2018 18:17:56 +0200 +Subject: [PATCH 18/25] tests/test-blockjob: remove exit callback + +RH-Author: John Snow +Message-id: <20180910181803.11781-19-jsnow@redhat.com> +Patchwork-id: 82108 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 18/25] tests/test-blockjob: remove exit callback +Bugzilla: 1626061 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +We remove the exit callback and the completed boolean along with it. +We can simulate it just fine by waiting for the job to defer to the +main loop, and then giving it one final kick to get the main loop +portion to run. + +Signed-off-by: John Snow +Reviewed-by: Max Reitz +Message-id: 20180906130225.5118-10-jsnow@redhat.com +Reviewed-by: Jeff Cody +Signed-off-by: Max Reitz +(cherry picked from commit c0345e9d3bd2f3672d481be7514b9ad181878921) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/test-blockjob.c | 16 ++++++---------- + 1 file changed, 6 insertions(+), 10 deletions(-) + +diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c +index 8e8b680..de4c1c2 100644 +--- a/tests/test-blockjob.c ++++ b/tests/test-blockjob.c +@@ -160,15 +160,8 @@ typedef struct CancelJob { + BlockBackend *blk; + bool should_converge; + bool should_complete; +- bool completed; + } CancelJob; + +-static void cancel_job_exit(Job *job) +-{ +- CancelJob *s = container_of(job, CancelJob, common.job); +- s->completed = true; +-} +- + static void cancel_job_complete(Job *job, Error **errp) + { + CancelJob *s = container_of(job, CancelJob, common.job); +@@ -201,7 +194,6 @@ static const BlockJobDriver test_cancel_driver = { + .user_resume = block_job_user_resume, + .drain = block_job_drain, + .run = cancel_job_run, +- .exit = cancel_job_exit, + .complete = cancel_job_complete, + }, + }; +@@ -335,9 +327,11 @@ static void test_cancel_pending(void) + + job_complete(job, &error_abort); + job_enter(job); +- while (!s->completed) { ++ while (!job->deferred_to_main_loop) { + aio_poll(qemu_get_aio_context(), true); + } ++ assert(job->status == JOB_STATUS_READY); ++ aio_poll(qemu_get_aio_context(), true); + assert(job->status == JOB_STATUS_PENDING); + + cancel_common(s); +@@ -359,9 +353,11 @@ static void test_cancel_concluded(void) + + job_complete(job, &error_abort); + job_enter(job); +- while (!s->completed) { ++ while (!job->deferred_to_main_loop) { + aio_poll(qemu_get_aio_context(), true); + } ++ assert(job->status == JOB_STATUS_READY); ++ aio_poll(qemu_get_aio_context(), true); + assert(job->status == JOB_STATUS_PENDING); + + job_finalize(job, &error_abort); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-tests-test-blockjob-txn-move-.exit-to-.clean.patch b/SOURCES/kvm-tests-test-blockjob-txn-move-.exit-to-.clean.patch new file mode 100644 index 0000000..34fe464 --- /dev/null +++ b/SOURCES/kvm-tests-test-blockjob-txn-move-.exit-to-.clean.patch @@ -0,0 +1,53 @@ +From 45cb87c803124a009d401ab959bb4881f84ac4e1 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 10 Sep 2018 18:17:57 +0200 +Subject: [PATCH 19/25] tests/test-blockjob-txn: move .exit to .clean + +RH-Author: John Snow +Message-id: <20180910181803.11781-20-jsnow@redhat.com> +Patchwork-id: 82097 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 19/25] tests/test-blockjob-txn: move .exit to .clean +Bugzilla: 1626061 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Kevin Wolf + +The exit callback in this test actually only performs cleanup. + +Signed-off-by: John Snow +Reviewed-by: Max Reitz +Message-id: 20180906130225.5118-11-jsnow@redhat.com +Reviewed-by: Jeff Cody +Signed-off-by: Max Reitz +(cherry picked from commit d498b2b6d6f5a547593a3123c9ed8967965c0c44) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + tests/test-blockjob-txn.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c +index ef29f35..86606f9 100644 +--- a/tests/test-blockjob-txn.c ++++ b/tests/test-blockjob-txn.c +@@ -24,7 +24,7 @@ typedef struct { + int *result; + } TestBlockJob; + +-static void test_block_job_exit(Job *job) ++static void test_block_job_clean(Job *job) + { + BlockJob *bjob = container_of(job, BlockJob, job); + BlockDriverState *bs = blk_bs(bjob->blk); +@@ -73,7 +73,7 @@ static const BlockJobDriver test_block_job_driver = { + .user_resume = block_job_user_resume, + .drain = block_job_drain, + .run = test_block_job_run, +- .exit = test_block_job_exit, ++ .clean = test_block_job_clean, + }, + }; + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-throttle-groups-drain-before-detaching-ThrottleState.patch b/SOURCES/kvm-throttle-groups-drain-before-detaching-ThrottleState.patch deleted file mode 100644 index 966dcd1..0000000 --- a/SOURCES/kvm-throttle-groups-drain-before-detaching-ThrottleState.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 9e1beaad709ba68a82a54738ad7b50cac69861cc Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Fri, 17 Nov 2017 11:19:04 +0100 -Subject: [PATCH 05/15] throttle-groups: drain before detaching ThrottleState - -RH-Author: Stefan Hajnoczi -Message-id: <20171117111908.8815-6-stefanha@redhat.com> -Patchwork-id: 77740 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 5/9] throttle-groups: drain before detaching ThrottleState -Bugzilla: 1492295 -RH-Acked-by: John Snow -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth - -I/O requests hang after stop/cont commands at least since QEMU 2.10.0 -with -drive iops=100: - - (guest)$ dd if=/dev/zero of=/dev/vdb oflag=direct count=1000 - (qemu) stop - (qemu) cont - ...I/O is stuck... - -This happens because blk_set_aio_context() detaches the ThrottleState -while requests may still be in flight: - - if (tgm->throttle_state) { - throttle_group_detach_aio_context(tgm); - throttle_group_attach_aio_context(tgm, new_context); - } - -This patch encloses the detach/attach calls in a drained region so no -I/O request is left hanging. Also add assertions so we don't make the -same mistake again in the future. - -Reported-by: Yongxue Hong -Signed-off-by: Stefan Hajnoczi -Reviewed-by: Alberto Garcia -Message-id: 20171110151934.16883-1-stefanha@redhat.com -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit dc868fb03b9b829ed9d2ecdae0fcc12f3fe19b4f) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - block/block-backend.c | 2 ++ - block/throttle-groups.c | 6 ++++++ - 2 files changed, 8 insertions(+) - -diff --git a/block/block-backend.c b/block/block-backend.c -index bfb3e84..520f2b2 100644 ---- a/block/block-backend.c -+++ b/block/block-backend.c -@@ -1771,8 +1771,10 @@ void blk_set_aio_context(BlockBackend *blk, AioContext *new_context) - - if (bs) { - if (tgm->throttle_state) { -+ bdrv_drained_begin(bs); - throttle_group_detach_aio_context(tgm); - throttle_group_attach_aio_context(tgm, new_context); -+ bdrv_drained_end(bs); - } - bdrv_set_aio_context(bs, new_context); - } -diff --git a/block/throttle-groups.c b/block/throttle-groups.c -index 7749cf0..44cc1e6 100644 ---- a/block/throttle-groups.c -+++ b/block/throttle-groups.c -@@ -568,6 +568,12 @@ void throttle_group_attach_aio_context(ThrottleGroupMember *tgm, - void throttle_group_detach_aio_context(ThrottleGroupMember *tgm) - { - ThrottleTimers *tt = &tgm->throttle_timers; -+ -+ /* Requests must have been drained */ -+ assert(tgm->pending_reqs[0] == 0 && tgm->pending_reqs[1] == 0); -+ assert(qemu_co_queue_empty(&tgm->throttled_reqs[0])); -+ assert(qemu_co_queue_empty(&tgm->throttled_reqs[1])); -+ - throttle_timers_detach_aio_context(tt); - tgm->aio_context = NULL; - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-throttle-groups-fix-hang-when-group-member-leaves.patch b/SOURCES/kvm-throttle-groups-fix-hang-when-group-member-leaves.patch new file mode 100644 index 0000000..38d320b --- /dev/null +++ b/SOURCES/kvm-throttle-groups-fix-hang-when-group-member-leaves.patch @@ -0,0 +1,68 @@ +From 542fe943f769002a9826f057fcf32acdb1cdc41e Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Mon, 23 Jul 2018 16:36:29 +0200 +Subject: [PATCH 89/89] throttle-groups: fix hang when group member leaves + +RH-Author: Stefan Hajnoczi +Message-id: <20180723163629.7600-2-stefanha@redhat.com> +Patchwork-id: 81469 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/1] throttle-groups: fix hang when group member leaves +Bugzilla: 1535914 +RH-Acked-by: Fam Zheng +RH-Acked-by: Laurent Vivier +RH-Acked-by: Miroslav Rezanina + +Throttle groups consist of members sharing one throttling state +(including bps/iops limits). Round-robin scheduling is used to ensure +fairness. If a group member already has a timer pending then other +groups members do not schedule their own timers. The next group member +will have its turn when the existing timer expires. + +A hang may occur when a group member leaves while it had a timer +scheduled. Although the code carefully removes the group member from +the round-robin list, it does not schedule the next member. Therefore +remaining members continue to wait for the removed member's timer to +expire. + +This patch schedules the next request if a timer is pending. +Unfortunately the actual bug is a race condition that I've been unable +to capture in a test case. + +Sometimes drive2 hangs when drive1 is removed from the throttling group: + + $ qemu ... -drive if=none,id=drive1,cache=none,format=qcow2,file=data1.qcow2,iops=100,group=foo \ + -device virtio-blk-pci,id=virtio-blk-pci0,drive=drive1 \ + -drive if=none,id=drive2,cache=none,format=qcow2,file=data2.qcow2,iops=10,group=foo \ + -device virtio-blk-pci,id=virtio-blk-pci1,drive=drive2 + (guest-console1)# fio -filename /dev/vda 4k-seq-read.job + (guest-console2)# fio -filename /dev/vdb 4k-seq-read.job + (qmp) {"execute": "block_set_io_throttle", "arguments": {"device": "drive1","bps": 0,"bps_rd": 0,"bps_wr": 0,"iops": 0,"iops_rd": 0,"iops_wr": 0}} + +Reported-by: Nini Gu +Signed-off-by: Stefan Hajnoczi +Message-id: 20180704145410.794-1-stefanha@redhat.com +Cc: Alberto Garcia +Signed-off-by: Stefan Hajnoczi +Signed-off-by: Miroslav Rezanina +--- + block/throttle-groups.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/block/throttle-groups.c b/block/throttle-groups.c +index 36cc043..e297b04 100644 +--- a/block/throttle-groups.c ++++ b/block/throttle-groups.c +@@ -564,6 +564,10 @@ void throttle_group_unregister_tgm(ThrottleGroupMember *tgm) + + qemu_mutex_lock(&tg->lock); + for (i = 0; i < 2; i++) { ++ if (timer_pending(tgm->throttle_timers.timers[i])) { ++ tg->any_timer_armed[i] = false; ++ schedule_next_request(tgm, i); ++ } + if (tg->tokens[i] == tgm) { + token = throttle_group_next_tgm(tgm); + /* Take care of the case where this is the last tgm in the group */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-throttle-groups-forget-timer-and-schedule-next-TGM-o.patch b/SOURCES/kvm-throttle-groups-forget-timer-and-schedule-next-TGM-o.patch deleted file mode 100644 index 73cbad5..0000000 --- a/SOURCES/kvm-throttle-groups-forget-timer-and-schedule-next-TGM-o.patch +++ /dev/null @@ -1,74 +0,0 @@ -From ae4ca7d9cfb0033cf39971f1c59e9a20a80c9bee Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Fri, 17 Nov 2017 11:19:08 +0100 -Subject: [PATCH 09/15] throttle-groups: forget timer and schedule next TGM on - detach - -RH-Author: Stefan Hajnoczi -Message-id: <20171117111908.8815-10-stefanha@redhat.com> -Patchwork-id: 77744 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 9/9] throttle-groups: forget timer and schedule next TGM on detach -Bugzilla: 1492295 -RH-Acked-by: John Snow -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth - -tg->any_timer_armed[] must be cleared when detaching pending timers from -the AioContext. Failure to do so leads to hung I/O because it looks -like there are still timers pending when in fact they have been removed. - -Other ThrottleGroupMembers might have requests pending too so it's -necessary to schedule the next TGM so it can set a timer. - -This patch fixes hung I/O when QEMU is launched with drives that are in -the same throttling group: - - (guest)$ dd if=/dev/zero of=/dev/vdb oflag=direct bs=512 & - (guest)$ dd if=/dev/zero of=/dev/vdc oflag=direct bs=512 & - (qemu) stop - (qemu) cont - ...I/O is stuck... - -Signed-off-by: Stefan Hajnoczi -Message-id: 20171116112150.27607-1-stefanha@redhat.com -Signed-off-by: Stefan Hajnoczi -(cherry picked from commit 341e0b5658681f46680024cdbfc998717d85cc35) -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - block/throttle-groups.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/block/throttle-groups.c b/block/throttle-groups.c -index 44cc1e6..35c22ac 100644 ---- a/block/throttle-groups.c -+++ b/block/throttle-groups.c -@@ -567,13 +567,25 @@ void throttle_group_attach_aio_context(ThrottleGroupMember *tgm, - - void throttle_group_detach_aio_context(ThrottleGroupMember *tgm) - { -+ ThrottleGroup *tg = container_of(tgm->throttle_state, ThrottleGroup, ts); - ThrottleTimers *tt = &tgm->throttle_timers; -+ int i; - - /* Requests must have been drained */ - assert(tgm->pending_reqs[0] == 0 && tgm->pending_reqs[1] == 0); - assert(qemu_co_queue_empty(&tgm->throttled_reqs[0])); - assert(qemu_co_queue_empty(&tgm->throttled_reqs[1])); - -+ /* Kick off next ThrottleGroupMember, if necessary */ -+ qemu_mutex_lock(&tg->lock); -+ for (i = 0; i < 2; i++) { -+ if (timer_pending(tt->timers[i])) { -+ tg->any_timer_armed[i] = false; -+ schedule_next_request(tgm, i); -+ } -+ } -+ qemu_mutex_unlock(&tg->lock); -+ - throttle_timers_detach_aio_context(tt); - tgm->aio_context = NULL; - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-add-Total-column.patch b/SOURCES/kvm-tools-kvm_stat-add-Total-column.patch deleted file mode 100644 index f8015ce..0000000 --- a/SOURCES/kvm-tools-kvm_stat-add-Total-column.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 4f80c9081b411684efbd2e3caff57e7a261d71e7 Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:43 +0200 -Subject: [PATCH 38/69] tools/kvm_stat: add '%Total' column -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-18-david@redhat.com> -Patchwork-id: 77328 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 17/39] tools/kvm_stat: add '%Total' column -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git e55fe3ccccc1efb8f20c99728c8863424ae9ee4a - -commit e55fe3ccccc1efb8f20c99728c8863424ae9ee4a -Author: Stefan Raspl -Date: Fri Mar 10 13:40:16 2017 +0100 - - tools/kvm_stat: add '%Total' column - - Add column '%Total' next to 'Total' for easier comparison of numbers between - hosts. - - Signed-off-by: Stefan Raspl - Marc Hartmayer - Signed-off-by: Radim Krčmář - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index f8c48f8..8f74ed8 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -973,7 +973,9 @@ class Tui(object): - self.screen.addstr(2, 1, 'Event') - self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH - - len('Total'), 'Total') -- self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH + 8 - -+ self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH + 7 - -+ len('%Total'), '%Total') -+ self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH + 7 + 8 - - len('Current'), 'Current') - self.screen.addstr(4, 1, 'Collecting data...') - self.screen.refresh() -@@ -989,6 +991,9 @@ class Tui(object): - return (-stats[x][1], -stats[x][0]) - else: - return (0, -stats[x][0]) -+ total = 0. -+ for val in stats.values(): -+ total += val[0] - for key in sorted(stats.keys(), key=sortkey): - - if row >= self.screen.getmaxyx()[0]: -@@ -1001,6 +1006,8 @@ class Tui(object): - col += LABEL_WIDTH - self.screen.addstr(row, col, '%10d' % (values[0],)) - col += NUMBER_WIDTH -+ self.screen.addstr(row, col, '%7.1f' % (values[0] * 100 / total,)) -+ col += 7 - if values[1] is not None: - self.screen.addstr(row, col, '%8d' % (values[1] / sleeptime,)) - row += 1 --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-add-f-help-to-get-the-available-event.patch b/SOURCES/kvm-tools-kvm_stat-add-f-help-to-get-the-available-event.patch deleted file mode 100644 index 8c2464b..0000000 --- a/SOURCES/kvm-tools-kvm_stat-add-f-help-to-get-the-available-event.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 592b801e5cc13422eedf2bc81bb27c12e2da3d9e Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:16:05 +0200 -Subject: [PATCH 60/69] tools/kvm_stat: add '-f help' to get the available - event list - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-40-david@redhat.com> -Patchwork-id: 77345 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 39/39] tools/kvm_stat: add '-f help' to get the available event list -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git 67fbcd62f54d4503e3dc63b68af1c6757b74e050 - -commit 67fbcd62f54d4503e3dc63b68af1c6757b74e050 -Author: Lin Ma -Date: Tue Jul 25 19:05:54 2017 +0800 - - tools/kvm_stat: add '-f help' to get the available event list - - Signed-off-by: Lin Ma - Signed-off-by: Paolo Bonzini - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 16 ++++++++++++++-- - 1 file changed, 14 insertions(+), 2 deletions(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index 5704044..32283d8 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -474,7 +474,7 @@ class Provider(object): - @staticmethod - def is_field_wanted(fields_filter, field): - """Indicate whether field is valid according to fields_filter.""" -- if not fields_filter: -+ if not fields_filter or fields_filter == "help": - return True - return re.match(fields_filter, field) is not None - -@@ -1496,7 +1496,8 @@ Press any other key to refresh statistics immediately. - action='store', - default=DEFAULT_REGEX, - dest='fields', -- help='fields to display (regex)', -+ help='''fields to display (regex) -+ "-f help" for a list of available events''', - ) - optparser.add_option('-p', '--pid', - action='store', -@@ -1559,6 +1560,17 @@ def main(): - - stats = Stats(options) - -+ if options.fields == "help": -+ event_list = "\n" -+ s = stats.get() -+ for key in s.keys(): -+ if key.find('(') != -1: -+ key = key[0:key.find('(')] -+ if event_list.find('\n' + key + '\n') == -1: -+ event_list += key + '\n' -+ sys.stdout.write(event_list) -+ return "" -+ - if options.log: - log(stats) - elif not options.once: --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-add-interactive-command-c.patch b/SOURCES/kvm-tools-kvm_stat-add-interactive-command-c.patch deleted file mode 100644 index 4f909e0..0000000 --- a/SOURCES/kvm-tools-kvm_stat-add-interactive-command-c.patch +++ /dev/null @@ -1,121 +0,0 @@ -From 38362f9d75028cdcd58b6facb605f71f2a22a9be Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:41 +0200 -Subject: [PATCH 36/69] tools/kvm_stat: add interactive command 'c' -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-16-david@redhat.com> -Patchwork-id: 77325 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 15/39] tools/kvm_stat: add interactive command 'c' -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git 4443084fa0cf85f91d357c8917b90504b784d925 - -Convertion of documentation (for man page generation) to texi. - -commit 4443084fa0cf85f91d357c8917b90504b784d925 -Author: Stefan Raspl -Date: Fri Mar 10 13:40:14 2017 +0100 - - tools/kvm_stat: add interactive command 'c' - - Provide a real simple way to erase any active filter. - - Signed-off-by: Stefan Raspl - Reviewed-by: Marc Hartmayer - Signed-off-by: Radim Krčmář - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 16 ++++++++++++---- - scripts/kvm/kvm_stat.texi | 3 +++ - 2 files changed, 15 insertions(+), 4 deletions(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index f263312..676a92a 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -861,6 +861,7 @@ DELAY_INITIAL = 0.25 - DELAY_REGULAR = 3.0 - MAX_GUEST_NAME_LEN = 48 - MAX_REGEX_LEN = 44 -+DEFAULT_REGEX = r'^[^\(]*$' - - - class Tui(object): -@@ -907,9 +908,9 @@ class Tui(object): - def update_drilldown(self): - """Sets or removes a filter that only allows fields without braces.""" - if not self.stats.fields_filter: -- self.stats.fields_filter = r'^[^\(]*$' -+ self.stats.fields_filter = DEFAULT_REGEX - -- elif self.stats.fields_filter == r'^[^\(]*$': -+ elif self.stats.fields_filter == DEFAULT_REGEX: - self.stats.fields_filter = None - - def update_pid(self, pid): -@@ -931,7 +932,8 @@ class Tui(object): - .format(pid, gname), curses.A_BOLD) - else: - self.screen.addstr(0, 0, 'kvm statistics - summary', curses.A_BOLD) -- if self.stats.fields_filter and self.stats.fields_filter != '^[^\(]*$': -+ if self.stats.fields_filter and self.stats.fields_filter \ -+ != DEFAULT_REGEX: - regex = self.stats.fields_filter - if len(regex) > MAX_REGEX_LEN: - regex = regex[:MAX_REGEX_LEN] + '...' -@@ -991,7 +993,7 @@ class Tui(object): - regex = self.screen.getstr() - curses.noecho() - if len(regex) == 0: -- self.stats.fields_filter = r'^[^\(]*$' -+ self.stats.fields_filter = DEFAULT_REGEX - self.refresh_header() - return - try: -@@ -1101,6 +1103,11 @@ class Tui(object): - sleeptime = DELAY_INITIAL - if char == 'q': - break -+ if char == 'c': -+ self.stats.fields_filter = DEFAULT_REGEX -+ self.refresh_header(0) -+ self.update_pid(0) -+ sleeptime = DELAY_INITIAL - if char == 'f': - self.show_filter_selection() - sleeptime = DELAY_INITIAL -@@ -1177,6 +1184,7 @@ Requirements: - the large number of files that are possibly opened. - - Interactive Commands: -+ c clear filter - f filter by regular expression - g filter by guest name - p filter by PID -diff --git a/scripts/kvm/kvm_stat.texi b/scripts/kvm/kvm_stat.texi -index a8c1071..203d61d 100644 ---- a/scripts/kvm/kvm_stat.texi -+++ b/scripts/kvm/kvm_stat.texi -@@ -24,6 +24,9 @@ Use batch and logging modes for scripting purposes. - While running in regular (interactive) mode, use any of the following keys: - - @table @key -+@item c -+@kindex c -+clear filter - @item f - @kindex f - filter by regular expression --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-add-interactive-command-r.patch b/SOURCES/kvm-tools-kvm_stat-add-interactive-command-r.patch deleted file mode 100644 index 5351a8a..0000000 --- a/SOURCES/kvm-tools-kvm_stat-add-interactive-command-r.patch +++ /dev/null @@ -1,225 +0,0 @@ -From 243d90a041dca861bb85bc71df863578a8f839bd Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:42 +0200 -Subject: [PATCH 37/69] tools/kvm_stat: add interactive command 'r' -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-17-david@redhat.com> -Patchwork-id: 77326 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 16/39] tools/kvm_stat: add interactive command 'r' -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git 9f114a03c6854f49065dd036c17e1b4bb947f842 - -Convertion of documentation (for man page generation) to texi. - -commit 9f114a03c6854f49065dd036c17e1b4bb947f842 -Author: Stefan Raspl -Date: Fri Mar 10 13:40:15 2017 +0100 - - tools/kvm_stat: add interactive command 'r' - - Provide an interactive command to reset the tracepoint statistics. - Requires some extra work for debugfs, as the counters cannot be reset. - - On the up side, this offers us the opportunity to have debugfs values - reset on startup and whenever a filter is modified, becoming consistent - with the tracepoint provider. As a bonus, 'kvmstat -dt' will now provide - useful output, instead of mixing values in totally different orders of - magnitude. - Furthermore, we avoid unnecessary resets when any of the filters is - "changed" interactively to the previous value. - - Signed-off-by: Stefan Raspl - Acked-by: Janosch Frank - Signed-off-by: Radim Krčmář - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 65 +++++++++++++++++++++++++++++++++++++---------- - scripts/kvm/kvm_stat.texi | 3 +++ - 2 files changed, 54 insertions(+), 14 deletions(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index 676a92a..f8c48f8 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -716,15 +716,23 @@ class TracepointProvider(object): - ret[name] += val - return ret - -+ def reset(self): -+ """Reset all field counters""" -+ for group in self.group_leaders: -+ for event in group.events: -+ event.reset() -+ - - class DebugfsProvider(object): - """Provides data from the files that KVM creates in the kvm debugfs - folder.""" - def __init__(self): - self._fields = self.get_available_fields() -+ self._baseline = {} - self._pid = 0 - self.do_read = True - self.paths = [] -+ self.reset() - - def get_available_fields(self): - """"Returns a list of available fields. -@@ -741,6 +749,7 @@ class DebugfsProvider(object): - @fields.setter - def fields(self, fields): - self._fields = fields -+ self.reset() - - @property - def pid(self): -@@ -758,10 +767,11 @@ class DebugfsProvider(object): - self.paths = filter(lambda x: "{}-".format(pid) in x, vms) - - else: -- self.paths = [''] -+ self.paths = [] - self.do_read = True -+ self.reset() - -- def read(self): -+ def read(self, reset=0): - """Returns a dict with format:'file name / field -> current value'.""" - results = {} - -@@ -769,10 +779,22 @@ class DebugfsProvider(object): - if not self.do_read: - return results - -- for path in self.paths: -+ paths = self.paths -+ if self._pid == 0: -+ paths = [] -+ for entry in os.walk(PATH_DEBUGFS_KVM): -+ for dir in entry[1]: -+ paths.append(dir) -+ for path in paths: - for field in self._fields: -- results[field] = results.get(field, 0) \ -- + self.read_field(field, path) -+ value = self.read_field(field, path) -+ key = path + field -+ if reset: -+ self._baseline[key] = value -+ if self._baseline.get(key, -1) == -1: -+ self._baseline[key] = value -+ results[field] = (results.get(field, 0) + value - -+ self._baseline.get(key, 0)) - - return results - -@@ -786,6 +808,11 @@ class DebugfsProvider(object): - except IOError: - return 0 - -+ def reset(self): -+ """Reset field counters""" -+ self._baseline = {} -+ self.read(1) -+ - - class Stats(object): - """Manages the data providers and the data they provide. -@@ -822,14 +849,20 @@ class Stats(object): - for provider in self.providers: - provider.pid = self._pid_filter - -+ def reset(self): -+ self.values = {} -+ for provider in self.providers: -+ provider.reset() -+ - @property - def fields_filter(self): - return self._fields_filter - - @fields_filter.setter - def fields_filter(self, fields_filter): -- self._fields_filter = fields_filter -- self.update_provider_filters() -+ if fields_filter != self._fields_filter: -+ self._fields_filter = fields_filter -+ self.update_provider_filters() - - @property - def pid_filter(self): -@@ -837,9 +870,10 @@ class Stats(object): - - @pid_filter.setter - def pid_filter(self, pid): -- self._pid_filter = pid -- self.values = {} -- self.update_provider_pid() -+ if pid != self._pid_filter: -+ self._pid_filter = pid -+ self.values = {} -+ self.update_provider_pid() - - def get(self): - """Returns a dict with field -> (value, delta to last value) of all -@@ -847,11 +881,9 @@ class Stats(object): - for provider in self.providers: - new = provider.read() - for key in provider.fields: -- oldval = self.values.get(key, (0, 0)) -+ oldval = self.values.get(key, (0, 0))[0] - newval = new.get(key, 0) -- newdelta = None -- if oldval is not None: -- newdelta = newval - oldval[0] -+ newdelta = newval - oldval - self.values[key] = (newval, newdelta) - return self.values - -@@ -1117,6 +1149,10 @@ class Tui(object): - if char == 'p': - self.show_vm_selection_by_pid() - sleeptime = DELAY_INITIAL -+ if char == 'r': -+ self.refresh_header() -+ self.stats.reset() -+ sleeptime = DELAY_INITIAL - except KeyboardInterrupt: - break - except curses.error: -@@ -1190,6 +1226,7 @@ Interactive Commands: - p filter by PID - q quit - x toggle reporting of stats for individual child trace events -+ r reset stats - Press any other key to refresh statistics immediately. - """ - -diff --git a/scripts/kvm/kvm_stat.texi b/scripts/kvm/kvm_stat.texi -index 203d61d..c0cb7bc 100644 ---- a/scripts/kvm/kvm_stat.texi -+++ b/scripts/kvm/kvm_stat.texi -@@ -39,6 +39,9 @@ filter by PID - @item q - @kindex q - quit -+@item r -+@kindex r -+reset stats - @item x - @kindex x - toggle reporting of stats for child trace events --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-add-new-command-line-switch-i.patch b/SOURCES/kvm-tools-kvm_stat-add-new-command-line-switch-i.patch deleted file mode 100644 index fefaafe..0000000 --- a/SOURCES/kvm-tools-kvm_stat-add-new-command-line-switch-i.patch +++ /dev/null @@ -1,149 +0,0 @@ -From 72f660ddfca081d8a3124e30b0d55f2be06965bc Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:16:02 +0200 -Subject: [PATCH 57/69] tools/kvm_stat: add new command line switch '-i' - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-37-david@redhat.com> -Patchwork-id: 77348 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 36/39] tools/kvm_stat: add new command line switch '-i' -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git ab7ef193fab628fc5da6fd4f4672ffd0d1bb53df - -Convertion of documentation (for man page generation) to texi. - -commit ab7ef193fab628fc5da6fd4f4672ffd0d1bb53df -Author: Stefan Raspl -Date: Sun Jun 25 21:34:15 2017 +0200 - - tools/kvm_stat: add new command line switch '-i' - - It might be handy to display the full history of event stats to compare - the current event distribution against any available historic data. - Since we have that available for debugfs, we offer a respective command - line option to display what's available. - - Signed-off-by: Stefan Raspl - Signed-off-by: Paolo Bonzini - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 34 ++++++++++++++++++++++++++++++---- - scripts/kvm/kvm_stat.texi | 2 ++ - 2 files changed, 32 insertions(+), 4 deletions(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index 39476e5..4065b29 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -681,12 +681,14 @@ class TracepointProvider(Provider): - class DebugfsProvider(Provider): - """Provides data from the files that KVM creates in the kvm debugfs - folder.""" -- def __init__(self, pid, fields_filter): -+ def __init__(self, pid, fields_filter, include_past): - self.update_fields(fields_filter) - self._baseline = {} - self.do_read = True - self.paths = [] - self.pid = pid -+ if include_past: -+ self.restore() - - def get_available_fields(self): - """"Returns a list of available fields. -@@ -730,7 +732,14 @@ class DebugfsProvider(Provider): - self.reset() - - def read(self, reset=0): -- """Returns a dict with format:'file name / field -> current value'.""" -+ """Returns a dict with format:'file name / field -> current value'. -+ -+ Parameter 'reset': -+ 0 plain read -+ 1 reset field counts to 0 -+ 2 restore the original field counts -+ -+ """ - results = {} - - # If no debugfs filtering support is available, then don't read. -@@ -747,8 +756,10 @@ class DebugfsProvider(Provider): - for field in self._fields: - value = self.read_field(field, path) - key = path + field -- if reset: -+ if reset == 1: - self._baseline[key] = value -+ if reset == 2: -+ self._baseline[key] = 0 - if self._baseline.get(key, -1) == -1: - self._baseline[key] = value - results[field] = (results.get(field, 0) + value - -@@ -771,6 +782,11 @@ class DebugfsProvider(Provider): - self._baseline = {} - self.read(1) - -+ def restore(self): -+ """Reset field counters""" -+ self._baseline = {} -+ self.read(2) -+ - - class Stats(object): - """Manages the data providers and the data they provide. -@@ -791,7 +807,8 @@ class Stats(object): - providers = [] - - if options.debugfs: -- providers.append(DebugfsProvider(options.pid, options.fields)) -+ providers.append(DebugfsProvider(options.pid, options.fields, -+ options.dbgfs_include_past)) - if options.tracepoints or not providers: - providers.append(TracepointProvider(options.pid, options.fields)) - -@@ -1270,6 +1287,8 @@ class Tui(object): - sleeptime = self._delay_initial - if char == 'x': - self.update_drilldown() -+ # prevents display of current values on next refresh -+ self.stats.get() - except KeyboardInterrupt: - break - except curses.error: -@@ -1381,6 +1400,13 @@ Press any other key to refresh statistics immediately. - dest='once', - help='run in batch mode for one second', - ) -+ optparser.add_option('-i', '--debugfs-include-past', -+ action='store_true', -+ default=False, -+ dest='dbgfs_include_past', -+ help='include all available data on past events for ' -+ 'debugfs', -+ ) - optparser.add_option('-l', '--log', - action='store_true', - default=False, -diff --git a/scripts/kvm/kvm_stat.texi b/scripts/kvm/kvm_stat.texi -index 68d5024..b0e282a 100644 ---- a/scripts/kvm/kvm_stat.texi -+++ b/scripts/kvm/kvm_stat.texi -@@ -73,6 +73,8 @@ Press any other key to refresh statistics immediately. - retrieve statistics from debugfs - @item -p, --pid=@var{pid} - limit statistics to one virtual machine (pid) -+@item -i, --debugfs-include-past -+ include all available data on past events for debugfs - @item -g, --guest=@var{guest_name} - limit statistics to one virtual machine (guest name) - @item -f, --fields=@var{fields} --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-add-new-interactive-command-b.patch b/SOURCES/kvm-tools-kvm_stat-add-new-interactive-command-b.patch deleted file mode 100644 index b27d3e1..0000000 --- a/SOURCES/kvm-tools-kvm_stat-add-new-interactive-command-b.patch +++ /dev/null @@ -1,240 +0,0 @@ -From 17165a0bc8b8496f52f9273fe4466797f3a6726e Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:16:03 +0200 -Subject: [PATCH 58/69] tools/kvm_stat: add new interactive command 'b' - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-38-david@redhat.com> -Patchwork-id: 77344 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 37/39] tools/kvm_stat: add new interactive command 'b' -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git 5c1954d25d1b9e857be2a4c77437312075875589 - -Convertion of documentation (for man page generation) to texi. - -commit 5c1954d25d1b9e857be2a4c77437312075875589 -Author: Stefan Raspl -Date: Sun Jun 25 21:34:16 2017 +0200 - - tools/kvm_stat: add new interactive command 'b' - - Toggle display total number of events by guest (debugfs only). - When switching to display of events by guest, field filters remain - active. I.e. the number of events per guest reported considers only - events matching the filters. Likewise with pid/guest filtering. - Note that when switching to display of events by guest, DebugfsProvider - remains to collect data for events as it did before, but the read() - method summarizes the values by pid. - - Signed-off-by: Stefan Raspl - Signed-off-by: Paolo Bonzini - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 87 +++++++++++++++++++++++++++++++++++++++++------ - scripts/kvm/kvm_stat.texi | 3 ++ - 2 files changed, 80 insertions(+), 10 deletions(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index 4065b29..dd8f00c 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -662,7 +662,7 @@ class TracepointProvider(Provider): - self.setup_traces() - self.fields = self._fields - -- def read(self): -+ def read(self, by_guest=0): - """Returns 'event name: current value' for all enabled events.""" - ret = defaultdict(int) - for group in self.group_leaders: -@@ -731,7 +731,7 @@ class DebugfsProvider(Provider): - self.do_read = True - self.reset() - -- def read(self, reset=0): -+ def read(self, reset=0, by_guest=0): - """Returns a dict with format:'file name / field -> current value'. - - Parameter 'reset': -@@ -762,8 +762,16 @@ class DebugfsProvider(Provider): - self._baseline[key] = 0 - if self._baseline.get(key, -1) == -1: - self._baseline[key] = value -- results[field] = (results.get(field, 0) + value - -- self._baseline.get(key, 0)) -+ increment = (results.get(field, 0) + value - -+ self._baseline.get(key, 0)) -+ if by_guest: -+ pid = key.split('-')[0] -+ if pid in results: -+ results[pid] += increment -+ else: -+ results[pid] = increment -+ else: -+ results[field] = increment - - return results - -@@ -849,18 +857,44 @@ class Stats(object): - for provider in self.providers: - provider.pid = self._pid_filter - -- def get(self): -+ def get(self, by_guest=0): - """Returns a dict with field -> (value, delta to last value) of all - provider data.""" - for provider in self.providers: -- new = provider.read() -- for key in provider.fields: -+ new = provider.read(by_guest=by_guest) -+ for key in new if by_guest else provider.fields: - oldval = self.values.get(key, (0, 0))[0] - newval = new.get(key, 0) - newdelta = newval - oldval - self.values[key] = (newval, newdelta) - return self.values - -+ def toggle_display_guests(self, to_pid): -+ """Toggle between collection of stats by individual event and by -+ guest pid -+ -+ Events reported by DebugfsProvider change when switching to/from -+ reading by guest values. Hence we have to remove the excess event -+ names from self.values. -+ -+ """ -+ if any(isinstance(ins, TracepointProvider) for ins in self.providers): -+ return 1 -+ if to_pid: -+ for provider in self.providers: -+ if isinstance(provider, DebugfsProvider): -+ for key in provider.fields: -+ if key in self.values.keys(): -+ del self.values[key] -+ else: -+ oldvals = self.values.copy() -+ for key in oldvals: -+ if key.isdigit(): -+ del self.values[key] -+ # Update oldval (see get()) -+ self.get(to_pid) -+ return 0 -+ - DELAY_DEFAULT = 3.0 - MAX_GUEST_NAME_LEN = 48 - MAX_REGEX_LEN = 44 -@@ -876,6 +910,7 @@ class Tui(object): - self._delay_initial = 0.25 - self._delay_regular = DELAY_DEFAULT - self._sorting = SORT_DEFAULT -+ self._display_guests = 0 - - def __enter__(self): - """Initialises curses for later use. Based on curses.wrapper -@@ -1024,8 +1059,12 @@ class Tui(object): - if len(regex) > MAX_REGEX_LEN: - regex = regex[:MAX_REGEX_LEN] + '...' - self.screen.addstr(1, 17, 'regex filter: {0}'.format(regex)) -+ if self._display_guests: -+ col_name = 'Guest Name' -+ else: -+ col_name = 'Event' - self.screen.addstr(2, 1, '%-40s %10s%7s %8s' % -- ('Event', 'Total', '%Total', 'CurAvg/s'), -+ (col_name, 'Total', '%Total', 'CurAvg/s'), - curses.A_STANDOUT) - self.screen.addstr(4, 1, 'Collecting data...') - self.screen.refresh() -@@ -1034,7 +1073,7 @@ class Tui(object): - row = 3 - self.screen.move(row, 0) - self.screen.clrtobot() -- stats = self.stats.get() -+ stats = self.stats.get(self._display_guests) - - def sortCurAvg(x): - # sort by current events if available -@@ -1062,6 +1101,8 @@ class Tui(object): - break - if values[0] is not None: - cur = int(round(values[1] / sleeptime)) if values[1] else '' -+ if self._display_guests: -+ key = self.get_gname_from_pid(key) - self.screen.addstr(row, 1, '%-40s %10d%7.1f %8s' % - (key, values[0], values[0] * 100 / total, - cur)) -@@ -1070,9 +1111,26 @@ class Tui(object): - self.screen.addstr(4, 1, 'No matching events reported yet') - self.screen.refresh() - -+ def show_msg(self, text): -+ """Display message centered text and exit on key press""" -+ hint = 'Press any key to continue' -+ curses.cbreak() -+ self.screen.erase() -+ (x, term_width) = self.screen.getmaxyx() -+ row = 2 -+ for line in text: -+ start = (term_width - len(line)) / 2 -+ self.screen.addstr(row, start, line) -+ row += 1 -+ self.screen.addstr(row + 1, (term_width - len(hint)) / 2, hint, -+ curses.A_STANDOUT) -+ self.screen.getkey() -+ - def show_help_interactive(self): - """Display help with list of interactive commands""" -- msg = (' c clear filter', -+ msg = (' b toggle events by guests (debugfs only, honors' -+ ' filters)', -+ ' c clear filter', - ' f filter by regular expression', - ' g filter by guest name', - ' h display interactive commands reference', -@@ -1253,6 +1311,14 @@ class Tui(object): - sleeptime = self._delay_regular - try: - char = self.screen.getkey() -+ if char == 'b': -+ self._display_guests = not self._display_guests -+ if self.stats.toggle_display_guests(self._display_guests): -+ self.show_msg(['Command not available with tracepoints' -+ ' enabled', 'Restart with debugfs only ' -+ '(see option \'-d\') and try again!']) -+ self._display_guests = not self._display_guests -+ self.refresh_header() - if char == 'c': - self.stats.fields_filter = DEFAULT_REGEX - self.refresh_header(0) -@@ -1356,6 +1422,7 @@ Requirements: - the large number of files that are possibly opened. - - Interactive Commands: -+ b toggle events by guests (debugfs only, honors filters) - c clear filter - f filter by regular expression - g filter by guest name -diff --git a/scripts/kvm/kvm_stat.texi b/scripts/kvm/kvm_stat.texi -index b0e282a..5d964f6 100644 ---- a/scripts/kvm/kvm_stat.texi -+++ b/scripts/kvm/kvm_stat.texi -@@ -24,6 +24,9 @@ Use batch and logging modes for scripting purposes. - While running in regular (interactive) mode, use any of the following keys: - - @table @key -+@item b -+@kindex b -+toggle events by guests (debugfs only, honors filters) - @item c - @kindex c - clear filter --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-add-new-interactive-command-h.patch b/SOURCES/kvm-tools-kvm_stat-add-new-interactive-command-h.patch deleted file mode 100644 index 5d3b241..0000000 --- a/SOURCES/kvm-tools-kvm_stat-add-new-interactive-command-h.patch +++ /dev/null @@ -1,134 +0,0 @@ -From 95b5c46145b2ac79dd4b0f5621baec07e488ff3e Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:57 +0200 -Subject: [PATCH 52/69] tools/kvm_stat: add new interactive command 'h' - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-32-david@redhat.com> -Patchwork-id: 77339 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 31/39] tools/kvm_stat: add new interactive command 'h' -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git 1fdea7b2893045e5258a13937c3d78c425fd7aa0 - -Convertion of documentation (for man page generation) to texi. - -commit 1fdea7b2893045e5258a13937c3d78c425fd7aa0 -Author: Stefan Raspl -Date: Wed Jun 7 21:08:38 2017 +0200 - - tools/kvm_stat: add new interactive command 'h' - - Display interactive commands reference on 'h'. - While at it, sort interactive commands alphabetically in various places. - - Signed-off-by: Stefan Raspl - Signed-off-by: Paolo Bonzini - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 37 ++++++++++++++++++++++++++++++++----- - scripts/kvm/kvm_stat.texi | 3 +++ - 2 files changed, 35 insertions(+), 5 deletions(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index a9e7ea6..6838de3 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -1018,6 +1018,30 @@ class Tui(object): - self.screen.addstr(4, 1, 'No matching events reported yet') - self.screen.refresh() - -+ def show_help_interactive(self): -+ """Display help with list of interactive commands""" -+ msg = (' c clear filter', -+ ' f filter by regular expression', -+ ' g filter by guest name', -+ ' h display interactive commands reference', -+ ' p filter by PID', -+ ' q quit', -+ ' r reset stats', -+ ' x toggle reporting of stats for individual child trace' -+ ' events', -+ 'Any other key refreshes statistics immediately') -+ curses.cbreak() -+ self.screen.erase() -+ self.screen.addstr(0, 0, "Interactive commands reference", -+ curses.A_BOLD) -+ self.screen.addstr(2, 0, "Press any key to exit", curses.A_STANDOUT) -+ row = 4 -+ for line in msg: -+ self.screen.addstr(row, 0, line) -+ row += 1 -+ self.screen.getkey() -+ self.refresh_header() -+ - def show_filter_selection(self): - """Draws filter selection mask. - -@@ -1142,10 +1166,6 @@ class Tui(object): - sleeptime = DELAY_REGULAR - try: - char = self.screen.getkey() -- if char == 'x': -- self.update_drilldown() -- if char == 'q': -- break - if char == 'c': - self.stats.fields_filter = DEFAULT_REGEX - self.refresh_header(0) -@@ -1160,13 +1180,19 @@ class Tui(object): - self.show_vm_selection_by_guest_name() - curses.curs_set(0) - sleeptime = DELAY_INITIAL -+ if char == 'h': -+ self.show_help_interactive() - if char == 'p': - curses.curs_set(1) - self.show_vm_selection_by_pid() - curses.curs_set(0) - sleeptime = DELAY_INITIAL -+ if char == 'q': -+ break - if char == 'r': - self.stats.reset() -+ if char == 'x': -+ self.update_drilldown() - except KeyboardInterrupt: - break - except curses.error: -@@ -1237,10 +1263,11 @@ Interactive Commands: - c clear filter - f filter by regular expression - g filter by guest name -+ h display interactive commands reference - p filter by PID - q quit -- x toggle reporting of stats for individual child trace events - r reset stats -+ x toggle reporting of stats for individual child trace events - Press any other key to refresh statistics immediately. - """ - -diff --git a/scripts/kvm/kvm_stat.texi b/scripts/kvm/kvm_stat.texi -index c0cb7bc..4dfcd8f 100644 ---- a/scripts/kvm/kvm_stat.texi -+++ b/scripts/kvm/kvm_stat.texi -@@ -33,6 +33,9 @@ filter by regular expression - @item g - @kindex g - filter by guest name -+@item h -+@kindex h -+display interactive commands reference - @item p - @kindex p - filter by PID --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-add-new-interactive-command-o.patch b/SOURCES/kvm-tools-kvm_stat-add-new-interactive-command-o.patch deleted file mode 100644 index 399e5ee..0000000 --- a/SOURCES/kvm-tools-kvm_stat-add-new-interactive-command-o.patch +++ /dev/null @@ -1,125 +0,0 @@ -From 55f7ed9b2ccc2761e353d14680fe5d1ea8bc11be Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:59 +0200 -Subject: [PATCH 54/69] tools/kvm_stat: add new interactive command 'o' - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-34-david@redhat.com> -Patchwork-id: 77347 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 33/39] tools/kvm_stat: add new interactive command 'o' -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git 6667ae8f395099257afca0963838d2dc50a18da7 - -Convertion of documentation (for man page generation) to texi. - -commit 6667ae8f395099257afca0963838d2dc50a18da7 -Author: Stefan Raspl -Date: Wed Jun 7 21:08:41 2017 +0200 - - tools/kvm_stat: add new interactive command 'o' - - Add new interactive command 'o' to toggle sorting by 'CurAvg/s' (default) - and 'Total' columns. - - Signed-off-by: Stefan Raspl - Signed-off-by: Paolo Bonzini - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 17 ++++++++++++++++- - scripts/kvm/kvm_stat.texi | 3 +++ - 2 files changed, 19 insertions(+), 1 deletion(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index 1276b88..cf7aa28 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -848,6 +848,7 @@ DELAY_DEFAULT = 3.0 - MAX_GUEST_NAME_LEN = 48 - MAX_REGEX_LEN = 44 - DEFAULT_REGEX = r'^[^\(]*$' -+SORT_DEFAULT = 0 - - - class Tui(object): -@@ -857,6 +858,7 @@ class Tui(object): - self.screen = None - self._delay_initial = 0.25 - self._delay_regular = DELAY_DEFAULT -+ self._sorting = SORT_DEFAULT - - def __enter__(self): - """Initialises curses for later use. Based on curses.wrapper -@@ -994,14 +996,23 @@ class Tui(object): - self.screen.clrtobot() - stats = self.stats.get() - -- def sortkey(x): -+ def sortCurAvg(x): -+ # sort by current events if available - if stats[x][1]: - return (-stats[x][1], -stats[x][0]) - else: - return (0, -stats[x][0]) -+ -+ def sortTotal(x): -+ # sort by totals -+ return (0, -stats[x][0]) - total = 0. - for val in stats.values(): - total += val[0] -+ if self._sorting == SORT_DEFAULT: -+ sortkey = sortCurAvg -+ else: -+ sortkey = sortTotal - for key in sorted(stats.keys(), key=sortkey): - - if row >= self.screen.getmaxyx()[0]: -@@ -1025,6 +1036,7 @@ class Tui(object): - ' f filter by regular expression', - ' g filter by guest name', - ' h display interactive commands reference', -+ ' o toggle sorting order (Total vs CurAvg/s)', - ' p filter by PID', - ' q quit', - ' r reset stats', -@@ -1215,6 +1227,8 @@ class Tui(object): - sleeptime = self._delay_initial - if char == 'h': - self.show_help_interactive() -+ if char == 'o': -+ self._sorting = not self._sorting - if char == 'p': - curses.curs_set(1) - self.show_vm_selection_by_pid() -@@ -1302,6 +1316,7 @@ Interactive Commands: - f filter by regular expression - g filter by guest name - h display interactive commands reference -+ o toggle sorting order (Total vs CurAvg/s) - p filter by PID - q quit - r reset stats -diff --git a/scripts/kvm/kvm_stat.texi b/scripts/kvm/kvm_stat.texi -index f0066ff..68d5024 100644 ---- a/scripts/kvm/kvm_stat.texi -+++ b/scripts/kvm/kvm_stat.texi -@@ -36,6 +36,9 @@ filter by guest name - @item h - @kindex h - display interactive commands reference -+@item o -+@kindex o -+toggle sorting order (Total vs CurAvg/s) - @item p - @kindex p - filter by PID --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-add-new-interactive-command-s.patch b/SOURCES/kvm-tools-kvm_stat-add-new-interactive-command-s.patch deleted file mode 100644 index 3e06a56..0000000 --- a/SOURCES/kvm-tools-kvm_stat-add-new-interactive-command-s.patch +++ /dev/null @@ -1,187 +0,0 @@ -From 25c56e3212fa11d526544b402f4f19234cf991e8 Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:58 +0200 -Subject: [PATCH 53/69] tools/kvm_stat: add new interactive command 's' - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-33-david@redhat.com> -Patchwork-id: 77336 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 32/39] tools/kvm_stat: add new interactive command 's' -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git 64eefad2cdbf2d7c76e24d0b67e19efdbe1c97a9 - -Convertion of documentation (for man page generation) to texi. - -commit 64eefad2cdbf2d7c76e24d0b67e19efdbe1c97a9 -Author: Stefan Raspl -Date: Wed Jun 7 21:08:39 2017 +0200 - - tools/kvm_stat: add new interactive command 's' - - Add new command 's' to modify the update interval. Limited to a maximum of - 25.5 sec and a minimum of 0.1 sec, since curses cannot handle longer - and shorter delays respectively. - - Signed-off-by: Stefan Raspl - Signed-off-by: Paolo Bonzini - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 55 ++++++++++++++++++++++++++++++++++++++++------- - scripts/kvm/kvm_stat.texi | 3 +++ - 2 files changed, 50 insertions(+), 8 deletions(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index 6838de3..1276b88 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -844,8 +844,7 @@ class Stats(object): - self.values[key] = (newval, newdelta) - return self.values - --DELAY_INITIAL = 0.25 --DELAY_REGULAR = 3.0 -+DELAY_DEFAULT = 3.0 - MAX_GUEST_NAME_LEN = 48 - MAX_REGEX_LEN = 44 - DEFAULT_REGEX = r'^[^\(]*$' -@@ -856,6 +855,8 @@ class Tui(object): - def __init__(self, stats): - self.stats = stats - self.screen = None -+ self._delay_initial = 0.25 -+ self._delay_regular = DELAY_DEFAULT - - def __enter__(self): - """Initialises curses for later use. Based on curses.wrapper -@@ -1027,6 +1028,7 @@ class Tui(object): - ' p filter by PID', - ' q quit', - ' r reset stats', -+ ' s set update interval', - ' x toggle reporting of stats for individual child trace' - ' events', - 'Any other key refreshes statistics immediately') -@@ -1106,10 +1108,41 @@ class Tui(object): - self.refresh_header(pid) - self.update_pid(pid) - break -- - except ValueError: - msg = '"' + str(pid) + '": Not a valid pid' - -+ def show_set_update_interval(self): -+ """Draws update interval selection mask.""" -+ msg = '' -+ while True: -+ self.screen.erase() -+ self.screen.addstr(0, 0, 'Set update interval (defaults to %fs).' % -+ DELAY_DEFAULT, curses.A_BOLD) -+ self.screen.addstr(4, 0, msg) -+ self.screen.addstr(2, 0, 'Change delay from %.1fs to ' % -+ self._delay_regular) -+ curses.echo() -+ val = self.screen.getstr() -+ curses.noecho() -+ -+ try: -+ if len(val) > 0: -+ delay = float(val) -+ if delay < 0.1: -+ msg = '"' + str(val) + '": Value must be >=0.1' -+ continue -+ if delay > 25.5: -+ msg = '"' + str(val) + '": Value must be <=25.5' -+ continue -+ else: -+ delay = DELAY_DEFAULT -+ self._delay_regular = delay -+ break -+ -+ except ValueError: -+ msg = '"' + str(val) + '": Invalid value' -+ self.refresh_header() -+ - def show_vm_selection_by_guest_name(self): - """Draws guest selection mask. - -@@ -1156,14 +1189,14 @@ class Tui(object): - - def show_stats(self): - """Refreshes the screen and processes user input.""" -- sleeptime = DELAY_INITIAL -+ sleeptime = self._delay_initial - self.refresh_header() - start = 0.0 # result based on init value never appears on screen - while True: - self.refresh_body(time.time() - start) - curses.halfdelay(int(sleeptime * 10)) - start = time.time() -- sleeptime = DELAY_REGULAR -+ sleeptime = self._delay_regular - try: - char = self.screen.getkey() - if char == 'c': -@@ -1174,23 +1207,28 @@ class Tui(object): - curses.curs_set(1) - self.show_filter_selection() - curses.curs_set(0) -- sleeptime = DELAY_INITIAL -+ sleeptime = self._delay_initial - if char == 'g': - curses.curs_set(1) - self.show_vm_selection_by_guest_name() - curses.curs_set(0) -- sleeptime = DELAY_INITIAL -+ sleeptime = self._delay_initial - if char == 'h': - self.show_help_interactive() - if char == 'p': - curses.curs_set(1) - self.show_vm_selection_by_pid() - curses.curs_set(0) -- sleeptime = DELAY_INITIAL -+ sleeptime = self._delay_initial - if char == 'q': - break - if char == 'r': - self.stats.reset() -+ if char == 's': -+ curses.curs_set(1) -+ self.show_set_update_interval() -+ curses.curs_set(0) -+ sleeptime = self._delay_initial - if char == 'x': - self.update_drilldown() - except KeyboardInterrupt: -@@ -1267,6 +1305,7 @@ Interactive Commands: - p filter by PID - q quit - r reset stats -+ s set update interval - x toggle reporting of stats for individual child trace events - Press any other key to refresh statistics immediately. - """ -diff --git a/scripts/kvm/kvm_stat.texi b/scripts/kvm/kvm_stat.texi -index 4dfcd8f..f0066ff 100644 ---- a/scripts/kvm/kvm_stat.texi -+++ b/scripts/kvm/kvm_stat.texi -@@ -45,6 +45,9 @@ quit - @item r - @kindex r - reset stats -+@item s -+@kindex s -+set update interval - @item x - @kindex x - toggle reporting of stats for child trace events --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-add-option-guest.patch b/SOURCES/kvm-tools-kvm_stat-add-option-guest.patch deleted file mode 100644 index fd2b980..0000000 --- a/SOURCES/kvm-tools-kvm_stat-add-option-guest.patch +++ /dev/null @@ -1,239 +0,0 @@ -From 8b7b31fc24968fc62be018b9932ea94263e1b586 Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:40 +0200 -Subject: [PATCH 35/69] tools/kvm_stat: add option '--guest' -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-15-david@redhat.com> -Patchwork-id: 77323 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 14/39] tools/kvm_stat: add option '--guest' -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git f9ff1087354e5e063b96a291360a8de84bea0bed - -Convertion of documentation (for man page generation) to texi. - -commit f9ff1087354e5e063b96a291360a8de84bea0bed -Author: Stefan Raspl -Date: Fri Mar 10 13:40:13 2017 +0100 - - tools/kvm_stat: add option '--guest' - - Add a new option '-g'/'--guest' to select a particular process by providing - the QEMU guest name. - Notes: - - The logic to figure out the pid corresponding to the guest name might look - scary, but works pretty reliably in practice; in the unlikely event that it - returns add'l flukes, it will bail out and hint at using '-p' instead, no - harm done. - - Mixing '-g' and '-p' is possible, and the final instance specified on the - command line is the significant one. This is consistent with current - behavior for '-p' which, if specified multiple times, also regards the final - instance as the significant one. - - Signed-off-by: Stefan Raspl - Reviewed-by: Janosch Frank - Signed-off-by: Radim Krčmář - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 101 +++++++++++++++++++++++++++++++++++++++++++++- - scripts/kvm/kvm_stat.texi | 5 +++ - 2 files changed, 104 insertions(+), 2 deletions(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index f2a868b..f263312 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -30,6 +30,7 @@ import fcntl - import resource - import struct - import re -+import subprocess - from collections import defaultdict - - VMX_EXIT_REASONS = { -@@ -320,6 +321,30 @@ def parse_int_list(list_string): - return integers - - -+def get_pid_from_gname(gname): -+ """Fuzzy function to convert guest name to QEMU process pid. -+ -+ Returns a list of potential pids, can be empty if no match found. -+ Throws an exception on processing errors. -+ -+ """ -+ pids = [] -+ try: -+ child = subprocess.Popen(['ps', '-A', '--format', 'pid,args'], -+ stdout=subprocess.PIPE) -+ except: -+ raise Exception -+ for line in child.stdout: -+ line = line.lstrip().split(' ', 1) -+ # perform a sanity check before calling the more expensive -+ # function to possibly extract the guest name -+ if ' -name ' in line[1] and gname == get_gname_from_pid(line[0]): -+ pids.append(int(line[0])) -+ child.stdout.close() -+ -+ return pids -+ -+ - def get_gname_from_pid(pid): - """Returns the guest name for a QEMU process pid. - -@@ -977,7 +1002,7 @@ class Tui(object): - except re.error: - continue - -- def show_vm_selection(self): -+ def show_vm_selection_by_pid(self): - """Draws PID selection mask. - - Asks for a pid until a valid pid or 0 has been entered. -@@ -1016,6 +1041,50 @@ class Tui(object): - msg = '"' + str(pid) + '": Not a valid pid' - continue - -+ def show_vm_selection_by_guest_name(self): -+ """Draws guest selection mask. -+ -+ Asks for a guest name until a valid guest name or '' is entered. -+ -+ """ -+ msg = '' -+ while True: -+ self.screen.erase() -+ self.screen.addstr(0, 0, -+ 'Show statistics for specific guest.', -+ curses.A_BOLD) -+ self.screen.addstr(1, 0, -+ 'This might limit the shown data to the trace ' -+ 'statistics.') -+ self.screen.addstr(5, 0, msg) -+ curses.echo() -+ self.screen.addstr(3, 0, "Guest [ENTER or guest]: ") -+ gname = self.screen.getstr() -+ curses.noecho() -+ -+ if not gname: -+ self.refresh_header(0) -+ self.update_pid(0) -+ break -+ else: -+ pids = [] -+ try: -+ pids = get_pid_from_gname(gname) -+ except: -+ msg = '"' + gname + '": Internal error while searching, ' \ -+ 'use pid filter instead' -+ continue -+ if len(pids) == 0: -+ msg = '"' + gname + '": Not an active guest' -+ continue -+ if len(pids) > 1: -+ msg = '"' + gname + '": Multiple matches found, use pid ' \ -+ 'filter instead' -+ continue -+ self.refresh_header(pids[0]) -+ self.update_pid(pids[0]) -+ break -+ - def show_stats(self): - """Refreshes the screen and processes user input.""" - sleeptime = DELAY_INITIAL -@@ -1035,8 +1104,11 @@ class Tui(object): - if char == 'f': - self.show_filter_selection() - sleeptime = DELAY_INITIAL -+ if char == 'g': -+ self.show_vm_selection_by_guest_name() -+ sleeptime = DELAY_INITIAL - if char == 'p': -- self.show_vm_selection() -+ self.show_vm_selection_by_pid() - sleeptime = DELAY_INITIAL - except KeyboardInterrupt: - break -@@ -1106,6 +1178,7 @@ Requirements: - - Interactive Commands: - f filter by regular expression -+ g filter by guest name - p filter by PID - q quit - x toggle reporting of stats for individual child trace events -@@ -1119,6 +1192,22 @@ Press any other key to refresh statistics immediately. - else: - return "" - -+ def cb_guest_to_pid(option, opt, val, parser): -+ try: -+ pids = get_pid_from_gname(val) -+ except: -+ raise optparse.OptionValueError('Error while searching for guest ' -+ '"{}", use "-p" to specify a pid ' -+ 'instead'.format(val)) -+ if len(pids) == 0: -+ raise optparse.OptionValueError('No guest by the name "{}" ' -+ 'found'.format(val)) -+ if len(pids) > 1: -+ raise optparse.OptionValueError('Multiple processes found (pids: ' -+ '{}) - use "-p" to specify a pid ' -+ 'instead'.format(" ".join(pids))) -+ parser.values.pid = pids[0] -+ - optparser = optparse.OptionParser(description=description_text, - formatter=PlainHelpFormatter()) - optparser.add_option('-1', '--once', '--batch', -@@ -1158,6 +1247,14 @@ Press any other key to refresh statistics immediately. - dest='pid', - help='restrict statistics to pid', - ) -+ optparser.add_option('-g', '--guest', -+ action='callback', -+ type='string', -+ dest='pid', -+ metavar='GUEST', -+ help='restrict statistics to guest by name', -+ callback=cb_guest_to_pid, -+ ) - (options, _) = optparser.parse_args(sys.argv) - return options - -diff --git a/scripts/kvm/kvm_stat.texi b/scripts/kvm/kvm_stat.texi -index 3519cf9..a8c1071 100644 ---- a/scripts/kvm/kvm_stat.texi -+++ b/scripts/kvm/kvm_stat.texi -@@ -27,6 +27,9 @@ While running in regular (interactive) mode, use any of the following keys: - @item f - @kindex f - filter by regular expression -+@item g -+@kindex g -+filter by guest name - @item p - @kindex p - filter by PID -@@ -55,6 +58,8 @@ Press any other key to refresh statistics immediately. - retrieve statistics from debugfs - @item -p, --pid=@var{pid} - limit statistics to one virtual machine (pid) -+@item -g, --guest=@var{guest_name} -+ limit statistics to one virtual machine (guest name) - @item -f, --fields=@var{fields} - fields to display (regex) - @item -h, --help --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-catch-curses-exceptions-only.patch b/SOURCES/kvm-tools-kvm_stat-catch-curses-exceptions-only.patch deleted file mode 100644 index 08b4920..0000000 --- a/SOURCES/kvm-tools-kvm_stat-catch-curses-exceptions-only.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 98cf56caaacda1b1f3ef8b571fe601fe0acdd8bf Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:28 +0200 -Subject: [PATCH 23/69] tools/kvm_stat: catch curses exceptions only -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-3-david@redhat.com> -Patchwork-id: 77311 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 02/39] tools/kvm_stat: catch curses exceptions only -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git 9fc0adfc427a5e3f95f8db8dafabe1eaa3720f4a - -commit 9fc0adfc427a5e3f95f8db8dafabe1eaa3720f4a -Author: Stefan Raspl -Date: Fri Mar 10 13:40:01 2017 +0100 - - tools/kvm_stat: catch curses exceptions only - - The previous version was catching all exceptions, including SIGINT. - We only want to catch the curses exceptions here. - - Signed-off-by: Stefan Raspl - Reviewed-by: Janosch Frank - Reviewed-by: Sascha Silbe - Reviewed-by: Marc Hartmayer - Signed-off-by: Radim Krčmář - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index 8cc83a3..ef47ad7 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -809,7 +809,7 @@ class Tui(object): - # return from C start_color() is ignorable. - try: - curses.start_color() -- except: -+ except curses.error: - pass - - # Hide cursor in extra statement as some monochrome terminals --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-display-guest-list-in-pid-guest-sele2.patch b/SOURCES/kvm-tools-kvm_stat-display-guest-list-in-pid-guest-sele2.patch deleted file mode 100644 index 16adf5c..0000000 --- a/SOURCES/kvm-tools-kvm_stat-display-guest-list-in-pid-guest-sele2.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 554fa10df52cbb50ef39ee5eb4ac324610b240ea Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:16:01 +0200 -Subject: [PATCH 56/69] tools/kvm_stat: display guest list in pid/guest - selection screens - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-36-david@redhat.com> -Patchwork-id: 77342 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 35/39] tools/kvm_stat: display guest list in pid/guest selection screens -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git 61f381bb7e1a8e9250aa32b3963a7a5c4b92cbf5 - -commit 61f381bb7e1a8e9250aa32b3963a7a5c4b92cbf5 -Author: Stefan Raspl -Date: Sun Jun 25 21:34:14 2017 +0200 - - tools/kvm_stat: fix error on interactive command 'g' - - Fix an instance where print_all_gnames() is called without the mandatory - argument, resulting in a stack trace. - To reproduce, simply press 'g' in interactive mode. - - Signed-off-by: Stefan Raspl - Signed-off-by: Paolo Bonzini - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index 2cf5176..39476e5 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -1195,7 +1195,7 @@ class Tui(object): - 'This might limit the shown data to the trace ' - 'statistics.') - self.screen.addstr(5, 0, msg) -- self.print_all_gnames() -+ self.print_all_gnames(7) - curses.echo() - self.screen.addstr(3, 0, "Guest [ENTER or guest]: ") - gname = self.screen.getstr() --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-display-guest-list-in-pid-guest-selec.patch b/SOURCES/kvm-tools-kvm_stat-display-guest-list-in-pid-guest-selec.patch deleted file mode 100644 index 67fa011..0000000 --- a/SOURCES/kvm-tools-kvm_stat-display-guest-list-in-pid-guest-selec.patch +++ /dev/null @@ -1,125 +0,0 @@ -From 53a1267b00b7e981a5f67b9d241da6008004d002 Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:16:00 +0200 -Subject: [PATCH 55/69] tools/kvm_stat: display guest list in pid/guest - selection screens - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-35-david@redhat.com> -Patchwork-id: 77338 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 34/39] tools/kvm_stat: display guest list in pid/guest selection screens -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git 865279c53ca9d88718d974bb014b2c6ce259ac75 - -commit 865279c53ca9d88718d974bb014b2c6ce259ac75 -Author: Stefan Raspl -Date: Wed Jun 7 21:08:43 2017 +0200 - - tools/kvm_stat: display guest list in pid/guest selection screens - - Display a (possibly inaccurate) list of all running guests. Note that we - leave a bit of extra room above the list for potential error messages. - Furthermore, we deliberately do not reject pids or guest names that are - not in our list, as we cannot rule out that our fuzzy approach might be - in error somehow. - - Signed-off-by: Stefan Raspl - Signed-off-by: Paolo Bonzini - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 49 +++++++++++++++++++++++++++++++++++++------------ - 1 file changed, 37 insertions(+), 12 deletions(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index cf7aa28..2cf5176 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -894,15 +894,9 @@ class Tui(object): - curses.nocbreak() - curses.endwin() - -- @staticmethod -- def get_pid_from_gname(gname): -- """Fuzzy function to convert guest name to QEMU process pid. -- -- Returns a list of potential pids, can be empty if no match found. -- Throws an exception on processing errors. -- -- """ -- pids = [] -+ def get_all_gnames(self): -+ """Returns a list of (pid, gname) tuples of all running guests""" -+ res = [] - try: - child = subprocess.Popen(['ps', '-A', '--format', 'pid,args'], - stdout=subprocess.PIPE) -@@ -912,11 +906,40 @@ class Tui(object): - line = line.lstrip().split(' ', 1) - # perform a sanity check before calling the more expensive - # function to possibly extract the guest name -- if (' -name ' in line[1] and -- gname == self.get_gname_from_pid(line[0])): -- pids.append(int(line[0])) -+ if ' -name ' in line[1]: -+ res.append((line[0], self.get_gname_from_pid(line[0]))) - child.stdout.close() - -+ return res -+ -+ def print_all_gnames(self, row): -+ """Print a list of all running guests along with their pids.""" -+ self.screen.addstr(row, 2, '%8s %-60s' % -+ ('Pid', 'Guest Name (fuzzy list, might be ' -+ 'inaccurate!)'), -+ curses.A_UNDERLINE) -+ row += 1 -+ try: -+ for line in self.get_all_gnames(): -+ self.screen.addstr(row, 2, '%8s %-60s' % (line[0], line[1])) -+ row += 1 -+ if row >= self.screen.getmaxyx()[0]: -+ break -+ except Exception: -+ self.screen.addstr(row + 1, 2, 'Not available') -+ -+ def get_pid_from_gname(self, gname): -+ """Fuzzy function to convert guest name to QEMU process pid. -+ -+ Returns a list of potential pids, can be empty if no match found. -+ Throws an exception on processing errors. -+ -+ """ -+ pids = [] -+ for line in self.get_all_gnames(): -+ if gname == line[1]: -+ pids.append(int(line[0])) -+ - return pids - - @staticmethod -@@ -1102,6 +1125,7 @@ class Tui(object): - 'This might limit the shown data to the trace ' - 'statistics.') - self.screen.addstr(5, 0, msg) -+ self.print_all_gnames(7) - - curses.echo() - self.screen.addstr(3, 0, "Pid [0 or pid]: ") -@@ -1171,6 +1195,7 @@ class Tui(object): - 'This might limit the shown data to the trace ' - 'statistics.') - self.screen.addstr(5, 0, msg) -+ self.print_all_gnames() - curses.echo() - self.screen.addstr(3, 0, "Guest [ENTER or guest]: ") - gname = self.screen.getstr() --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-display-guest-name-when-using-pid-fil.patch b/SOURCES/kvm-tools-kvm_stat-display-guest-name-when-using-pid-fil.patch deleted file mode 100644 index 434ccef..0000000 --- a/SOURCES/kvm-tools-kvm_stat-display-guest-name-when-using-pid-fil.patch +++ /dev/null @@ -1,110 +0,0 @@ -From 3e1d2fc34c6ff536cfcc2787a98e579ff31550b1 Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:35 +0200 -Subject: [PATCH 30/69] tools/kvm_stat: display guest name when using pid - filter -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-10-david@redhat.com> -Patchwork-id: 77317 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 09/39] tools/kvm_stat: display guest name when using pid filter -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git a24e85f6a69f09a9d09a86110a6bb168c60610ef - -commit a24e85f6a69f09a9d09a86110a6bb168c60610ef -Author: Stefan Raspl -Date: Fri Mar 10 13:40:08 2017 +0100 - - tools/kvm_stat: display guest name when using pid filter - - When running kvm_stat with option '-p' to filter per process, display - the QEMU guest name next to the pid, if available. - - Signed-off-by: Stefan Raspl - Reviewed-By: Janosch Frank - Signed-off-by: Radim Krčmář - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 41 +++++++++++++++++++++++++++++++++++++++-- - 1 file changed, 39 insertions(+), 2 deletions(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index aca8508..95ffa9a 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -320,6 +320,37 @@ def parse_int_list(list_string): - return integers - - -+def get_gname_from_pid(pid): -+ """Returns the guest name for a QEMU process pid. -+ -+ Extracts the guest name from the QEMU comma line by processing the '-name' -+ option. Will also handle names specified out of sequence. -+ -+ """ -+ name = '' -+ try: -+ line = open('/proc/{}/cmdline'.format(pid), 'rb').read().split('\0') -+ parms = line[line.index('-name') + 1].split(',') -+ while '' in parms: -+ # commas are escaped (i.e. ',,'), hence e.g. 'foo,bar' results in -+ # ['foo', '', 'bar'], which we revert here -+ idx = parms.index('') -+ parms[idx - 1] += ',' + parms[idx + 1] -+ del parms[idx:idx+2] -+ # the '-name' switch allows for two ways to specify the guest name, -+ # where the plain name overrides the name specified via 'guest=' -+ for arg in parms: -+ if '=' not in arg: -+ name = arg -+ break -+ if arg[:6] == 'guest=': -+ name = arg[6:] -+ except (ValueError, IOError, IndexError): -+ pass -+ -+ return name -+ -+ - def get_online_cpus(): - """Returns a list of cpu id integers.""" - with open('/sys/devices/system/cpu/online') as cpu_list: -@@ -803,6 +834,7 @@ LABEL_WIDTH = 40 - NUMBER_WIDTH = 10 - DELAY_INITIAL = 0.25 - DELAY_REGULAR = 3.0 -+MAX_GUEST_NAME_LEN = 48 - - - class Tui(object): -@@ -863,9 +895,14 @@ class Tui(object): - if pid is None: - pid = self.stats.pid_filter - self.screen.erase() -+ gname = get_gname_from_pid(pid) -+ if gname: -+ gname = ('({})'.format(gname[:MAX_GUEST_NAME_LEN] + '...' -+ if len(gname) > MAX_GUEST_NAME_LEN -+ else gname)) - if pid > 0: -- self.screen.addstr(0, 0, 'kvm statistics - pid {0}' -- .format(pid), curses.A_BOLD) -+ self.screen.addstr(0, 0, 'kvm statistics - pid {0} {1}' -+ .format(pid, gname), curses.A_BOLD) - else: - self.screen.addstr(0, 0, 'kvm statistics - summary', curses.A_BOLD) - self.screen.addstr(2, 1, 'Event') --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-display-message-indicating-lack-of-ev.patch b/SOURCES/kvm-tools-kvm_stat-display-message-indicating-lack-of-ev.patch deleted file mode 100644 index afea904..0000000 --- a/SOURCES/kvm-tools-kvm_stat-display-message-indicating-lack-of-ev.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 6b557dc235257a9d4e69532f79007a9a4de854c6 Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:54 +0200 -Subject: [PATCH 49/69] tools/kvm_stat: display message indicating lack of - events - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-29-david@redhat.com> -Patchwork-id: 77340 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 28/39] tools/kvm_stat: display message indicating lack of events -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git 5725393764a342b6a5420fdd10184984ca08b5f6 - -commit 5725393764a342b6a5420fdd10184984ca08b5f6 -Author: Stefan Raspl -Date: Wed Jun 7 21:08:35 2017 +0200 - - tools/kvm_stat: display message indicating lack of events - - Give users some indication on the reason why no data is displayed on the - screen yet. - - Signed-off-by: Stefan Raspl - Signed-off-by: Paolo Bonzini - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index 53dcd40..790fbce 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -1013,6 +1013,8 @@ class Tui(object): - (key, values[0], values[0] * 100 / total, - cur)) - row += 1 -+ if row == 3: -+ self.screen.addstr(4, 1, 'No matching events reported yet') - self.screen.refresh() - - def show_filter_selection(self): --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-display-regex-when-set-to-non-default.patch b/SOURCES/kvm-tools-kvm_stat-display-regex-when-set-to-non-default.patch deleted file mode 100644 index 013af6d..0000000 --- a/SOURCES/kvm-tools-kvm_stat-display-regex-when-set-to-non-default.patch +++ /dev/null @@ -1,66 +0,0 @@ -From a0c6451760d3bae225d4cd4e152d862c6e76673e Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:38 +0200 -Subject: [PATCH 33/69] tools/kvm_stat: display regex when set to non-default -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-13-david@redhat.com> -Patchwork-id: 77319 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 12/39] tools/kvm_stat: display regex when set to non-default -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git 72187dfa8e2686b748ad7485d0ca59ba993ba526 - -commit 72187dfa8e2686b748ad7485d0ca59ba993ba526 -Author: Stefan Raspl -Date: Fri Mar 10 13:40:11 2017 +0100 - - tools/kvm_stat: display regex when set to non-default - - If a user defines a regex filter through the interactive command, display - the active regex in the header's second line. - - Signed-off-by: Stefan Raspl - Reviewed-by: Marc Hartmayer - Signed-off-by: Radim Krčmář - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index ced0cb9..af70717 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -835,6 +835,7 @@ NUMBER_WIDTH = 10 - DELAY_INITIAL = 0.25 - DELAY_REGULAR = 3.0 - MAX_GUEST_NAME_LEN = 48 -+MAX_REGEX_LEN = 44 - - - class Tui(object): -@@ -905,6 +906,11 @@ class Tui(object): - .format(pid, gname), curses.A_BOLD) - else: - self.screen.addstr(0, 0, 'kvm statistics - summary', curses.A_BOLD) -+ if self.stats.fields_filter and self.stats.fields_filter != '^[^\(]*$': -+ regex = self.stats.fields_filter -+ if len(regex) > MAX_REGEX_LEN: -+ regex = regex[:MAX_REGEX_LEN] + '...' -+ self.screen.addstr(1, 17, 'regex filter: {0}'.format(regex)) - self.screen.addstr(2, 1, 'Event') - self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH - - len('Total'), 'Total') --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-document-list-of-interactive-commands.patch b/SOURCES/kvm-tools-kvm_stat-document-list-of-interactive-commands.patch deleted file mode 100644 index 823ffef..0000000 --- a/SOURCES/kvm-tools-kvm_stat-document-list-of-interactive-commands.patch +++ /dev/null @@ -1,99 +0,0 @@ -From 2ef292f12dbc13c450bdac0ec48c293ce6a1a7fe Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:34 +0200 -Subject: [PATCH 29/69] tools/kvm_stat: document list of interactive commands -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-9-david@redhat.com> -Patchwork-id: 77315 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 08/39] tools/kvm_stat: document list of interactive commands -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git 1eaa2f9022d55a8d7249c42def8dc4b0d682e142 - -Convertion of documentation (for man page generation) to texi. - -commit 1eaa2f9022d55a8d7249c42def8dc4b0d682e142 -Author: Stefan Raspl -Date: Fri Mar 10 13:40:07 2017 +0100 - - tools/kvm_stat: document list of interactive commands - - Apart from the source code, there does not seem to be a place that documents - the interactive capabilities of kvm_stat yet. - - Signed-off-by: Stefan Raspl - Signed-off-by: Radim Krčmář - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 7 +++++++ - scripts/kvm/kvm_stat.texi | 24 ++++++++++++++++++++++++ - 2 files changed, 31 insertions(+) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index 3e60d93..aca8508 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -1052,6 +1052,13 @@ Requirements: - CAP_SYS_ADMIN and perf events are used. - - CAP_SYS_RESOURCE if the hard limit is not high enough to allow - the large number of files that are possibly opened. -+ -+Interactive Commands: -+ f filter by regular expression -+ p filter by PID -+ q quit -+ x toggle reporting of stats for individual child trace events -+Press any other key to refresh statistics immediately. - """ - - class PlainHelpFormatter(optparse.IndentedHelpFormatter): -diff --git a/scripts/kvm/kvm_stat.texi b/scripts/kvm/kvm_stat.texi -index 4faf1a6..3519cf9 100644 ---- a/scripts/kvm/kvm_stat.texi -+++ b/scripts/kvm/kvm_stat.texi -@@ -17,8 +17,32 @@ The set of KVM kernel module trace events may be specific to the kernel version - or architecture. It is best to check the KVM kernel module source code for the - meaning of events. - -+Use batch and logging modes for scripting purposes. -+ -+@section Interactive Commands -+ -+While running in regular (interactive) mode, use any of the following keys: -+ -+@table @key -+@item f -+@kindex f -+filter by regular expression -+@item p -+@kindex p -+filter by PID -+@item q -+@kindex q -+quit -+@item x -+@kindex x -+toggle reporting of stats for child trace events -+@end table -+ -+Press any other key to refresh statistics immediately. -+ - @c man end - -+ - @c man begin OPTIONS - @table @option - @item -1, --once, --batch --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-fix-command-line-option-g.patch b/SOURCES/kvm-tools-kvm_stat-fix-command-line-option-g.patch deleted file mode 100644 index 6dd8952..0000000 --- a/SOURCES/kvm-tools-kvm_stat-fix-command-line-option-g.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 283aa25f757053d99515887348cdc49e873e577c Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Mon, 8 Jan 2018 21:26:31 +0100 -Subject: [PATCH 01/12] tools/kvm_stat: fix command line option '-g' - -RH-Author: David Hildenbrand -Message-id: <20180108212631.29046-1-david@redhat.com> -Patchwork-id: 78528 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH] tools/kvm_stat: fix command line option '-g' -Bugzilla: 1529676 -RH-Acked-by: Thomas Huth -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi - -commit 19e8e54f4309eaa438237aa1973fe40c331903d4 (HEAD) -Author: Stefan Raspl -Date: Mon Dec 11 12:25:19 2017 +0100 - - tools/kvm_stat: fix command line option '-g' - - Specifying a guest via '-g foo' always results in an error: - $ kvm_stat -g foo - Usage: kvm_stat [options] - - kvm_stat: error: Error while searching for guest "foo", use "-p" to - specify a pid instead - - Reason is that Tui.get_pid_from_gname() is not static, as it is supposed - to be. - - Signed-off-by: Stefan Raspl - Tested-by: Christian Borntraeger - Signed-off-by: Paolo Bonzini - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 10 ++++++---- - 1 file changed, 6 insertions(+), 4 deletions(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index 32283d8..c74a9a0 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -946,7 +946,8 @@ class Tui(object): - curses.nocbreak() - curses.endwin() - -- def get_all_gnames(self): -+ @staticmethod -+ def get_all_gnames(): - """Returns a list of (pid, gname) tuples of all running guests""" - res = [] - try: -@@ -959,7 +960,7 @@ class Tui(object): - # perform a sanity check before calling the more expensive - # function to possibly extract the guest name - if ' -name ' in line[1]: -- res.append((line[0], self.get_gname_from_pid(line[0]))) -+ res.append((line[0], Tui.get_gname_from_pid(line[0]))) - child.stdout.close() - - return res -@@ -980,7 +981,8 @@ class Tui(object): - except Exception: - self.screen.addstr(row + 1, 2, 'Not available') - -- def get_pid_from_gname(self, gname): -+ @staticmethod -+ def get_pid_from_gname(gname): - """Fuzzy function to convert guest name to QEMU process pid. - - Returns a list of potential pids, can be empty if no match found. -@@ -988,7 +990,7 @@ class Tui(object): - - """ - pids = [] -- for line in self.get_all_gnames(): -+ for line in Tui.get_all_gnames(): - if gname == line[1]: - pids.append(int(line[0])) - --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-fix-event-counts-display-for-interrup.patch b/SOURCES/kvm-tools-kvm_stat-fix-event-counts-display-for-interrup.patch deleted file mode 100644 index f7f4849..0000000 --- a/SOURCES/kvm-tools-kvm_stat-fix-event-counts-display-for-interrup.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 7bc419ee18fb59acbd0bf2fc5d31b25b32bc28ea Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:45 +0200 -Subject: [PATCH 40/69] tools/kvm_stat: fix event counts display for - interrupted intervals - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-20-david@redhat.com> -Patchwork-id: 77330 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 19/39] tools/kvm_stat: fix event counts display for interrupted intervals -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git 124c2fc9fdf5fb1d9cea4707d7e5471e317ba3bf - -commit 124c2fc9fdf5fb1d9cea4707d7e5471e317ba3bf -Author: Stefan Raspl -Date: Wed Jun 7 21:08:26 2017 +0200 - - tools/kvm_stat: fix event counts display for interrupted intervals - - When an update interval is interrupted via key press (e.g. space), the - 'Current' column value is calculated using the full interval length - instead of the elapsed time, which leads to lower than actual numbers. - Furthermore, the value should be rounded, not truncated. - This is fixed by using the actual elapsed time for the calculation. - - Signed-off-by: Stefan Raspl - Signed-off-by: Paolo Bonzini - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index 904eb62..b571584 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -1009,7 +1009,8 @@ class Tui(object): - self.screen.addstr(row, col, '%7.1f' % (values[0] * 100 / total,)) - col += 7 - if values[1] is not None: -- self.screen.addstr(row, col, '%8d' % (values[1] / sleeptime,)) -+ self.screen.addstr(row, col, '%8d' % -+ round(values[1] / sleeptime)) - row += 1 - self.screen.refresh() - -@@ -1130,9 +1131,11 @@ class Tui(object): - """Refreshes the screen and processes user input.""" - sleeptime = DELAY_INITIAL - self.refresh_header() -+ start = 0.0 # result based on init value never appears on screen - while True: -- self.refresh_body(sleeptime) -+ self.refresh_body(time.time() - start) - curses.halfdelay(int(sleeptime * 10)) -+ start = time.time() - sleeptime = DELAY_REGULAR - try: - char = self.screen.getkey() --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-fix-misc-glitches.patch b/SOURCES/kvm-tools-kvm_stat-fix-misc-glitches.patch deleted file mode 100644 index c194fea..0000000 --- a/SOURCES/kvm-tools-kvm_stat-fix-misc-glitches.patch +++ /dev/null @@ -1,127 +0,0 @@ -From 8654f68785c5ddddfd92b8fd2b0e550481e3099c Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:30 +0200 -Subject: [PATCH 25/69] tools/kvm_stat: fix misc glitches -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-5-david@redhat.com> -Patchwork-id: 77313 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 04/39] tools/kvm_stat: fix misc glitches -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git e0ba38765c1d1d670246d6f6c518594aa8e62587 - -commit e0ba38765c1d1d670246d6f6c518594aa8e62587 -Author: Stefan Raspl -Date: Fri Mar 10 13:40:03 2017 +0100 - - tools/kvm_stat: fix misc glitches - - Addresses - - eliminate extra import - - missing variable initialization - - type redefinition from int to float - - passing of int type argument instead of string - - a couple of PEP8-reported indentation/formatting glitches - - remove unused variable drilldown in class Tui - - Signed-off-by: Stefan Raspl - Reviewed-by: Marc Hartmayer - Signed-off-by: Radim Krčmář - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 24 +++++++++++------------- - 1 file changed, 11 insertions(+), 13 deletions(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index 14536c0..231186a 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -31,7 +31,6 @@ import resource - import struct - import re - from collections import defaultdict --from time import sleep - - VMX_EXIT_REASONS = { - 'EXCEPTION_NMI': 0, -@@ -657,6 +656,7 @@ class DebugfsProvider(object): - self._fields = self.get_available_fields() - self._pid = 0 - self.do_read = True -+ self.paths = [] - - def get_available_fields(self): - """"Returns a list of available fields. -@@ -794,7 +794,6 @@ class Tui(object): - def __init__(self, stats): - self.stats = stats - self.screen = None -- self.drilldown = False - self.update_drilldown() - - def __enter__(self): -@@ -950,11 +949,10 @@ class Tui(object): - while True: - self.refresh(sleeptime) - curses.halfdelay(int(sleeptime * 10)) -- sleeptime = 3 -+ sleeptime = 3.0 - try: - char = self.screen.getkey() - if char == 'x': -- self.drilldown = not self.drilldown - self.update_drilldown() - if char == 'q': - break -@@ -1064,12 +1062,12 @@ Requirements: - help='fields to display (regex)', - ) - optparser.add_option('-p', '--pid', -- action='store', -- default=0, -- type=int, -- dest='pid', -- help='restrict statistics to pid', -- ) -+ action='store', -+ default=0, -+ type='int', -+ dest='pid', -+ help='restrict statistics to pid', -+ ) - (options, _) = optparser.parse_args(sys.argv) - return options - -@@ -1099,8 +1097,8 @@ def check_access(options): - "Also ensure, that the kvm modules are loaded.\n") - sys.exit(1) - -- if not os.path.exists(PATH_DEBUGFS_TRACING) and (options.tracepoints -- or not options.debugfs): -+ if not os.path.exists(PATH_DEBUGFS_TRACING) and (options.tracepoints or -+ not options.debugfs): - sys.stderr.write("Please enable CONFIG_TRACING in your kernel " - "when using the option -t (default).\n" - "If it is enabled, make {0} readable by the " -@@ -1111,7 +1109,7 @@ def check_access(options): - - sys.stderr.write("Falling back to debugfs statistics!\n") - options.debugfs = True -- sleep(5) -+ time.sleep(5) - - return options - --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-fix-trace-setup-glitch-on-field-updat.patch b/SOURCES/kvm-tools-kvm_stat-fix-trace-setup-glitch-on-field-updat.patch deleted file mode 100644 index 8a4e4c0..0000000 --- a/SOURCES/kvm-tools-kvm_stat-fix-trace-setup-glitch-on-field-updat.patch +++ /dev/null @@ -1,80 +0,0 @@ -From d4525d7460d6d129d3a6e4b94a125afb6a06e6ca Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:31 +0200 -Subject: [PATCH 26/69] tools/kvm_stat: fix trace setup glitch on field updates - in TracepointProvider -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-6-david@redhat.com> -Patchwork-id: 77316 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 05/39] tools/kvm_stat: fix trace setup glitch on field updates in TracepointProvider -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git a183606937489ab5ada2215aa8211374a6b26bd3 - -commit a183606937489ab5ada2215aa8211374a6b26bd3 -Author: Stefan Raspl -Date: Fri Mar 10 13:40:04 2017 +0100 - - tools/kvm_stat: fix trace setup glitch on field updates in TracepointProvider - - Updating the fields of the TracepointProvider does not propagate changes to the - tracepoints. This shows when a pid filter is enabled, whereby subsequent - extensions of the fields of the Tracepoint provider (e.g. by toggling - drilldown) will not modify the tracepoints as required. - To reproduce, select a specific process via interactive command 'p', and - enable drilldown via 'x' - none of the fields with the braces will appear - although they should. - The fix will always leave all available fields in the TracepointProvider - enabled. - - Signed-off-by: Stefan Raspl - Based-on-text-by: Janosch Frank - Signed-off-by: Radim Krčmář - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index 231186a..6207843 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -550,6 +550,7 @@ class TracepointProvider(object): - def setup_traces(self): - """Creates all event and group objects needed to be able to retrieve - data.""" -+ fields = self.get_available_fields() - if self._pid > 0: - # Fetch list of all threads of the monitored pid, as qemu - # starts a thread for each vcpu. -@@ -560,7 +561,7 @@ class TracepointProvider(object): - - # The constant is needed as a buffer for python libs, std - # streams and other files that the script opens. -- newlim = len(groupids) * len(self._fields) + 50 -+ newlim = len(groupids) * len(fields) + 50 - try: - softlim_, hardlim = resource.getrlimit(resource.RLIMIT_NOFILE) - -@@ -576,7 +577,7 @@ class TracepointProvider(object): - - for groupid in groupids: - group = Group() -- for name in self._fields: -+ for name in fields: - tracepoint = name - tracefilter = None - match = re.match(r'(.*)\((.*)\)', name) --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-fix-typo.patch b/SOURCES/kvm-tools-kvm_stat-fix-typo.patch deleted file mode 100644 index f5bea9f..0000000 --- a/SOURCES/kvm-tools-kvm_stat-fix-typo.patch +++ /dev/null @@ -1,48 +0,0 @@ -From e21fb4a96edba8dfc5edada51d15e604444d9cf9 Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:44 +0200 -Subject: [PATCH 39/69] tools/kvm_stat: fix typo - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-19-david@redhat.com> -Patchwork-id: 77324 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 18/39] tools/kvm_stat: fix typo -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git 773bffeeb2f1fca7739516d0a5a814dd14a5cc83 - -commit 773bffeeb2f1fca7739516d0a5a814dd14a5cc83 -Author: Stefan Raspl -Date: Wed Jun 7 21:08:25 2017 +0200 - - tools/kvm_stat: fix typo - - Signed-off-by: Stefan Raspl - Signed-off-by: Paolo Bonzini - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index 8f74ed8..904eb62 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -929,7 +929,7 @@ class Tui(object): - return self - - def __exit__(self, *exception): -- """Resets the terminal to its normal state. Based on curses.wrappre -+ """Resets the terminal to its normal state. Based on curses.wrapper - implementation from the Python standard library.""" - if self.screen: - self.screen.keypad(0) --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-fix-undue-use-of-initial-sleeptime.patch b/SOURCES/kvm-tools-kvm_stat-fix-undue-use-of-initial-sleeptime.patch deleted file mode 100644 index 3ea2f6c..0000000 --- a/SOURCES/kvm-tools-kvm_stat-fix-undue-use-of-initial-sleeptime.patch +++ /dev/null @@ -1,66 +0,0 @@ -From d54183dd4ba5e326ebe193815338b9824d5fef56 Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:46 +0200 -Subject: [PATCH 41/69] tools/kvm_stat: fix undue use of initial sleeptime - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-21-david@redhat.com> -Patchwork-id: 77331 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 20/39] tools/kvm_stat: fix undue use of initial sleeptime -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git 81468d73b6eb0ed251e7c77f2cc44c0f4edb4d36 - -commit 81468d73b6eb0ed251e7c77f2cc44c0f4edb4d36 -Author: Stefan Raspl -Date: Wed Jun 7 21:08:27 2017 +0200 - - tools/kvm_stat: fix undue use of initial sleeptime - - We should not use the initial sleeptime for any key press that does not - switch to a different screen, as that introduces an unaesthetic flicker due - to two updates in quick succession. - - Signed-off-by: Stefan Raspl - Signed-off-by: Paolo Bonzini - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 3 --- - 1 file changed, 3 deletions(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index b571584..6e29e5b 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -1142,14 +1142,12 @@ class Tui(object): - if char == 'x': - self.refresh_header() - self.update_drilldown() -- sleeptime = DELAY_INITIAL - if char == 'q': - break - if char == 'c': - self.stats.fields_filter = DEFAULT_REGEX - self.refresh_header(0) - self.update_pid(0) -- sleeptime = DELAY_INITIAL - if char == 'f': - self.show_filter_selection() - sleeptime = DELAY_INITIAL -@@ -1162,7 +1160,6 @@ class Tui(object): - if char == 'r': - self.refresh_header() - self.stats.reset() -- sleeptime = DELAY_INITIAL - except KeyboardInterrupt: - break - except curses.error: --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-full-PEP8-compliance.patch b/SOURCES/kvm-tools-kvm_stat-full-PEP8-compliance.patch deleted file mode 100644 index 85c742a..0000000 --- a/SOURCES/kvm-tools-kvm_stat-full-PEP8-compliance.patch +++ /dev/null @@ -1,212 +0,0 @@ -From 5f41d9716a2f46f18ee4bf02c9875f1ae0ba53ee Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:32 +0200 -Subject: [PATCH 27/69] tools/kvm_stat: full PEP8 compliance -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-7-david@redhat.com> -Patchwork-id: 77312 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 06/39] tools/kvm_stat: full PEP8 compliance -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git 692c7f6deb553dde2531102cd10ac17ab61438e4 - -commit 692c7f6deb553dde2531102cd10ac17ab61438e4 -Author: Stefan Raspl -Date: Fri Mar 10 13:40:05 2017 +0100 - - tools/kvm_stat: full PEP8 compliance - - Provides all missing empty lines as required for full PEP compliance. - - Signed-off-by: Stefan Raspl - Reviewed-by: Marc Hartmayer - Signed-off-by: Radim Krčmář - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 22 ++++++++++++++++++++++ - 1 file changed, 22 insertions(+) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index 6207843..5c4f248 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -224,6 +224,7 @@ IOCTL_NUMBERS = { - 'RESET': 0x00002403, - } - -+ - class Arch(object): - """Encapsulates global architecture specific data. - -@@ -254,12 +255,14 @@ class Arch(object): - return ArchX86(SVM_EXIT_REASONS) - return - -+ - class ArchX86(Arch): - def __init__(self, exit_reasons): - self.sc_perf_evt_open = 298 - self.ioctl_numbers = IOCTL_NUMBERS - self.exit_reasons = exit_reasons - -+ - class ArchPPC(Arch): - def __init__(self): - self.sc_perf_evt_open = 319 -@@ -274,12 +277,14 @@ class ArchPPC(Arch): - self.ioctl_numbers['SET_FILTER'] = 0x80002406 | char_ptr_size << 16 - self.exit_reasons = {} - -+ - class ArchA64(Arch): - def __init__(self): - self.sc_perf_evt_open = 241 - self.ioctl_numbers = IOCTL_NUMBERS - self.exit_reasons = AARCH64_EXIT_REASONS - -+ - class ArchS390(Arch): - def __init__(self): - self.sc_perf_evt_open = 331 -@@ -341,6 +346,7 @@ def get_filters(): - libc = ctypes.CDLL('libc.so.6', use_errno=True) - syscall = libc.syscall - -+ - class perf_event_attr(ctypes.Structure): - """Struct that holds the necessary data to set up a trace event. - -@@ -369,6 +375,7 @@ class perf_event_attr(ctypes.Structure): - self.size = ctypes.sizeof(self) - self.read_format = PERF_FORMAT_GROUP - -+ - def perf_event_open(attr, pid, cpu, group_fd, flags): - """Wrapper for the sys_perf_evt_open() syscall. - -@@ -394,6 +401,7 @@ PERF_FORMAT_GROUP = 1 << 3 - PATH_DEBUGFS_TRACING = '/sys/kernel/debug/tracing' - PATH_DEBUGFS_KVM = '/sys/kernel/debug/kvm' - -+ - class Group(object): - """Represents a perf event group.""" - -@@ -426,6 +434,7 @@ class Group(object): - struct.unpack(read_format, - os.read(self.events[0].fd, length)))) - -+ - class Event(object): - """Represents a performance event and manages its life cycle.""" - def __init__(self, name, group, trace_cpu, trace_pid, trace_point, -@@ -509,6 +518,7 @@ class Event(object): - """Resets the count of the trace event in the kernel.""" - fcntl.ioctl(self.fd, ARCH.ioctl_numbers['RESET'], 0) - -+ - class TracepointProvider(object): - """Data provider for the stats class. - -@@ -650,6 +660,7 @@ class TracepointProvider(object): - ret[name] += val - return ret - -+ - class DebugfsProvider(object): - """Provides data from the files that KVM creates in the kvm debugfs - folder.""" -@@ -719,6 +730,7 @@ class DebugfsProvider(object): - except IOError: - return 0 - -+ - class Stats(object): - """Manages the data providers and the data they provide. - -@@ -790,6 +802,7 @@ class Stats(object): - LABEL_WIDTH = 40 - NUMBER_WIDTH = 10 - -+ - class Tui(object): - """Instruments curses to draw a nice text ui.""" - def __init__(self, stats): -@@ -859,6 +872,7 @@ class Tui(object): - len('Current'), 'Current') - row = 3 - stats = self.stats.get() -+ - def sortkey(x): - if stats[x][1]: - return (-stats[x][1], -stats[x][0]) -@@ -966,6 +980,7 @@ class Tui(object): - except curses.error: - continue - -+ - def batch(stats): - """Prints statistics in a key, value format.""" - try: -@@ -978,13 +993,16 @@ def batch(stats): - except KeyboardInterrupt: - pass - -+ - def log(stats): - """Prints statistics as reiterating key block, multiple value blocks.""" - keys = sorted(stats.get().iterkeys()) -+ - def banner(): - for k in keys: - print '%s' % k, - print -+ - def statline(): - s = stats.get() - for k in keys: -@@ -1002,6 +1020,7 @@ def log(stats): - except KeyboardInterrupt: - break - -+ - def get_options(): - """Returns processed program arguments.""" - description_text = """ -@@ -1072,6 +1091,7 @@ Requirements: - (options, _) = optparser.parse_args(sys.argv) - return options - -+ - def get_providers(options): - """Returns a list of data providers depending on the passed options.""" - providers = [] -@@ -1085,6 +1105,7 @@ def get_providers(options): - - return providers - -+ - def check_access(options): - """Exits if the current user can't access all needed directories.""" - if not os.path.exists('/sys/kernel/debug'): -@@ -1114,6 +1135,7 @@ def check_access(options): - - return options - -+ - def main(): - options = get_options() - options = check_access(options) --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-handle-SIGINT-in-log-and-batch-modes.patch b/SOURCES/kvm-tools-kvm_stat-handle-SIGINT-in-log-and-batch-modes.patch deleted file mode 100644 index d4fc4ea..0000000 --- a/SOURCES/kvm-tools-kvm_stat-handle-SIGINT-in-log-and-batch-modes.patch +++ /dev/null @@ -1,88 +0,0 @@ -From dada85e20a716597bb06c8684eca7a17a2eb8c5e Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:29 +0200 -Subject: [PATCH 24/69] tools/kvm_stat: handle SIGINT in log and batch modes -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-4-david@redhat.com> -Patchwork-id: 77318 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 03/39] tools/kvm_stat: handle SIGINT in log and batch modes -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git dadf1e7839243474b691ca4258bfd2a59e628a5e - -commit dadf1e7839243474b691ca4258bfd2a59e628a5e -Author: Stefan Raspl -Date: Fri Mar 10 13:40:02 2017 +0100 - - tools/kvm_stat: handle SIGINT in log and batch modes - - SIGINT causes ugly unhandled exceptions in log and batch mode, which we - prevent by catching the exceptions accordingly. - - Signed-off-by: Stefan Raspl - Reviewed-by: Marc Hartmayer - Signed-off-by: Radim Krčmář - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 28 +++++++++++++++++----------- - 1 file changed, 17 insertions(+), 11 deletions(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index ef47ad7..14536c0 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -969,12 +969,15 @@ class Tui(object): - - def batch(stats): - """Prints statistics in a key, value format.""" -- s = stats.get() -- time.sleep(1) -- s = stats.get() -- for key in sorted(s.keys()): -- values = s[key] -- print '%-42s%10d%10d' % (key, values[0], values[1]) -+ try: -+ s = stats.get() -+ time.sleep(1) -+ s = stats.get() -+ for key in sorted(s.keys()): -+ values = s[key] -+ print '%-42s%10d%10d' % (key, values[0], values[1]) -+ except KeyboardInterrupt: -+ pass - - def log(stats): - """Prints statistics as reiterating key block, multiple value blocks.""" -@@ -991,11 +994,14 @@ def log(stats): - line = 0 - banner_repeat = 20 - while True: -- time.sleep(1) -- if line % banner_repeat == 0: -- banner() -- statline() -- line += 1 -+ try: -+ time.sleep(1) -+ if line % banner_repeat == 0: -+ banner() -+ statline() -+ line += 1 -+ except KeyboardInterrupt: -+ break - - def get_options(): - """Returns processed program arguments.""" --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-hide-cursor.patch b/SOURCES/kvm-tools-kvm_stat-hide-cursor.patch deleted file mode 100644 index 6ae9e06..0000000 --- a/SOURCES/kvm-tools-kvm_stat-hide-cursor.patch +++ /dev/null @@ -1,62 +0,0 @@ -From beffa30342dc667526c274e71f135c9863a56e61 Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:27 +0200 -Subject: [PATCH 22/69] tools/kvm_stat: hide cursor -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-2-david@redhat.com> -Patchwork-id: 77309 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 01/39] tools/kvm_stat: hide cursor -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git a0b4e6a0325e325d91901342dd436d917da0ddd6 - -commit a0b4e6a0325e325d91901342dd436d917da0ddd6 -Author: Stefan Raspl -Date: Fri Mar 10 13:40:00 2017 +0100 - - tools/kvm_stat: hide cursor - - When running kvm_stat in interactive mode, the cursor appears at the lower - left corner, which looks a bit distracting. - This patch hides the cursor by turning it invisible. - - Signed-off-by: Stefan Raspl - Reviewed-By: Sascha Silbe - Reviewed-by: Marc Hartmayer - Signed-off-by: Radim Krčmář - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index 581278c..8cc83a3 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -812,6 +812,13 @@ class Tui(object): - except: - pass - -+ # Hide cursor in extra statement as some monochrome terminals -+ # might support hiding but not colors. -+ try: -+ curses.curs_set(0) -+ except curses.error: -+ pass -+ - curses.use_default_colors() - return self - --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-make-heading-look-a-bit-more-like-top.patch b/SOURCES/kvm-tools-kvm_stat-make-heading-look-a-bit-more-like-top.patch deleted file mode 100644 index 5674c24..0000000 --- a/SOURCES/kvm-tools-kvm_stat-make-heading-look-a-bit-more-like-top.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 7f50a8be62efbab70573a4dc1ca3afb14f66960a Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:55 +0200 -Subject: [PATCH 50/69] tools/kvm_stat: make heading look a bit more like 'top' - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-30-david@redhat.com> -Patchwork-id: 77343 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 29/39] tools/kvm_stat: make heading look a bit more like 'top' -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git f6d753102a2469ae4ce08ef3e34d170ec583fb50 - -commit f6d753102a2469ae4ce08ef3e34d170ec583fb50 -Author: Stefan Raspl -Date: Wed Jun 7 21:08:36 2017 +0200 - - tools/kvm_stat: make heading look a bit more like 'top' - - Print header in standout font just like the 'top' command does. - - Signed-off-by: Stefan Raspl - Signed-off-by: Paolo Bonzini - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index 790fbce..35147e4 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -982,7 +982,8 @@ class Tui(object): - regex = regex[:MAX_REGEX_LEN] + '...' - self.screen.addstr(1, 17, 'regex filter: {0}'.format(regex)) - self.screen.addstr(2, 1, '%-40s %10s%7s %7s' % -- ('Event', 'Total', '%Total', 'Current')) -+ ('Event', 'Total', '%Total', 'Current'), -+ curses.A_STANDOUT) - self.screen.addstr(4, 1, 'Collecting data...') - self.screen.refresh() - --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-move-functions-to-corresponding-class.patch b/SOURCES/kvm-tools-kvm_stat-move-functions-to-corresponding-class.patch deleted file mode 100644 index 13e3cbf..0000000 --- a/SOURCES/kvm-tools-kvm_stat-move-functions-to-corresponding-class.patch +++ /dev/null @@ -1,516 +0,0 @@ -From 1dbc0659acce676594060b331eb4d854d26eed0c Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:52 +0200 -Subject: [PATCH 47/69] tools/kvm_stat: move functions to corresponding classes - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-27-david@redhat.com> -Patchwork-id: 77334 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 26/39] tools/kvm_stat: move functions to corresponding classes -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git 099a2dfc674e3333bd4ff5e5b106ccd788aa46d7 - -commit 099a2dfc674e3333bd4ff5e5b106ccd788aa46d7 -Author: Stefan Raspl -Date: Wed Jun 7 21:08:33 2017 +0200 - - tools/kvm_stat: move functions to corresponding classes - - Quite a few of the functions are used only in a single class. Moving - functions accordingly to improve the overall structure. - Furthermore, introduce a base class for the providers, which might also - come handy for future extensions. - - Signed-off-by: Stefan Raspl - Signed-off-by: Paolo Bonzini - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 327 ++++++++++++++++++++++++++------------------------- - 1 file changed, 165 insertions(+), 162 deletions(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index b8522d2..f81ed20 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -295,121 +295,6 @@ class ArchS390(Arch): - ARCH = Arch.get_arch() - - --def is_field_wanted(fields_filter, field): -- """Indicate whether field is valid according to fields_filter.""" -- if not fields_filter: -- return True -- return re.match(fields_filter, field) is not None -- -- --def walkdir(path): -- """Returns os.walk() data for specified directory. -- -- As it is only a wrapper it returns the same 3-tuple of (dirpath, -- dirnames, filenames). -- """ -- return next(os.walk(path)) -- -- --def parse_int_list(list_string): -- """Returns an int list from a string of comma separated integers and -- integer ranges.""" -- integers = [] -- members = list_string.split(',') -- -- for member in members: -- if '-' not in member: -- integers.append(int(member)) -- else: -- int_range = member.split('-') -- integers.extend(range(int(int_range[0]), -- int(int_range[1]) + 1)) -- -- return integers -- -- --def get_pid_from_gname(gname): -- """Fuzzy function to convert guest name to QEMU process pid. -- -- Returns a list of potential pids, can be empty if no match found. -- Throws an exception on processing errors. -- -- """ -- pids = [] -- try: -- child = subprocess.Popen(['ps', '-A', '--format', 'pid,args'], -- stdout=subprocess.PIPE) -- except: -- raise Exception -- for line in child.stdout: -- line = line.lstrip().split(' ', 1) -- # perform a sanity check before calling the more expensive -- # function to possibly extract the guest name -- if ' -name ' in line[1] and gname == get_gname_from_pid(line[0]): -- pids.append(int(line[0])) -- child.stdout.close() -- -- return pids -- -- --def get_gname_from_pid(pid): -- """Returns the guest name for a QEMU process pid. -- -- Extracts the guest name from the QEMU comma line by processing the '-name' -- option. Will also handle names specified out of sequence. -- -- """ -- name = '' -- try: -- line = open('/proc/{}/cmdline'.format(pid), 'rb').read().split('\0') -- parms = line[line.index('-name') + 1].split(',') -- while '' in parms: -- # commas are escaped (i.e. ',,'), hence e.g. 'foo,bar' results in -- # ['foo', '', 'bar'], which we revert here -- idx = parms.index('') -- parms[idx - 1] += ',' + parms[idx + 1] -- del parms[idx:idx+2] -- # the '-name' switch allows for two ways to specify the guest name, -- # where the plain name overrides the name specified via 'guest=' -- for arg in parms: -- if '=' not in arg: -- name = arg -- break -- if arg[:6] == 'guest=': -- name = arg[6:] -- except (ValueError, IOError, IndexError): -- pass -- -- return name -- -- --def get_online_cpus(): -- """Returns a list of cpu id integers.""" -- with open('/sys/devices/system/cpu/online') as cpu_list: -- cpu_string = cpu_list.readline() -- return parse_int_list(cpu_string) -- -- --def get_filters(): -- """Returns a dict of trace events, their filter ids and -- the values that can be filtered. -- -- Trace events can be filtered for special values by setting a -- filter string via an ioctl. The string normally has the format -- identifier==value. For each filter a new event will be created, to -- be able to distinguish the events. -- -- """ -- filters = {} -- filters['kvm_userspace_exit'] = ('reason', USERSPACE_EXIT_REASONS) -- if ARCH.exit_reasons: -- filters['kvm_exit'] = ('exit_reason', ARCH.exit_reasons) -- return filters -- --libc = ctypes.CDLL('libc.so.6', use_errno=True) --syscall = libc.syscall -- -- - class perf_event_attr(ctypes.Structure): - """Struct that holds the necessary data to set up a trace event. - -@@ -439,25 +324,6 @@ class perf_event_attr(ctypes.Structure): - self.read_format = PERF_FORMAT_GROUP - - --def perf_event_open(attr, pid, cpu, group_fd, flags): -- """Wrapper for the sys_perf_evt_open() syscall. -- -- Used to set up performance events, returns a file descriptor or -1 -- on error. -- -- Attributes are: -- - syscall number -- - struct perf_event_attr * -- - pid or -1 to monitor all pids -- - cpu number or -1 to monitor all cpus -- - The file descriptor of the group leader or -1 to create a group. -- - flags -- -- """ -- return syscall(ARCH.sc_perf_evt_open, ctypes.pointer(attr), -- ctypes.c_int(pid), ctypes.c_int(cpu), -- ctypes.c_int(group_fd), ctypes.c_long(flags)) -- - PERF_TYPE_TRACEPOINT = 2 - PERF_FORMAT_GROUP = 1 << 3 - -@@ -502,6 +368,8 @@ class Event(object): - """Represents a performance event and manages its life cycle.""" - def __init__(self, name, group, trace_cpu, trace_pid, trace_point, - trace_filter, trace_set='kvm'): -+ self.libc = ctypes.CDLL('libc.so.6', use_errno=True) -+ self.syscall = self.libc.syscall - self.name = name - self.fd = None - self.setup_event(group, trace_cpu, trace_pid, trace_point, -@@ -518,6 +386,25 @@ class Event(object): - if self.fd: - os.close(self.fd) - -+ def perf_event_open(self, attr, pid, cpu, group_fd, flags): -+ """Wrapper for the sys_perf_evt_open() syscall. -+ -+ Used to set up performance events, returns a file descriptor or -1 -+ on error. -+ -+ Attributes are: -+ - syscall number -+ - struct perf_event_attr * -+ - pid or -1 to monitor all pids -+ - cpu number or -1 to monitor all cpus -+ - The file descriptor of the group leader or -1 to create a group. -+ - flags -+ -+ """ -+ return self.syscall(ARCH.sc_perf_evt_open, ctypes.pointer(attr), -+ ctypes.c_int(pid), ctypes.c_int(cpu), -+ ctypes.c_int(group_fd), ctypes.c_long(flags)) -+ - def setup_event_attribute(self, trace_set, trace_point): - """Returns an initialized ctype perf_event_attr struct.""" - -@@ -546,8 +433,8 @@ class Event(object): - if group.events: - group_leader = group.events[0].fd - -- fd = perf_event_open(event_attr, trace_pid, -- trace_cpu, group_leader, 0) -+ fd = self.perf_event_open(event_attr, trace_pid, -+ trace_cpu, group_leader, 0) - if fd == -1: - err = ctypes.get_errno() - raise OSError(err, os.strerror(err), -@@ -582,7 +469,26 @@ class Event(object): - fcntl.ioctl(self.fd, ARCH.ioctl_numbers['RESET'], 0) - - --class TracepointProvider(object): -+class Provider(object): -+ """Encapsulates functionalities used by all providers.""" -+ @staticmethod -+ def is_field_wanted(fields_filter, field): -+ """Indicate whether field is valid according to fields_filter.""" -+ if not fields_filter: -+ return True -+ return re.match(fields_filter, field) is not None -+ -+ @staticmethod -+ def walkdir(path): -+ """Returns os.walk() data for specified directory. -+ -+ As it is only a wrapper it returns the same 3-tuple of (dirpath, -+ dirnames, filenames). -+ """ -+ return next(os.walk(path)) -+ -+ -+class TracepointProvider(Provider): - """Data provider for the stats class. - - Manages the events/groups from which it acquires its data. -@@ -590,10 +496,27 @@ class TracepointProvider(object): - """ - def __init__(self, pid, fields_filter): - self.group_leaders = [] -- self.filters = get_filters() -+ self.filters = self.get_filters() - self.update_fields(fields_filter) - self.pid = pid - -+ @staticmethod -+ def get_filters(): -+ """Returns a dict of trace events, their filter ids and -+ the values that can be filtered. -+ -+ Trace events can be filtered for special values by setting a -+ filter string via an ioctl. The string normally has the format -+ identifier==value. For each filter a new event will be created, to -+ be able to distinguish the events. -+ -+ """ -+ filters = {} -+ filters['kvm_userspace_exit'] = ('reason', USERSPACE_EXIT_REASONS) -+ if ARCH.exit_reasons: -+ filters['kvm_exit'] = ('exit_reason', ARCH.exit_reasons) -+ return filters -+ - def get_available_fields(self): - """Returns a list of available event's of format 'event name(filter - name)'. -@@ -610,7 +533,7 @@ class TracepointProvider(object): - - """ - path = os.path.join(PATH_DEBUGFS_TRACING, 'events', 'kvm') -- fields = walkdir(path)[1] -+ fields = self.walkdir(path)[1] - extra = [] - for field in fields: - if field in self.filters: -@@ -623,7 +546,30 @@ class TracepointProvider(object): - def update_fields(self, fields_filter): - """Refresh fields, applying fields_filter""" - self._fields = [field for field in self.get_available_fields() -- if is_field_wanted(fields_filter, field)] -+ if self.is_field_wanted(fields_filter, field)] -+ -+ @staticmethod -+ def get_online_cpus(): -+ """Returns a list of cpu id integers.""" -+ def parse_int_list(list_string): -+ """Returns an int list from a string of comma separated integers and -+ integer ranges.""" -+ integers = [] -+ members = list_string.split(',') -+ -+ for member in members: -+ if '-' not in member: -+ integers.append(int(member)) -+ else: -+ int_range = member.split('-') -+ integers.extend(range(int(int_range[0]), -+ int(int_range[1]) + 1)) -+ -+ return integers -+ -+ with open('/sys/devices/system/cpu/online') as cpu_list: -+ cpu_string = cpu_list.readline() -+ return parse_int_list(cpu_string) - - def setup_traces(self): - """Creates all event and group objects needed to be able to retrieve -@@ -633,9 +579,9 @@ class TracepointProvider(object): - # Fetch list of all threads of the monitored pid, as qemu - # starts a thread for each vcpu. - path = os.path.join('/proc', str(self._pid), 'task') -- groupids = walkdir(path)[1] -+ groupids = self.walkdir(path)[1] - else: -- groupids = get_online_cpus() -+ groupids = self.get_online_cpus() - - # The constant is needed as a buffer for python libs, std - # streams and other files that the script opens. -@@ -732,7 +678,7 @@ class TracepointProvider(object): - event.reset() - - --class DebugfsProvider(object): -+class DebugfsProvider(Provider): - """Provides data from the files that KVM creates in the kvm debugfs - folder.""" - def __init__(self, pid, fields_filter): -@@ -748,12 +694,12 @@ class DebugfsProvider(object): - The fields are all available KVM debugfs files - - """ -- return walkdir(PATH_DEBUGFS_KVM)[2] -+ return self.walkdir(PATH_DEBUGFS_KVM)[2] - - def update_fields(self, fields_filter): - """Refresh fields, applying fields_filter""" - self._fields = [field for field in self.get_available_fields() -- if is_field_wanted(fields_filter, field)] -+ if self.is_field_wanted(fields_filter, field)] - - @property - def fields(self): -@@ -772,7 +718,7 @@ class DebugfsProvider(object): - def pid(self, pid): - self._pid = pid - if pid != 0: -- vms = walkdir(PATH_DEBUGFS_KVM)[1] -+ vms = self.walkdir(PATH_DEBUGFS_KVM)[1] - if len(vms) == 0: - self.do_read = False - -@@ -834,11 +780,23 @@ class Stats(object): - - """ - def __init__(self, options): -- self.providers = get_providers(options) -+ self.providers = self.get_providers(options) - self._pid_filter = options.pid - self._fields_filter = options.fields - self.values = {} - -+ @staticmethod -+ def get_providers(options): -+ """Returns a list of data providers depending on the passed options.""" -+ providers = [] -+ -+ if options.debugfs: -+ providers.append(DebugfsProvider(options.pid, options.fields)) -+ if options.tracepoints or not providers: -+ providers.append(TracepointProvider(options.pid, options.fields)) -+ -+ return providers -+ - def update_provider_filters(self): - """Propagates fields filters to providers.""" - # As we reset the counters when updating the fields we can -@@ -933,6 +891,63 @@ class Tui(object): - curses.nocbreak() - curses.endwin() - -+ @staticmethod -+ def get_pid_from_gname(gname): -+ """Fuzzy function to convert guest name to QEMU process pid. -+ -+ Returns a list of potential pids, can be empty if no match found. -+ Throws an exception on processing errors. -+ -+ """ -+ pids = [] -+ try: -+ child = subprocess.Popen(['ps', '-A', '--format', 'pid,args'], -+ stdout=subprocess.PIPE) -+ except: -+ raise Exception -+ for line in child.stdout: -+ line = line.lstrip().split(' ', 1) -+ # perform a sanity check before calling the more expensive -+ # function to possibly extract the guest name -+ if (' -name ' in line[1] and -+ gname == self.get_gname_from_pid(line[0])): -+ pids.append(int(line[0])) -+ child.stdout.close() -+ -+ return pids -+ -+ @staticmethod -+ def get_gname_from_pid(pid): -+ """Returns the guest name for a QEMU process pid. -+ -+ Extracts the guest name from the QEMU comma line by processing the -+ '-name' option. Will also handle names specified out of sequence. -+ -+ """ -+ name = '' -+ try: -+ line = open('/proc/{}/cmdline' -+ .format(pid), 'rb').read().split('\0') -+ parms = line[line.index('-name') + 1].split(',') -+ while '' in parms: -+ # commas are escaped (i.e. ',,'), hence e.g. 'foo,bar' results -+ # in # ['foo', '', 'bar'], which we revert here -+ idx = parms.index('') -+ parms[idx - 1] += ',' + parms[idx + 1] -+ del parms[idx:idx+2] -+ # the '-name' switch allows for two ways to specify the guest name, -+ # where the plain name overrides the name specified via 'guest=' -+ for arg in parms: -+ if '=' not in arg: -+ name = arg -+ break -+ if arg[:6] == 'guest=': -+ name = arg[6:] -+ except (ValueError, IOError, IndexError): -+ pass -+ -+ return name -+ - def update_drilldown(self): - """Sets or removes a filter that only allows fields without braces.""" - if not self.stats.fields_filter: -@@ -950,7 +965,7 @@ class Tui(object): - if pid is None: - pid = self.stats.pid_filter - self.screen.erase() -- gname = get_gname_from_pid(pid) -+ gname = self.get_gname_from_pid(pid) - if gname: - gname = ('({})'.format(gname[:MAX_GUEST_NAME_LEN] + '...' - if len(gname) > MAX_GUEST_NAME_LEN -@@ -1096,7 +1111,7 @@ class Tui(object): - else: - pids = [] - try: -- pids = get_pid_from_gname(gname) -+ pids = self.get_pid_from_gname(gname) - except: - msg = '"' + gname + '": Internal error while searching, ' \ - 'use pid filter instead' -@@ -1229,7 +1244,7 @@ Press any other key to refresh statistics immediately. - - def cb_guest_to_pid(option, opt, val, parser): - try: -- pids = get_pid_from_gname(val) -+ pids = Tui.get_pid_from_gname(val) - except: - raise optparse.OptionValueError('Error while searching for guest ' - '"{}", use "-p" to specify a pid ' -@@ -1294,18 +1309,6 @@ Press any other key to refresh statistics immediately. - return options - - --def get_providers(options): -- """Returns a list of data providers depending on the passed options.""" -- providers = [] -- -- if options.debugfs: -- providers.append(DebugfsProvider(options.pid, options.fields)) -- if options.tracepoints or not providers: -- providers.append(TracepointProvider(options.pid, options.fields)) -- -- return providers -- -- - def check_access(options): - """Exits if the current user can't access all needed directories.""" - if not os.path.exists('/sys/kernel/debug'): --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-print-error-messages-on-faulty-pid-fi.patch b/SOURCES/kvm-tools-kvm_stat-print-error-messages-on-faulty-pid-fi.patch deleted file mode 100644 index 57c415a..0000000 --- a/SOURCES/kvm-tools-kvm_stat-print-error-messages-on-faulty-pid-fi.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 05cc1c1aab959dde7801cabe184c5f4b287835b6 Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:37 +0200 -Subject: [PATCH 32/69] tools/kvm_stat: print error messages on faulty pid - filter input -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-12-david@redhat.com> -Patchwork-id: 77321 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 11/39] tools/kvm_stat: print error messages on faulty pid filter input -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git 0152c20f0400498774ae56067f8076cef312abc7 - -commit 0152c20f0400498774ae56067f8076cef312abc7 -Author: Stefan Raspl -Date: Fri Mar 10 13:40:10 2017 +0100 - - tools/kvm_stat: print error messages on faulty pid filter input - - Print helpful messages in case users enter invalid input or invalid pids in - the interactive pid filter dialogue. - - Signed-off-by: Stefan Raspl - Reviewed-by: Marc Hartmayer - Signed-off-by: Radim Krčmář - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index 9e9eb98..ced0cb9 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -976,6 +976,7 @@ class Tui(object): - Asks for a pid until a valid pid or 0 has been entered. - - """ -+ msg = '' - while True: - self.screen.erase() - self.screen.addstr(0, 0, -@@ -984,6 +985,7 @@ class Tui(object): - self.screen.addstr(1, 0, - 'This might limit the shown data to the trace ' - 'statistics.') -+ self.screen.addstr(5, 0, msg) - - curses.echo() - self.screen.addstr(3, 0, "Pid [0 or pid]: ") -@@ -995,6 +997,7 @@ class Tui(object): - pid = int(pid) - if pid != 0 and not os.path.isdir(os.path.join('/proc/', - str(pid))): -+ msg = '"' + str(pid) + '": Not a running process' - continue - else: - pid = 0 -@@ -1003,6 +1006,7 @@ class Tui(object): - break - - except ValueError: -+ msg = '"' + str(pid) + '": Not a valid pid' - continue - - def show_stats(self): --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-reduce-perceived-idle-time-on-filter-.patch b/SOURCES/kvm-tools-kvm_stat-reduce-perceived-idle-time-on-filter-.patch deleted file mode 100644 index 3ca2a8b..0000000 --- a/SOURCES/kvm-tools-kvm_stat-reduce-perceived-idle-time-on-filter-.patch +++ /dev/null @@ -1,161 +0,0 @@ -From 5bf653923c85a01b85fe801b3a752938424ce659 Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:33 +0200 -Subject: [PATCH 28/69] tools/kvm_stat: reduce perceived idle time on filter - updates -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-8-david@redhat.com> -Patchwork-id: 77314 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 07/39] tools/kvm_stat: reduce perceived idle time on filter updates -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git 184b2d23b057b35fba7fd4049962a897ef0e3f9d - -commit 184b2d23b057b35fba7fd4049962a897ef0e3f9d -Author: Stefan Raspl -Date: Fri Mar 10 13:40:06 2017 +0100 - - tools/kvm_stat: reduce perceived idle time on filter updates - - Whenever a user adds a filter, we - * redraw the header immediately for a snappy response - * print a message indicating to the user that we're busy while the - noticeable delay induced by updating all of the stats objects takes place - * update the statistics ASAP (i.e. after 0.25s instead of 3s) to be - consistent with behavior on startup - To do so, we split the Tui's refresh() method to allow for drawing header - and stats separately, and trigger a header refresh whenever we are about - to do something that takes a while - like updating filters. - - Signed-off-by: Stefan Raspl - Signed-off-by: Radim Krčmář - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 48 ++++++++++++++++++++++++++++++------------------ - 1 file changed, 30 insertions(+), 18 deletions(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index 5c4f248..3e60d93 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -801,6 +801,8 @@ class Stats(object): - - LABEL_WIDTH = 40 - NUMBER_WIDTH = 10 -+DELAY_INITIAL = 0.25 -+DELAY_REGULAR = 3.0 - - - class Tui(object): -@@ -856,13 +858,14 @@ class Tui(object): - """Propagates pid selection to stats object.""" - self.stats.pid_filter = pid - -- def refresh(self, sleeptime): -- """Refreshes on-screen data.""" -+ def refresh_header(self, pid=None): -+ """Refreshes the header.""" -+ if pid is None: -+ pid = self.stats.pid_filter - self.screen.erase() -- if self.stats.pid_filter > 0: -+ if pid > 0: - self.screen.addstr(0, 0, 'kvm statistics - pid {0}' -- .format(self.stats.pid_filter), -- curses.A_BOLD) -+ .format(pid), curses.A_BOLD) - else: - self.screen.addstr(0, 0, 'kvm statistics - summary', curses.A_BOLD) - self.screen.addstr(2, 1, 'Event') -@@ -870,7 +873,13 @@ class Tui(object): - len('Total'), 'Total') - self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH + 8 - - len('Current'), 'Current') -+ self.screen.addstr(4, 1, 'Collecting data...') -+ self.screen.refresh() -+ -+ def refresh_body(self, sleeptime): - row = 3 -+ self.screen.move(row, 0) -+ self.screen.clrtobot() - stats = self.stats.get() - - def sortkey(x): -@@ -914,10 +923,12 @@ class Tui(object): - regex = self.screen.getstr() - curses.noecho() - if len(regex) == 0: -+ self.refresh_header() - return - try: - re.compile(regex) - self.stats.fields_filter = regex -+ self.refresh_header() - return - except re.error: - continue -@@ -944,37 +955,38 @@ class Tui(object): - - try: - pid = int(pid) -- -- if pid == 0: -- self.update_pid(pid) -- break -- else: -- if not os.path.isdir(os.path.join('/proc/', str(pid))): -- continue -- else: -- self.update_pid(pid) -- break -+ if pid != 0 and not os.path.isdir(os.path.join('/proc/', -+ str(pid))): -+ continue -+ self.refresh_header(pid) -+ self.update_pid(pid) -+ break - - except ValueError: - continue - - def show_stats(self): - """Refreshes the screen and processes user input.""" -- sleeptime = 0.25 -+ sleeptime = DELAY_INITIAL -+ self.refresh_header() - while True: -- self.refresh(sleeptime) -+ self.refresh_body(sleeptime) - curses.halfdelay(int(sleeptime * 10)) -- sleeptime = 3.0 -+ sleeptime = DELAY_REGULAR - try: - char = self.screen.getkey() - if char == 'x': -+ self.refresh_header() - self.update_drilldown() -+ sleeptime = DELAY_INITIAL - if char == 'q': - break - if char == 'f': - self.show_filter_selection() -+ sleeptime = DELAY_INITIAL - if char == 'p': - self.show_vm_selection() -+ sleeptime = DELAY_INITIAL - except KeyboardInterrupt: - break - except curses.error: --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-remove-extra-statement.patch b/SOURCES/kvm-tools-kvm_stat-remove-extra-statement.patch deleted file mode 100644 index 6d19276..0000000 --- a/SOURCES/kvm-tools-kvm_stat-remove-extra-statement.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 92d06e843c4d105175e2e1961f94ce879f84630f Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:50 +0200 -Subject: [PATCH 45/69] tools/kvm_stat: remove extra statement - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-25-david@redhat.com> -Patchwork-id: 77332 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 24/39] tools/kvm_stat: remove extra statement -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git 5e3823a49c50d70cc6b92808c262a43cf3505f3c - -commit 5e3823a49c50d70cc6b92808c262a43cf3505f3c -Author: Stefan Raspl -Date: Wed Jun 7 21:08:31 2017 +0200 - - tools/kvm_stat: remove extra statement - - Signed-off-by: Stefan Raspl - Signed-off-by: Paolo Bonzini - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index 1b8626b..e38791d 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -1066,7 +1066,6 @@ class Tui(object): - - except ValueError: - msg = '"' + str(pid) + '": Not a valid pid' -- continue - - def show_vm_selection_by_guest_name(self): - """Draws guest selection mask. --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-remove-pid-filter-on-empty-input.patch b/SOURCES/kvm-tools-kvm_stat-remove-pid-filter-on-empty-input.patch deleted file mode 100644 index 0b9a4d3..0000000 --- a/SOURCES/kvm-tools-kvm_stat-remove-pid-filter-on-empty-input.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 66f2e8203e1d29f8ec656f5e333dbc1f13229f9f Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:36 +0200 -Subject: [PATCH 31/69] tools/kvm_stat: remove pid filter on empty input -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-11-david@redhat.com> -Patchwork-id: 77320 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 10/39] tools/kvm_stat: remove pid filter on empty input -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git be03ea3b77387db36617d71d60ee182a866fb9cd - -commit be03ea3b77387db36617d71d60ee182a866fb9cd -Author: Stefan Raspl -Date: Fri Mar 10 13:40:09 2017 +0100 - - tools/kvm_stat: remove pid filter on empty input - - Improve consistency in the interactive dialogue for pid filtering by - removing any filters on empty input (in addition to entering 0). - - Signed-off-by: Stefan Raspl - Reviewed-by: Janosch Frank - Reviewed-by: Marc Hartmayer - Signed-off-by: Radim Krčmář - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 11 +++++++---- - 1 file changed, 7 insertions(+), 4 deletions(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index 95ffa9a..9e9eb98 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -991,10 +991,13 @@ class Tui(object): - curses.noecho() - - try: -- pid = int(pid) -- if pid != 0 and not os.path.isdir(os.path.join('/proc/', -- str(pid))): -- continue -+ if len(pid) > 0: -+ pid = int(pid) -+ if pid != 0 and not os.path.isdir(os.path.join('/proc/', -+ str(pid))): -+ continue -+ else: -+ pid = 0 - self.refresh_header(pid) - self.update_pid(pid) - break --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-remove-regex-filter-on-empty-input.patch b/SOURCES/kvm-tools-kvm_stat-remove-regex-filter-on-empty-input.patch deleted file mode 100644 index 2e71708..0000000 --- a/SOURCES/kvm-tools-kvm_stat-remove-regex-filter-on-empty-input.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 3c7dae7507abb6ebe8c2dd9a4ef76e55135c8acd Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:39 +0200 -Subject: [PATCH 34/69] tools/kvm_stat: remove regex filter on empty input -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-14-david@redhat.com> -Patchwork-id: 77322 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 13/39] tools/kvm_stat: remove regex filter on empty input -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git 645c1728a9d33d78028d93a2ed770f51df0a92c6 - -commit 645c1728a9d33d78028d93a2ed770f51df0a92c6 -Author: Stefan Raspl -Date: Fri Mar 10 13:40:12 2017 +0100 - - tools/kvm_stat: remove regex filter on empty input - - Behavior on empty/0 input for regex and pid filtering was inconsistent, as - the former would keep the current filter, while the latter would (naturally) - remove any pid filtering. - Make things consistent by falling back to the default filter on empty input - for the regex filter dialogue. - - Signed-off-by: Stefan Raspl - Reviewed-by: Marc Hartmayer - Signed-off-by: Radim Krčmář - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index af70717..f2a868b 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -966,6 +966,7 @@ class Tui(object): - regex = self.screen.getstr() - curses.noecho() - if len(regex) == 0: -+ self.stats.fields_filter = r'^[^\(]*$' - self.refresh_header() - return - try: --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-remove-unnecessary-header-redraws.patch b/SOURCES/kvm-tools-kvm_stat-remove-unnecessary-header-redraws.patch deleted file mode 100644 index b7bc8a6..0000000 --- a/SOURCES/kvm-tools-kvm_stat-remove-unnecessary-header-redraws.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 6514729674c1054580cd85feca527740f5476813 Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:47 +0200 -Subject: [PATCH 42/69] tools/kvm_stat: remove unnecessary header redraws - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-22-david@redhat.com> -Patchwork-id: 77327 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 21/39] tools/kvm_stat: remove unnecessary header redraws -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git 2da9d4aaa7348fc13374d7398c9c7027b0a9e2cb - -commit 2da9d4aaa7348fc13374d7398c9c7027b0a9e2cb -Author: Stefan Raspl -Date: Wed Jun 7 21:08:28 2017 +0200 - - tools/kvm_stat: remove unnecessary header redraws - - Certain interactive commands will not modify any information displayed in - the header, hence we can skip them. - - Signed-off-by: Stefan Raspl - Signed-off-by: Paolo Bonzini - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 2 -- - 1 file changed, 2 deletions(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index 6e29e5b..d2526b6 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -1140,7 +1140,6 @@ class Tui(object): - try: - char = self.screen.getkey() - if char == 'x': -- self.refresh_header() - self.update_drilldown() - if char == 'q': - break -@@ -1158,7 +1157,6 @@ class Tui(object): - self.show_vm_selection_by_pid() - sleeptime = DELAY_INITIAL - if char == 'r': -- self.refresh_header() - self.stats.reset() - except KeyboardInterrupt: - break --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-removed-unused-function.patch b/SOURCES/kvm-tools-kvm_stat-removed-unused-function.patch deleted file mode 100644 index ffadfb6..0000000 --- a/SOURCES/kvm-tools-kvm_stat-removed-unused-function.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 35c050e4fdf7eca9ede714377dc427203cc9fd1f Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:49 +0200 -Subject: [PATCH 44/69] tools/kvm_stat: removed unused function - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-24-david@redhat.com> -Patchwork-id: 77337 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 23/39] tools/kvm_stat: simplify line print logic -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git 42a947b77b00da8fb1c9b1350eaa85fd3d53bacb - -commit 42a947b77b00da8fb1c9b1350eaa85fd3d53bacb -Author: Stefan Raspl -Date: Wed Jun 7 21:08:30 2017 +0200 - - tools/kvm_stat: removed unused function - - Function available_fields() is not used in any place. - - Signed-off-by: Stefan Raspl - Reviewed-by: Janosch Frank - Signed-off-by: Paolo Bonzini - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 3 --- - 1 file changed, 3 deletions(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index a527b2f..1b8626b 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -671,9 +671,6 @@ class TracepointProvider(object): - - self.group_leaders.append(group) - -- def available_fields(self): -- return self.get_available_fields() -- - @property - def fields(self): - return self._fields --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-rename-Current-column-to-CurAvg-s.patch b/SOURCES/kvm-tools-kvm_stat-rename-Current-column-to-CurAvg-s.patch deleted file mode 100644 index 1dd883f..0000000 --- a/SOURCES/kvm-tools-kvm_stat-rename-Current-column-to-CurAvg-s.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 8ba2fd89d16cb721110ecff6e95b6eca0a2325f9 Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:56 +0200 -Subject: [PATCH 51/69] tools/kvm_stat: rename 'Current' column to 'CurAvg/s' - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-31-david@redhat.com> -Patchwork-id: 77341 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 30/39] tools/kvm_stat: rename 'Current' column to 'CurAvg/s' -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git 38e89c37a1e05e6e16af582b980534abda29a4d9 - -commit 38e89c37a1e05e6e16af582b980534abda29a4d9 -Author: Stefan Raspl -Date: Wed Jun 7 21:08:37 2017 +0200 - - tools/kvm_stat: rename 'Current' column to 'CurAvg/s' - - 'Current' can be misleading as it doesn't tell whether this is the amount - of events in the last interval or the current average per second. - Note that this necessitates widening the respective column by one more - character. - - Signed-off-by: Stefan Raspl - Signed-off-by: Paolo Bonzini - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index 35147e4..a9e7ea6 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -981,8 +981,8 @@ class Tui(object): - if len(regex) > MAX_REGEX_LEN: - regex = regex[:MAX_REGEX_LEN] + '...' - self.screen.addstr(1, 17, 'regex filter: {0}'.format(regex)) -- self.screen.addstr(2, 1, '%-40s %10s%7s %7s' % -- ('Event', 'Total', '%Total', 'Current'), -+ self.screen.addstr(2, 1, '%-40s %10s%7s %8s' % -+ ('Event', 'Total', '%Total', 'CurAvg/s'), - curses.A_STANDOUT) - self.screen.addstr(4, 1, 'Collecting data...') - self.screen.refresh() -@@ -1010,7 +1010,7 @@ class Tui(object): - break - if values[0] is not None: - cur = int(round(values[1] / sleeptime)) if values[1] else '' -- self.screen.addstr(row, 1, '%-40s %10d%7.1f %7s' % -+ self.screen.addstr(row, 1, '%-40s %10d%7.1f %8s' % - (key, values[0], values[0] * 100 / total, - cur)) - row += 1 --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-show-cursor-in-selection-screens.patch b/SOURCES/kvm-tools-kvm_stat-show-cursor-in-selection-screens.patch deleted file mode 100644 index 876869a..0000000 --- a/SOURCES/kvm-tools-kvm_stat-show-cursor-in-selection-screens.patch +++ /dev/null @@ -1,62 +0,0 @@ -From bf53d773722b8790858a6415540c5011bd25fe8c Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:53 +0200 -Subject: [PATCH 48/69] tools/kvm_stat: show cursor in selection screens - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-28-david@redhat.com> -Patchwork-id: 77335 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 27/39] tools/kvm_stat: show cursor in selection screens -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git 62d1b6cc24d0dedde89e6a39aae1711270aee1c9 - -commit 62d1b6cc24d0dedde89e6a39aae1711270aee1c9 -Author: Stefan Raspl -Date: Wed Jun 7 21:08:34 2017 +0200 - - tools/kvm_stat: show cursor in selection screens - - Show the cursor in the interactive screens to specify pid, filter or guest - name as an orientation for the user. - - Signed-off-by: Stefan Raspl - Signed-off-by: Paolo Bonzini - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index f81ed20..53dcd40 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -1148,13 +1148,19 @@ class Tui(object): - self.refresh_header(0) - self.update_pid(0) - if char == 'f': -+ curses.curs_set(1) - self.show_filter_selection() -+ curses.curs_set(0) - sleeptime = DELAY_INITIAL - if char == 'g': -+ curses.curs_set(1) - self.show_vm_selection_by_guest_name() -+ curses.curs_set(0) - sleeptime = DELAY_INITIAL - if char == 'p': -+ curses.curs_set(1) - self.show_vm_selection_by_pid() -+ curses.curs_set(0) - sleeptime = DELAY_INITIAL - if char == 'r': - self.stats.reset() --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-simplify-initializers.patch b/SOURCES/kvm-tools-kvm_stat-simplify-initializers.patch deleted file mode 100644 index ee8ff2e..0000000 --- a/SOURCES/kvm-tools-kvm_stat-simplify-initializers.patch +++ /dev/null @@ -1,227 +0,0 @@ -From d0ced131bf9b63e3197d5f997e6fe796df69ccec Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:51 +0200 -Subject: [PATCH 46/69] tools/kvm_stat: simplify initializers - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-26-david@redhat.com> -Patchwork-id: 77333 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 25/39] tools/kvm_stat: simplify initializers -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git c469117df05955901d2950b6130770e526b1dbf4 - -commit c469117df05955901d2950b6130770e526b1dbf4 -Author: Stefan Raspl -Date: Wed Jun 7 21:08:32 2017 +0200 - - tools/kvm_stat: simplify initializers - - Simplify a couple of initialization routines: - * TracepointProvider and DebugfsProvider: Pass pid into __init__() instead - of switching to the requested value in an extra call after initializing - to the default first. - * Pass a single options object into Stats.__init__(), delaying options - evaluation accordingly, instead of evaluating options first and passing - several parts of the options object to Stats.__init__() individually. - * Eliminate Stats.update_provider_pid(), since this 2-line function is now - used in a single place only. - * Remove extra call to update_drilldown() in Tui.__init__() by getting the - value of options.fields right initially when parsing options. - * Simplify get_providers() logic. - * Avoid duplicate fields initialization by handling it once in the - providers' __init__() methods. - - Signed-off-by: Stefan Raspl - Signed-off-by: Paolo Bonzini - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 74 +++++++++++++++++++++++++--------------------------- - 1 file changed, 36 insertions(+), 38 deletions(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index e38791d..b8522d2 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -295,6 +295,13 @@ class ArchS390(Arch): - ARCH = Arch.get_arch() - - -+def is_field_wanted(fields_filter, field): -+ """Indicate whether field is valid according to fields_filter.""" -+ if not fields_filter: -+ return True -+ return re.match(fields_filter, field) is not None -+ -+ - def walkdir(path): - """Returns os.walk() data for specified directory. - -@@ -581,11 +588,11 @@ class TracepointProvider(object): - Manages the events/groups from which it acquires its data. - - """ -- def __init__(self): -+ def __init__(self, pid, fields_filter): - self.group_leaders = [] - self.filters = get_filters() -- self._fields = self.get_available_fields() -- self._pid = 0 -+ self.update_fields(fields_filter) -+ self.pid = pid - - def get_available_fields(self): - """Returns a list of available event's of format 'event name(filter -@@ -613,6 +620,11 @@ class TracepointProvider(object): - fields += extra - return fields - -+ def update_fields(self, fields_filter): -+ """Refresh fields, applying fields_filter""" -+ self._fields = [field for field in self.get_available_fields() -+ if is_field_wanted(fields_filter, field)] -+ - def setup_traces(self): - """Creates all event and group objects needed to be able to retrieve - data.""" -@@ -723,13 +735,12 @@ class TracepointProvider(object): - class DebugfsProvider(object): - """Provides data from the files that KVM creates in the kvm debugfs - folder.""" -- def __init__(self): -- self._fields = self.get_available_fields() -+ def __init__(self, pid, fields_filter): -+ self.update_fields(fields_filter) - self._baseline = {} -- self._pid = 0 - self.do_read = True - self.paths = [] -- self.reset() -+ self.pid = pid - - def get_available_fields(self): - """"Returns a list of available fields. -@@ -739,6 +750,11 @@ class DebugfsProvider(object): - """ - return walkdir(PATH_DEBUGFS_KVM)[2] - -+ def update_fields(self, fields_filter): -+ """Refresh fields, applying fields_filter""" -+ self._fields = [field for field in self.get_available_fields() -+ if is_field_wanted(fields_filter, field)] -+ - @property - def fields(self): - return self._fields -@@ -754,9 +770,8 @@ class DebugfsProvider(object): - - @pid.setter - def pid(self, pid): -+ self._pid = pid - if pid != 0: -- self._pid = pid -- - vms = walkdir(PATH_DEBUGFS_KVM)[1] - if len(vms) == 0: - self.do_read = False -@@ -818,33 +833,19 @@ class Stats(object): - provider data. - - """ -- def __init__(self, providers, pid, fields=None): -- self.providers = providers -- self._pid_filter = pid -- self._fields_filter = fields -+ def __init__(self, options): -+ self.providers = get_providers(options) -+ self._pid_filter = options.pid -+ self._fields_filter = options.fields - self.values = {} -- self.update_provider_pid() -- self.update_provider_filters() - - def update_provider_filters(self): - """Propagates fields filters to providers.""" -- def wanted(key): -- if not self._fields_filter: -- return True -- return re.match(self._fields_filter, key) is not None -- - # As we reset the counters when updating the fields we can - # also clear the cache of old values. - self.values = {} - for provider in self.providers: -- provider_fields = [key for key in provider.get_available_fields() -- if wanted(key)] -- provider.fields = provider_fields -- -- def update_provider_pid(self): -- """Propagates pid filters to providers.""" -- for provider in self.providers: -- provider.pid = self._pid_filter -+ provider.update_fields(self._fields_filter) - - def reset(self): - self.values = {} -@@ -870,7 +871,8 @@ class Stats(object): - if pid != self._pid_filter: - self._pid_filter = pid - self.values = {} -- self.update_provider_pid() -+ for provider in self.providers: -+ provider.pid = self._pid_filter - - def get(self): - """Returns a dict with field -> (value, delta to last value) of all -@@ -896,7 +898,6 @@ class Tui(object): - def __init__(self, stats): - self.stats = stats - self.screen = None -- self.update_drilldown() - - def __enter__(self): - """Initialises curses for later use. Based on curses.wrapper -@@ -1270,7 +1271,7 @@ Press any other key to refresh statistics immediately. - ) - optparser.add_option('-f', '--fields', - action='store', -- default=None, -+ default=DEFAULT_REGEX, - dest='fields', - help='fields to display (regex)', - ) -@@ -1297,12 +1298,10 @@ def get_providers(options): - """Returns a list of data providers depending on the passed options.""" - providers = [] - -- if options.tracepoints: -- providers.append(TracepointProvider()) - if options.debugfs: -- providers.append(DebugfsProvider()) -- if len(providers) == 0: -- providers.append(TracepointProvider()) -+ providers.append(DebugfsProvider(options.pid, options.fields)) -+ if options.tracepoints or not providers: -+ providers.append(TracepointProvider(options.pid, options.fields)) - - return providers - -@@ -1347,8 +1346,7 @@ def main(): - sys.stderr.write('Did you use a (unsupported) tid instead of a pid?\n') - sys.exit('Specified pid does not exist.') - -- providers = get_providers(options) -- stats = Stats(providers, options.pid, fields=options.fields) -+ stats = Stats(options) - - if options.log: - log(stats) --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-simplify-line-print-logic.patch b/SOURCES/kvm-tools-kvm_stat-simplify-line-print-logic.patch deleted file mode 100644 index c0581fa..0000000 --- a/SOURCES/kvm-tools-kvm_stat-simplify-line-print-logic.patch +++ /dev/null @@ -1,101 +0,0 @@ -From c4f941df751961aaf2456dfd4ffe7a7a8c0fda4c Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:15:48 +0200 -Subject: [PATCH 43/69] tools/kvm_stat: simplify line print logic - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-23-david@redhat.com> -Patchwork-id: 77329 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 22/39] tools/kvm_stat: simplify line print logic -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git 5a7d11f8dc59ddb36e89dca42a2526ea25914def - -commit 5a7d11f8dc59ddb36e89dca42a2526ea25914def -Author: Stefan Raspl -Date: Wed Jun 7 21:08:29 2017 +0200 - - tools/kvm_stat: simplify line print logic - - Simplify line print logic for header and data lines in interactive mode - as previously suggested by Radim. - While at it, add a space between the first two columns to avoid the - total bleeding into the event name. - Furthermore, for column 'Current', differentiate between no events being - reported (empty 'Current' column) vs the case where events were reported - but the average was rounded down to zero ('0' in 'Current column), for - the folks who appreciate the difference. - Finally: Only skip events which were not reported at all yet, instead of - events that don't have a value in the current interval. - Considered using constants for the field widths in the format strings. - However, that would make things a bit more complicated, and considering - that there are only two places where output happens, I figured it isn't - worth the trouble. - - Signed-off-by: Stefan Raspl - Signed-off-by: Paolo Bonzini - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 26 +++++++------------------- - 1 file changed, 7 insertions(+), 19 deletions(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index d2526b6..a527b2f 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -887,8 +887,6 @@ class Stats(object): - self.values[key] = (newval, newdelta) - return self.values - --LABEL_WIDTH = 40 --NUMBER_WIDTH = 10 - DELAY_INITIAL = 0.25 - DELAY_REGULAR = 3.0 - MAX_GUEST_NAME_LEN = 48 -@@ -970,13 +968,8 @@ class Tui(object): - if len(regex) > MAX_REGEX_LEN: - regex = regex[:MAX_REGEX_LEN] + '...' - self.screen.addstr(1, 17, 'regex filter: {0}'.format(regex)) -- self.screen.addstr(2, 1, 'Event') -- self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH - -- len('Total'), 'Total') -- self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH + 7 - -- len('%Total'), '%Total') -- self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH + 7 + 8 - -- len('Current'), 'Current') -+ self.screen.addstr(2, 1, '%-40s %10s%7s %7s' % -+ ('Event', 'Total', '%Total', 'Current')) - self.screen.addstr(4, 1, 'Collecting data...') - self.screen.refresh() - -@@ -1001,16 +994,11 @@ class Tui(object): - values = stats[key] - if not values[0] and not values[1]: - break -- col = 1 -- self.screen.addstr(row, col, key) -- col += LABEL_WIDTH -- self.screen.addstr(row, col, '%10d' % (values[0],)) -- col += NUMBER_WIDTH -- self.screen.addstr(row, col, '%7.1f' % (values[0] * 100 / total,)) -- col += 7 -- if values[1] is not None: -- self.screen.addstr(row, col, '%8d' % -- round(values[1] / sleeptime)) -+ if values[0] is not None: -+ cur = int(round(values[1] / sleeptime)) if values[1] else '' -+ self.screen.addstr(row, 1, '%-40s %10d%7.1f %7s' % -+ (key, values[0], values[0] * 100 / total, -+ cur)) - row += 1 - self.screen.refresh() - --- -1.8.3.1 - diff --git a/SOURCES/kvm-tools-kvm_stat-use-variables-instead-of-hard-paths-i.patch b/SOURCES/kvm-tools-kvm_stat-use-variables-instead-of-hard-paths-i.patch deleted file mode 100644 index 15bd717..0000000 --- a/SOURCES/kvm-tools-kvm_stat-use-variables-instead-of-hard-paths-i.patch +++ /dev/null @@ -1,63 +0,0 @@ -From ac6ba9a14be2caa8b3b4cb051138b77521ce4b35 Mon Sep 17 00:00:00 2001 -From: David Hildenbrand -Date: Tue, 17 Oct 2017 19:16:04 +0200 -Subject: [PATCH 59/69] tools/kvm_stat: use variables instead of hard paths in - help output - -RH-Author: David Hildenbrand -Message-id: <20171017191605.2378-39-david@redhat.com> -Patchwork-id: 77346 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 38/39] tools/kvm_stat: use variables instead of hard paths in help output -Bugzilla: 1497137 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Cornelia Huck -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Thomas Huth - -Upstream-status: linux.git efcb521943a8df5210f16f312037c2edc3e1449f - -commit efcb521943a8df5210f16f312037c2edc3e1449f -Author: Lin Ma -Date: Tue Jul 25 19:05:53 2017 +0800 - - tools/kvm_stat: use variables instead of hard paths in help output - - Using variables instead of hard paths makes the requirements information - more accurate. - - Signed-off-by: Lin Ma - Signed-off-by: Paolo Bonzini - -Signed-off-by: David Hildenbrand -Signed-off-by: Miroslav Rezanina ---- - scripts/kvm/kvm_stat | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat -index dd8f00c..5704044 100755 ---- a/scripts/kvm/kvm_stat -+++ b/scripts/kvm/kvm_stat -@@ -1413,8 +1413,8 @@ performance. - - Requirements: - - Access to: -- /sys/kernel/debug/kvm -- /sys/kernel/debug/trace/events/* -+ %s -+ %s/events/* - /proc/pid/task - - /proc/sys/kernel/perf_event_paranoid < 1 if user has no - CAP_SYS_ADMIN and perf events are used. -@@ -1434,7 +1434,7 @@ Interactive Commands: - s set update interval - x toggle reporting of stats for individual child trace events - Press any other key to refresh statistics immediately. --""" -+""" % (PATH_DEBUGFS_KVM, PATH_DEBUGFS_TRACING) - - class PlainHelpFormatter(optparse.IndentedHelpFormatter): - def format_description(self, description): --- -1.8.3.1 - diff --git a/SOURCES/kvm-ui-Always-remove-an-old-VNC-channel-watch-before-add.patch b/SOURCES/kvm-ui-Always-remove-an-old-VNC-channel-watch-before-add.patch deleted file mode 100644 index 546e92c..0000000 --- a/SOURCES/kvm-ui-Always-remove-an-old-VNC-channel-watch-before-add.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 2c959596e23736aadad5010a8db665b99359b517 Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Wed, 20 Dec 2017 17:56:46 +0100 -Subject: [PATCH 06/42] ui: Always remove an old VNC channel watch before - adding a new one - -RH-Author: Daniel P. Berrange -Message-id: <20171220175702.29663-5-berrange@redhat.com> -Patchwork-id: 78457 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 04/20] ui: Always remove an old VNC channel watch before adding a new one -Bugzilla: 1518649 -RH-Acked-by: John Snow -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Miroslav Rezanina - -From: Brandon Carpenter - -Also set saved handle to zero when removing without adding a new watch. - -Signed-off-by: Brandon Carpenter -Reviewed-by: Paolo Bonzini -Reviewed-by: Daniel P. Berrange -(cherry picked from commit a75d6f07613af7ec5b016b31b117436e32ce7a5f) -Signed-off-by: Miroslav Rezanina ---- - ui/vnc-auth-vencrypt.c | 3 +++ - ui/vnc-ws.c | 6 ++++++ - ui/vnc.c | 4 ++++ - 3 files changed, 13 insertions(+) - -diff --git a/ui/vnc-auth-vencrypt.c b/ui/vnc-auth-vencrypt.c -index ffaab57..c3eece4 100644 ---- a/ui/vnc-auth-vencrypt.c -+++ b/ui/vnc-auth-vencrypt.c -@@ -77,6 +77,9 @@ static void vnc_tls_handshake_done(QIOTask *task, - vnc_client_error(vs); - error_free(err); - } else { -+ if (vs->ioc_tag) { -+ g_source_remove(vs->ioc_tag); -+ } - vs->ioc_tag = qio_channel_add_watch( - vs->ioc, G_IO_IN | G_IO_OUT, vnc_client_io, vs, NULL); - start_auth_vencrypt_subauth(vs); -diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c -index f530cd5..eaf3095 100644 ---- a/ui/vnc-ws.c -+++ b/ui/vnc-ws.c -@@ -36,6 +36,9 @@ static void vncws_tls_handshake_done(QIOTask *task, - error_free(err); - } else { - VNC_DEBUG("TLS handshake complete, starting websocket handshake\n"); -+ if (vs->ioc_tag) { -+ g_source_remove(vs->ioc_tag); -+ } - vs->ioc_tag = qio_channel_add_watch( - QIO_CHANNEL(vs->ioc), G_IO_IN, vncws_handshake_io, vs, NULL); - } -@@ -97,6 +100,9 @@ static void vncws_handshake_done(QIOTask *task, - } else { - VNC_DEBUG("Websock handshake complete, starting VNC protocol\n"); - vnc_start_protocol(vs); -+ if (vs->ioc_tag) { -+ g_source_remove(vs->ioc_tag); -+ } - vs->ioc_tag = qio_channel_add_watch( - vs->ioc, G_IO_IN, vnc_client_io, vs, NULL); - } -diff --git a/ui/vnc.c b/ui/vnc.c -index 5b1e264..4e1d94f 100644 ---- a/ui/vnc.c -+++ b/ui/vnc.c -@@ -1121,6 +1121,7 @@ static void vnc_disconnect_start(VncState *vs) - vnc_set_share_mode(vs, VNC_SHARE_MODE_DISCONNECTED); - if (vs->ioc_tag) { - g_source_remove(vs->ioc_tag); -+ vs->ioc_tag = 0; - } - qio_channel_close(vs->ioc, NULL); - vs->disconnecting = TRUE; -@@ -2931,6 +2932,9 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc, - VNC_DEBUG("New client on socket %p\n", vs->sioc); - update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE); - qio_channel_set_blocking(vs->ioc, false, NULL); -+ if (vs->ioc_tag) { -+ g_source_remove(vs->ioc_tag); -+ } - if (websocket) { - vs->websocket = 1; - if (vd->tlscreds) { --- -1.8.3.1 - diff --git a/SOURCES/kvm-ui-add-trace-events-related-to-VNC-client-throttling.patch b/SOURCES/kvm-ui-add-trace-events-related-to-VNC-client-throttling.patch deleted file mode 100644 index 5d62e30..0000000 --- a/SOURCES/kvm-ui-add-trace-events-related-to-VNC-client-throttling.patch +++ /dev/null @@ -1,136 +0,0 @@ -From b4bcc805bc53775069ac656e1ac75c49d5eb6b6a Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Mon, 5 Feb 2018 11:10:09 +0100 -Subject: [PATCH 15/20] ui: add trace events related to VNC client throttling -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Daniel P. Berrange -Message-id: <20180205111012.6210-15-berrange@redhat.com> -Patchwork-id: 78886 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 14/17] ui: add trace events related to VNC client throttling -Bugzilla: 1527404 -RH-Acked-by: Gerd Hoffmann -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Thomas Huth - -From: "Daniel P. Berrange" - -The VNC client throttling is quite subtle so will benefit from having trace -points available for live debugging. - -Signed-off-by: Daniel P. Berrange -Reviewed-by: Darren Kenny -Reviewed-by: Marc-André Lureau -Message-id: 20171218191228.31018-13-berrange@redhat.com -Signed-off-by: Gerd Hoffmann -(cherry picked from commit 6aa22a29187e1908f5db738d27c64a9efc8d0bfa) -Signed-off-by: Miroslav Rezanina ---- - ui/trace-events | 7 +++++++ - ui/vnc.c | 23 +++++++++++++++++++++++ - 2 files changed, 30 insertions(+) - -diff --git a/ui/trace-events b/ui/trace-events -index 1a9f126..85f74f9 100644 ---- a/ui/trace-events -+++ b/ui/trace-events -@@ -35,6 +35,13 @@ vnc_client_connect(void *state, void *ioc) "VNC client connect state=%p ioc=%p" - vnc_client_disconnect_start(void *state, void *ioc) "VNC client disconnect start state=%p ioc=%p" - vnc_client_disconnect_finish(void *state, void *ioc) "VNC client disconnect finish state=%p ioc=%p" - vnc_client_io_wrap(void *state, void *ioc, const char *type) "VNC client I/O wrap state=%p ioc=%p type=%s" -+vnc_client_throttle_threshold(void *state, void *ioc, size_t oldoffset, size_t offset, int client_width, int client_height, int bytes_per_pixel, void *audio_cap) "VNC client throttle threshold state=%p ioc=%p oldoffset=%zu newoffset=%zu width=%d height=%d bpp=%d audio=%p" -+vnc_client_throttle_incremental(void *state, void *ioc, int job_update, size_t offset) "VNC client throttle incremental state=%p ioc=%p job-update=%d offset=%zu" -+vnc_client_throttle_forced(void *state, void *ioc, int job_update, size_t offset) "VNC client throttle forced state=%p ioc=%p job-update=%d offset=%zu" -+vnc_client_throttle_audio(void *state, void *ioc, size_t offset) "VNC client throttle audio state=%p ioc=%p offset=%zu" -+vnc_client_unthrottle_forced(void *state, void *ioc) "VNC client unthrottle forced offset state=%p ioc=%p" -+vnc_client_unthrottle_incremental(void *state, void *ioc, size_t offset) "VNC client unthrottle incremental state=%p ioc=%p offset=%zu" -+vnc_client_output_limit(void *state, void *ioc, size_t offset, size_t threshold) "VNC client output limit state=%p ioc=%p offset=%zu threshold=%zu" - vnc_auth_init(void *display, int websock, int auth, int subauth) "VNC auth init state=%p websock=%d auth=%d subauth=%d" - vnc_auth_start(void *state, int method) "VNC client auth start state=%p method=%d" - vnc_auth_pass(void *state, int method) "VNC client auth passed state=%p method=%d" -diff --git a/ui/vnc.c b/ui/vnc.c -index a7aff91..26f58bc 100644 ---- a/ui/vnc.c -+++ b/ui/vnc.c -@@ -1011,6 +1011,12 @@ static void vnc_update_throttle_offset(VncState *vs) - */ - offset = MAX(offset, 1024 * 1024); - -+ if (vs->throttle_output_offset != offset) { -+ trace_vnc_client_throttle_threshold( -+ vs, vs->ioc, vs->throttle_output_offset, offset, vs->client_width, -+ vs->client_height, vs->client_pf.bytes_per_pixel, vs->audio_cap); -+ } -+ - vs->throttle_output_offset = offset; - } - -@@ -1028,6 +1034,8 @@ static bool vnc_should_update(VncState *vs) - vs->job_update == VNC_STATE_UPDATE_NONE) { - return true; - } -+ trace_vnc_client_throttle_incremental( -+ vs, vs->ioc, vs->job_update, vs->output.offset); - break; - case VNC_STATE_UPDATE_FORCE: - /* Only allow forced updates if the pending send queue -@@ -1042,6 +1050,8 @@ static bool vnc_should_update(VncState *vs) - vs->job_update == VNC_STATE_UPDATE_NONE) { - return true; - } -+ trace_vnc_client_throttle_forced( -+ vs, vs->ioc, vs->job_update, vs->force_update_offset); - break; - } - return false; -@@ -1158,6 +1168,8 @@ static void audio_capture(void *opaque, void *buf, int size) - vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_DATA); - vnc_write_u32(vs, size); - vnc_write(vs, buf, size); -+ } else { -+ trace_vnc_client_throttle_audio(vs, vs->ioc, vs->output.offset); - } - vnc_unlock_output(vs); - vnc_flush(vs); -@@ -1328,6 +1340,7 @@ ssize_t vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen) - */ - static ssize_t vnc_client_write_plain(VncState *vs) - { -+ size_t offset; - ssize_t ret; - - #ifdef CONFIG_VNC_SASL -@@ -1348,11 +1361,19 @@ static ssize_t vnc_client_write_plain(VncState *vs) - return 0; - - if (ret >= vs->force_update_offset) { -+ if (vs->force_update_offset != 0) { -+ trace_vnc_client_unthrottle_forced(vs, vs->ioc); -+ } - vs->force_update_offset = 0; - } else { - vs->force_update_offset -= ret; - } -+ offset = vs->output.offset; - buffer_advance(&vs->output, ret); -+ if (offset >= vs->throttle_output_offset && -+ vs->output.offset < vs->throttle_output_offset) { -+ trace_vnc_client_unthrottle_incremental(vs, vs->ioc, vs->output.offset); -+ } - - if (vs->output.offset == 0) { - if (vs->ioc_tag) { -@@ -1549,6 +1570,8 @@ void vnc_write(VncState *vs, const void *data, size_t len) - if (vs->throttle_output_offset != 0 && - vs->output.offset > (vs->throttle_output_offset * - VNC_THROTTLE_OUTPUT_LIMIT_SCALE)) { -+ trace_vnc_client_output_limit(vs, vs->ioc, vs->output.offset, -+ vs->throttle_output_offset); - vnc_disconnect_start(vs); - return; - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-ui-add-tracing-of-VNC-authentication-process.patch b/SOURCES/kvm-ui-add-tracing-of-VNC-authentication-process.patch deleted file mode 100644 index c762b26..0000000 --- a/SOURCES/kvm-ui-add-tracing-of-VNC-authentication-process.patch +++ /dev/null @@ -1,665 +0,0 @@ -From d22fb15220016b86cca81f73f27c748f5a5c1183 Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Mon, 5 Feb 2018 11:09:57 +0100 -Subject: [PATCH 03/20] ui: add tracing of VNC authentication process - -RH-Author: Daniel P. Berrange -Message-id: <20180205111012.6210-3-berrange@redhat.com> -Patchwork-id: 78881 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 02/17] ui: add tracing of VNC authentication process -Bugzilla: 1527404 -RH-Acked-by: Gerd Hoffmann -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Thomas Huth - -From: "Daniel P. Berrange" - -Trace anything related to authentication in the VNC protocol -handshake - -Signed-off-by: Daniel P. Berrange -Message-id: 20170921121528.23935-3-berrange@redhat.com -Signed-off-by: Gerd Hoffmann -(cherry picked from commit 7364dbdabb7824d5bde1e341bb6d928282f01c83) -Signed-off-by: Miroslav Rezanina ---- - ui/trace-events | 15 +++++++ - ui/vnc-auth-sasl.c | 113 ++++++++++++++++++++++--------------------------- - ui/vnc-auth-vencrypt.c | 21 ++++----- - ui/vnc.c | 36 ++++++++-------- - 4 files changed, 92 insertions(+), 93 deletions(-) - -diff --git a/ui/trace-events b/ui/trace-events -index e4c02e4..1a9f126 100644 ---- a/ui/trace-events -+++ b/ui/trace-events -@@ -35,6 +35,21 @@ vnc_client_connect(void *state, void *ioc) "VNC client connect state=%p ioc=%p" - vnc_client_disconnect_start(void *state, void *ioc) "VNC client disconnect start state=%p ioc=%p" - vnc_client_disconnect_finish(void *state, void *ioc) "VNC client disconnect finish state=%p ioc=%p" - vnc_client_io_wrap(void *state, void *ioc, const char *type) "VNC client I/O wrap state=%p ioc=%p type=%s" -+vnc_auth_init(void *display, int websock, int auth, int subauth) "VNC auth init state=%p websock=%d auth=%d subauth=%d" -+vnc_auth_start(void *state, int method) "VNC client auth start state=%p method=%d" -+vnc_auth_pass(void *state, int method) "VNC client auth passed state=%p method=%d" -+vnc_auth_fail(void *state, int method, const char *message, const char *reason) "VNC client auth failed state=%p method=%d message=%s reason=%s" -+vnc_auth_reject(void *state, int expect, int got) "VNC client auth rejected state=%p method expected=%d got=%d" -+vnc_auth_vencrypt_version(void *state, int major, int minor) "VNC client auth vencrypt version state=%p major=%d minor=%d" -+vnc_auth_vencrypt_subauth(void *state, int auth) "VNC client auth vencrypt subauth state=%p auth=%d" -+vnc_auth_sasl_mech_list(void *state, const char *mechs) "VNC client auth SASL state=%p mechlist=%s" -+vnc_auth_sasl_mech_choose(void *state, const char *mech) "VNC client auth SASL state=%p mech=%s" -+vnc_auth_sasl_start(void *state, const void *clientdata, size_t clientlen, const void *serverdata, size_t severlen, int ret) "VNC client auth SASL start state=%p clientdata=%p clientlen=%zu serverdata=%p serverlen=%zu ret=%d" -+vnc_auth_sasl_step(void *state, const void *clientdata, size_t clientlen, const void *serverdata, size_t severlen, int ret) "VNC client auth SASL step state=%p clientdata=%p clientlen=%zu serverdata=%p serverlen=%zu ret=%d" -+vnc_auth_sasl_ssf(void *state, int ssf) "VNC client auth SASL SSF state=%p size=%d" -+vnc_auth_sasl_username(void *state, const char *name) "VNC client auth SASL user state=%p name=%s" -+vnc_auth_sasl_acl(void *state, int allow) "VNC client auth SASL ACL state=%p allow=%d" -+ - - # ui/input.c - input_event_key_number(int conidx, int number, const char *qcode, bool down) "con %d, key number 0x%x [%s], down %d" -diff --git a/ui/vnc-auth-sasl.c b/ui/vnc-auth-sasl.c -index 3ade4a4..23f2828 100644 ---- a/ui/vnc-auth-sasl.c -+++ b/ui/vnc-auth-sasl.c -@@ -25,6 +25,7 @@ - #include "qemu/osdep.h" - #include "qapi/error.h" - #include "vnc.h" -+#include "trace.h" - - /* Max amount of data we send/recv for SASL steps to prevent DOS */ - #define SASL_DATA_MAX_LEN (1024 * 1024) -@@ -133,27 +134,26 @@ static int vnc_auth_sasl_check_access(VncState *vs) - - err = sasl_getprop(vs->sasl.conn, SASL_USERNAME, &val); - if (err != SASL_OK) { -- VNC_DEBUG("cannot query SASL username on connection %d (%s), denying access\n", -- err, sasl_errstring(err, NULL, NULL)); -+ trace_vnc_auth_fail(vs, vs->auth, "Cannot fetch SASL username", -+ sasl_errstring(err, NULL, NULL)); - return -1; - } - if (val == NULL) { -- VNC_DEBUG("no client username was found, denying access\n"); -+ trace_vnc_auth_fail(vs, vs->auth, "No SASL username set", ""); - return -1; - } -- VNC_DEBUG("SASL client username %s\n", (const char *)val); - - vs->sasl.username = g_strdup((const char*)val); -+ trace_vnc_auth_sasl_username(vs, vs->sasl.username); - - if (vs->vd->sasl.acl == NULL) { -- VNC_DEBUG("no ACL activated, allowing access\n"); -+ trace_vnc_auth_sasl_acl(vs, 1); - return 0; - } - - allow = qemu_acl_party_is_allowed(vs->vd->sasl.acl, vs->sasl.username); - -- VNC_DEBUG("SASL client %s %s by ACL\n", vs->sasl.username, -- allow ? "allowed" : "denied"); -+ trace_vnc_auth_sasl_acl(vs, allow); - return allow ? 0 : -1; - } - -@@ -170,7 +170,9 @@ static int vnc_auth_sasl_check_ssf(VncState *vs) - return 0; - - ssf = *(const int *)val; -- VNC_DEBUG("negotiated an SSF of %d\n", ssf); -+ -+ trace_vnc_auth_sasl_ssf(vs, ssf); -+ - if (ssf < 56) - return 0; /* 56 is good for Kerberos */ - -@@ -218,33 +220,28 @@ static int protocol_client_auth_sasl_step(VncState *vs, uint8_t *data, size_t le - datalen--; /* Don't count NULL byte when passing to _start() */ - } - -- VNC_DEBUG("Step using SASL Data %p (%d bytes)\n", -- clientdata, datalen); - err = sasl_server_step(vs->sasl.conn, - clientdata, - datalen, - &serverout, - &serveroutlen); -+ trace_vnc_auth_sasl_step(vs, data, len, serverout, serveroutlen, err); - if (err != SASL_OK && - err != SASL_CONTINUE) { -- VNC_DEBUG("sasl step failed %d (%s)\n", -- err, sasl_errdetail(vs->sasl.conn)); -+ trace_vnc_auth_fail(vs, vs->auth, "Cannot step SASL auth", -+ sasl_errdetail(vs->sasl.conn)); - sasl_dispose(&vs->sasl.conn); - vs->sasl.conn = NULL; - goto authabort; - } - - if (serveroutlen > SASL_DATA_MAX_LEN) { -- VNC_DEBUG("sasl step reply data too long %d\n", -- serveroutlen); -+ trace_vnc_auth_fail(vs, vs->auth, "SASL data too long", ""); - sasl_dispose(&vs->sasl.conn); - vs->sasl.conn = NULL; - goto authabort; - } - -- VNC_DEBUG("SASL return data %d bytes, nil; %d\n", -- serveroutlen, serverout ? 0 : 1); -- - if (serveroutlen) { - vnc_write_u32(vs, serveroutlen + 1); - vnc_write(vs, serverout, serveroutlen + 1); -@@ -256,22 +253,20 @@ static int protocol_client_auth_sasl_step(VncState *vs, uint8_t *data, size_t le - vnc_write_u8(vs, err == SASL_CONTINUE ? 0 : 1); - - if (err == SASL_CONTINUE) { -- VNC_DEBUG("%s", "Authentication must continue\n"); - /* Wait for step length */ - vnc_read_when(vs, protocol_client_auth_sasl_step_len, 4); - } else { - if (!vnc_auth_sasl_check_ssf(vs)) { -- VNC_DEBUG("Authentication rejected for weak SSF %p\n", vs->ioc); -+ trace_vnc_auth_fail(vs, vs->auth, "SASL SSF too weak", ""); - goto authreject; - } - - /* Check username whitelist ACL */ - if (vnc_auth_sasl_check_access(vs) < 0) { -- VNC_DEBUG("Authentication rejected for ACL %p\n", vs->ioc); - goto authreject; - } - -- VNC_DEBUG("Authentication successful %p\n", vs->ioc); -+ trace_vnc_auth_pass(vs, vs->auth); - vnc_write_u32(vs, 0); /* Accept auth */ - /* - * Delay writing in SSF encoded mode until pending output -@@ -300,9 +295,9 @@ static int protocol_client_auth_sasl_step(VncState *vs, uint8_t *data, size_t le - static int protocol_client_auth_sasl_step_len(VncState *vs, uint8_t *data, size_t len) - { - uint32_t steplen = read_u32(data, 0); -- VNC_DEBUG("Got client step len %d\n", steplen); -+ - if (steplen > SASL_DATA_MAX_LEN) { -- VNC_DEBUG("Too much SASL data %d\n", steplen); -+ trace_vnc_auth_fail(vs, vs->auth, "SASL step len too large", ""); - vnc_client_error(vs); - return -1; - } -@@ -346,33 +341,28 @@ static int protocol_client_auth_sasl_start(VncState *vs, uint8_t *data, size_t l - datalen--; /* Don't count NULL byte when passing to _start() */ - } - -- VNC_DEBUG("Start SASL auth with mechanism %s. Data %p (%d bytes)\n", -- vs->sasl.mechlist, clientdata, datalen); - err = sasl_server_start(vs->sasl.conn, - vs->sasl.mechlist, - clientdata, - datalen, - &serverout, - &serveroutlen); -+ trace_vnc_auth_sasl_start(vs, data, len, serverout, serveroutlen, err); - if (err != SASL_OK && - err != SASL_CONTINUE) { -- VNC_DEBUG("sasl start failed %d (%s)\n", -- err, sasl_errdetail(vs->sasl.conn)); -+ trace_vnc_auth_fail(vs, vs->auth, "Cannot start SASL auth", -+ sasl_errdetail(vs->sasl.conn)); - sasl_dispose(&vs->sasl.conn); - vs->sasl.conn = NULL; - goto authabort; - } - if (serveroutlen > SASL_DATA_MAX_LEN) { -- VNC_DEBUG("sasl start reply data too long %d\n", -- serveroutlen); -+ trace_vnc_auth_fail(vs, vs->auth, "SASL data too long", ""); - sasl_dispose(&vs->sasl.conn); - vs->sasl.conn = NULL; - goto authabort; - } - -- VNC_DEBUG("SASL return data %d bytes, nil; %d\n", -- serveroutlen, serverout ? 0 : 1); -- - if (serveroutlen) { - vnc_write_u32(vs, serveroutlen + 1); - vnc_write(vs, serverout, serveroutlen + 1); -@@ -384,22 +374,20 @@ static int protocol_client_auth_sasl_start(VncState *vs, uint8_t *data, size_t l - vnc_write_u8(vs, err == SASL_CONTINUE ? 0 : 1); - - if (err == SASL_CONTINUE) { -- VNC_DEBUG("%s", "Authentication must continue\n"); - /* Wait for step length */ - vnc_read_when(vs, protocol_client_auth_sasl_step_len, 4); - } else { - if (!vnc_auth_sasl_check_ssf(vs)) { -- VNC_DEBUG("Authentication rejected for weak SSF %p\n", vs->ioc); -+ trace_vnc_auth_fail(vs, vs->auth, "SASL SSF too weak", ""); - goto authreject; - } - - /* Check username whitelist ACL */ - if (vnc_auth_sasl_check_access(vs) < 0) { -- VNC_DEBUG("Authentication rejected for ACL %p\n", vs->ioc); - goto authreject; - } - -- VNC_DEBUG("Authentication successful %p\n", vs->ioc); -+ trace_vnc_auth_pass(vs, vs->auth); - vnc_write_u32(vs, 0); /* Accept auth */ - start_client_init(vs); - } -@@ -422,9 +410,9 @@ static int protocol_client_auth_sasl_start(VncState *vs, uint8_t *data, size_t l - static int protocol_client_auth_sasl_start_len(VncState *vs, uint8_t *data, size_t len) - { - uint32_t startlen = read_u32(data, 0); -- VNC_DEBUG("Got client start len %d\n", startlen); -+ - if (startlen > SASL_DATA_MAX_LEN) { -- VNC_DEBUG("Too much SASL data %d\n", startlen); -+ trace_vnc_auth_fail(vs, vs->auth, "SASL start len too large", ""); - vnc_client_error(vs); - return -1; - } -@@ -439,22 +427,18 @@ static int protocol_client_auth_sasl_start_len(VncState *vs, uint8_t *data, size - static int protocol_client_auth_sasl_mechname(VncState *vs, uint8_t *data, size_t len) - { - char *mechname = g_strndup((const char *) data, len); -- VNC_DEBUG("Got client mechname '%s' check against '%s'\n", -- mechname, vs->sasl.mechlist); -+ trace_vnc_auth_sasl_mech_choose(vs, mechname); - - if (strncmp(vs->sasl.mechlist, mechname, len) == 0) { - if (vs->sasl.mechlist[len] != '\0' && - vs->sasl.mechlist[len] != ',') { -- VNC_DEBUG("One %d", vs->sasl.mechlist[len]); - goto fail; - } - } else { - char *offset = strstr(vs->sasl.mechlist, mechname); -- VNC_DEBUG("Two %p\n", offset); - if (!offset) { - goto fail; - } -- VNC_DEBUG("Two '%s'\n", offset); - if (offset[-1] != ',' || - (offset[len] != '\0'&& - offset[len] != ',')) { -@@ -465,11 +449,11 @@ static int protocol_client_auth_sasl_mechname(VncState *vs, uint8_t *data, size_ - g_free(vs->sasl.mechlist); - vs->sasl.mechlist = mechname; - -- VNC_DEBUG("Validated mechname '%s'\n", mechname); - vnc_read_when(vs, protocol_client_auth_sasl_start_len, 4); - return 0; - - fail: -+ trace_vnc_auth_fail(vs, vs->auth, "Unsupported mechname", mechname); - vnc_client_error(vs); - g_free(mechname); - return -1; -@@ -478,14 +462,14 @@ static int protocol_client_auth_sasl_mechname(VncState *vs, uint8_t *data, size_ - static int protocol_client_auth_sasl_mechname_len(VncState *vs, uint8_t *data, size_t len) - { - uint32_t mechlen = read_u32(data, 0); -- VNC_DEBUG("Got client mechname len %d\n", mechlen); -+ - if (mechlen > 100) { -- VNC_DEBUG("Too long SASL mechname data %d\n", mechlen); -+ trace_vnc_auth_fail(vs, vs->auth, "SASL mechname too long", ""); - vnc_client_error(vs); - return -1; - } - if (mechlen < 1) { -- VNC_DEBUG("Too short SASL mechname %d\n", mechlen); -+ trace_vnc_auth_fail(vs, vs->auth, "SASL mechname too short", ""); - vnc_client_error(vs); - return -1; - } -@@ -524,19 +508,22 @@ void start_auth_sasl(VncState *vs) - const char *mechlist = NULL; - sasl_security_properties_t secprops; - int err; -+ Error *local_err = NULL; - char *localAddr, *remoteAddr; - int mechlistlen; - -- VNC_DEBUG("Initialize SASL auth %p\n", vs->ioc); -- - /* Get local & remote client addresses in form IPADDR;PORT */ -- localAddr = vnc_socket_ip_addr_string(vs->sioc, true, NULL); -+ localAddr = vnc_socket_ip_addr_string(vs->sioc, true, &local_err); - if (!localAddr) { -+ trace_vnc_auth_fail(vs, vs->auth, "Cannot format local IP", -+ error_get_pretty(local_err)); - goto authabort; - } - -- remoteAddr = vnc_socket_ip_addr_string(vs->sioc, false, NULL); -+ remoteAddr = vnc_socket_ip_addr_string(vs->sioc, false, &local_err); - if (!remoteAddr) { -+ trace_vnc_auth_fail(vs, vs->auth, "Cannot format remote IP", -+ error_get_pretty(local_err)); - g_free(localAddr); - goto authabort; - } -@@ -554,8 +541,8 @@ void start_auth_sasl(VncState *vs) - localAddr = remoteAddr = NULL; - - if (err != SASL_OK) { -- VNC_DEBUG("sasl context setup failed %d (%s)", -- err, sasl_errstring(err, NULL, NULL)); -+ trace_vnc_auth_fail(vs, vs->auth, "SASL context setup failed", -+ sasl_errstring(err, NULL, NULL)); - vs->sasl.conn = NULL; - goto authabort; - } -@@ -570,8 +557,8 @@ void start_auth_sasl(VncState *vs) - keysize = qcrypto_tls_session_get_key_size(vs->tls, - &local_err); - if (keysize < 0) { -- VNC_DEBUG("cannot TLS get cipher size: %s\n", -- error_get_pretty(local_err)); -+ trace_vnc_auth_fail(vs, vs->auth, "cannot TLS get cipher size", -+ error_get_pretty(local_err)); - error_free(local_err); - sasl_dispose(&vs->sasl.conn); - vs->sasl.conn = NULL; -@@ -581,8 +568,8 @@ void start_auth_sasl(VncState *vs) - - err = sasl_setprop(vs->sasl.conn, SASL_SSF_EXTERNAL, &ssf); - if (err != SASL_OK) { -- VNC_DEBUG("cannot set SASL external SSF %d (%s)\n", -- err, sasl_errstring(err, NULL, NULL)); -+ trace_vnc_auth_fail(vs, vs->auth, "cannot set SASL external SSF", -+ sasl_errstring(err, NULL, NULL)); - sasl_dispose(&vs->sasl.conn); - vs->sasl.conn = NULL; - goto authabort; -@@ -617,8 +604,8 @@ void start_auth_sasl(VncState *vs) - - err = sasl_setprop(vs->sasl.conn, SASL_SEC_PROPS, &secprops); - if (err != SASL_OK) { -- VNC_DEBUG("cannot set SASL security props %d (%s)\n", -- err, sasl_errstring(err, NULL, NULL)); -+ trace_vnc_auth_fail(vs, vs->auth, "cannot set SASL security props", -+ sasl_errstring(err, NULL, NULL)); - sasl_dispose(&vs->sasl.conn); - vs->sasl.conn = NULL; - goto authabort; -@@ -633,13 +620,13 @@ void start_auth_sasl(VncState *vs) - NULL, - NULL); - if (err != SASL_OK) { -- VNC_DEBUG("cannot list SASL mechanisms %d (%s)\n", -- err, sasl_errdetail(vs->sasl.conn)); -+ trace_vnc_auth_fail(vs, vs->auth, "cannot list SASL mechanisms", -+ sasl_errdetail(vs->sasl.conn)); - sasl_dispose(&vs->sasl.conn); - vs->sasl.conn = NULL; - goto authabort; - } -- VNC_DEBUG("Available mechanisms for client: '%s'\n", mechlist); -+ trace_vnc_auth_sasl_mech_list(vs, mechlist); - - vs->sasl.mechlist = g_strdup(mechlist); - mechlistlen = strlen(mechlist); -@@ -647,12 +634,12 @@ void start_auth_sasl(VncState *vs) - vnc_write(vs, mechlist, mechlistlen); - vnc_flush(vs); - -- VNC_DEBUG("Wait for client mechname length\n"); - vnc_read_when(vs, protocol_client_auth_sasl_mechname_len, 4); - - return; - - authabort: -+ error_free(local_err); - vnc_client_error(vs); - } - -diff --git a/ui/vnc-auth-vencrypt.c b/ui/vnc-auth-vencrypt.c -index 2a3766a..7833631 100644 ---- a/ui/vnc-auth-vencrypt.c -+++ b/ui/vnc-auth-vencrypt.c -@@ -35,27 +35,24 @@ static void start_auth_vencrypt_subauth(VncState *vs) - switch (vs->subauth) { - case VNC_AUTH_VENCRYPT_TLSNONE: - case VNC_AUTH_VENCRYPT_X509NONE: -- VNC_DEBUG("Accept TLS auth none\n"); - vnc_write_u32(vs, 0); /* Accept auth completion */ - start_client_init(vs); - break; - - case VNC_AUTH_VENCRYPT_TLSVNC: - case VNC_AUTH_VENCRYPT_X509VNC: -- VNC_DEBUG("Start TLS auth VNC\n"); - start_auth_vnc(vs); - break; - - #ifdef CONFIG_VNC_SASL - case VNC_AUTH_VENCRYPT_TLSSASL: - case VNC_AUTH_VENCRYPT_X509SASL: -- VNC_DEBUG("Start TLS auth SASL\n"); - start_auth_sasl(vs); - break; - #endif /* CONFIG_VNC_SASL */ - - default: /* Should not be possible, but just in case */ -- VNC_DEBUG("Reject subauth %d server bug\n", vs->auth); -+ trace_vnc_auth_fail(vs, vs->auth, "Unhandled VeNCrypt subauth", ""); - vnc_write_u8(vs, 1); - if (vs->minor >= 8) { - static const char err[] = "Unsupported authentication type"; -@@ -73,8 +70,8 @@ static void vnc_tls_handshake_done(QIOTask *task, - Error *err = NULL; - - if (qio_task_propagate_error(task, &err)) { -- VNC_DEBUG("Handshake failed %s\n", -- error_get_pretty(err)); -+ trace_vnc_auth_fail(vs, vs->auth, "TLS handshake failed", -+ error_get_pretty(err)); - vnc_client_error(vs); - error_free(err); - } else { -@@ -92,15 +89,15 @@ static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len - { - int auth = read_u32(data, 0); - -+ trace_vnc_auth_vencrypt_subauth(vs, auth); - if (auth != vs->subauth) { -- VNC_DEBUG("Rejecting auth %d\n", auth); -+ trace_vnc_auth_fail(vs, vs->auth, "Unsupported sub-auth version", ""); - vnc_write_u8(vs, 0); /* Reject auth */ - vnc_flush(vs); - vnc_client_error(vs); - } else { - Error *err = NULL; - QIOChannelTLS *tls; -- VNC_DEBUG("Accepting auth %d, setting up TLS for handshake\n", auth); - vnc_write_u8(vs, 1); /* Accept auth */ - vnc_flush(vs); - -@@ -115,14 +112,14 @@ static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len - vs->vd->tlsaclname, - &err); - if (!tls) { -- VNC_DEBUG("Failed to setup TLS %s\n", error_get_pretty(err)); -+ trace_vnc_auth_fail(vs, vs->auth, "TLS setup failed", -+ error_get_pretty(err)); - error_free(err); - vnc_client_error(vs); - return 0; - } - - qio_channel_set_name(QIO_CHANNEL(tls), "vnc-server-tls"); -- VNC_DEBUG("Start TLS VeNCrypt handshake process\n"); - object_unref(OBJECT(vs->ioc)); - vs->ioc = QIO_CHANNEL(tls); - trace_vnc_client_io_wrap(vs, vs->ioc, "tls"); -@@ -138,14 +135,14 @@ static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len - - static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len) - { -+ trace_vnc_auth_vencrypt_version(vs, (int)data[0], (int)data[1]); - if (data[0] != 0 || - data[1] != 2) { -- VNC_DEBUG("Unsupported VeNCrypt protocol %d.%d\n", (int)data[0], (int)data[1]); -+ trace_vnc_auth_fail(vs, vs->auth, "Unsupported version", ""); - vnc_write_u8(vs, 1); /* Reject version */ - vnc_flush(vs); - vnc_client_error(vs); - } else { -- VNC_DEBUG("Sending allowed auth %d\n", vs->subauth); - vnc_write_u8(vs, 0); /* Accept version */ - vnc_write_u8(vs, 1); /* Number of sub-auths */ - vnc_write_u32(vs, vs->subauth); /* The supported auth */ -diff --git a/ui/vnc.c b/ui/vnc.c -index 66783ec..1275bba 100644 ---- a/ui/vnc.c -+++ b/ui/vnc.c -@@ -2407,11 +2407,11 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len) - Error *err = NULL; - - if (!vs->vd->password) { -- VNC_DEBUG("No password configured on server"); -+ trace_vnc_auth_fail(vs, vs->auth, "password is not set", ""); - goto reject; - } - if (vs->vd->expires < now) { -- VNC_DEBUG("Password is expired"); -+ trace_vnc_auth_fail(vs, vs->auth, "password is expired", ""); - goto reject; - } - -@@ -2428,8 +2428,8 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len) - key, G_N_ELEMENTS(key), - &err); - if (!cipher) { -- VNC_DEBUG("Cannot initialize cipher %s", -- error_get_pretty(err)); -+ trace_vnc_auth_fail(vs, vs->auth, "cannot create cipher", -+ error_get_pretty(err)); - error_free(err); - goto reject; - } -@@ -2439,18 +2439,18 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len) - response, - VNC_AUTH_CHALLENGE_SIZE, - &err) < 0) { -- VNC_DEBUG("Cannot encrypt challenge %s", -- error_get_pretty(err)); -+ trace_vnc_auth_fail(vs, vs->auth, "cannot encrypt challenge response", -+ error_get_pretty(err)); - error_free(err); - goto reject; - } - - /* Compare expected vs actual challenge response */ - if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) { -- VNC_DEBUG("Client challenge response did not match\n"); -+ trace_vnc_auth_fail(vs, vs->auth, "mis-matched challenge response", ""); - goto reject; - } else { -- VNC_DEBUG("Accepting VNC challenge response\n"); -+ trace_vnc_auth_pass(vs, vs->auth); - vnc_write_u32(vs, 0); /* Accept auth */ - vnc_flush(vs); - -@@ -2489,7 +2489,7 @@ static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len) - /* We only advertise 1 auth scheme at a time, so client - * must pick the one we sent. Verify this */ - if (data[0] != vs->auth) { /* Reject auth */ -- VNC_DEBUG("Reject auth %d because it didn't match advertized\n", (int)data[0]); -+ trace_vnc_auth_reject(vs, vs->auth, (int)data[0]); - vnc_write_u32(vs, 1); - if (vs->minor >= 8) { - static const char err[] = "Authentication failed"; -@@ -2498,36 +2498,33 @@ static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len) - } - vnc_client_error(vs); - } else { /* Accept requested auth */ -- VNC_DEBUG("Client requested auth %d\n", (int)data[0]); -+ trace_vnc_auth_start(vs, vs->auth); - switch (vs->auth) { - case VNC_AUTH_NONE: -- VNC_DEBUG("Accept auth none\n"); - if (vs->minor >= 8) { - vnc_write_u32(vs, 0); /* Accept auth completion */ - vnc_flush(vs); - } -+ trace_vnc_auth_pass(vs, vs->auth); - start_client_init(vs); - break; - - case VNC_AUTH_VNC: -- VNC_DEBUG("Start VNC auth\n"); - start_auth_vnc(vs); - break; - - case VNC_AUTH_VENCRYPT: -- VNC_DEBUG("Accept VeNCrypt auth\n"); - start_auth_vencrypt(vs); - break; - - #ifdef CONFIG_VNC_SASL - case VNC_AUTH_SASL: -- VNC_DEBUG("Accept SASL auth\n"); - start_auth_sasl(vs); - break; - #endif /* CONFIG_VNC_SASL */ - - default: /* Should not be possible, but just in case */ -- VNC_DEBUG("Reject auth %d server code bug\n", vs->auth); -+ trace_vnc_auth_fail(vs, vs->auth, "Unhandled auth method", ""); - vnc_write_u8(vs, 1); - if (vs->minor >= 8) { - static const char err[] = "Authentication failed"; -@@ -2572,10 +2569,11 @@ static int protocol_version(VncState *vs, uint8_t *version, size_t len) - vs->minor = 3; - - if (vs->minor == 3) { -+ trace_vnc_auth_start(vs, vs->auth); - if (vs->auth == VNC_AUTH_NONE) { -- VNC_DEBUG("Tell client auth none\n"); - vnc_write_u32(vs, vs->auth); - vnc_flush(vs); -+ trace_vnc_auth_pass(vs, vs->auth); - start_client_init(vs); - } else if (vs->auth == VNC_AUTH_VNC) { - VNC_DEBUG("Tell client VNC auth\n"); -@@ -2583,13 +2581,13 @@ static int protocol_version(VncState *vs, uint8_t *version, size_t len) - vnc_flush(vs); - start_auth_vnc(vs); - } else { -- VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->auth); -+ trace_vnc_auth_fail(vs, vs->auth, -+ "Unsupported auth method for v3.3", ""); - vnc_write_u32(vs, VNC_AUTH_INVALID); - vnc_flush(vs); - vnc_client_error(vs); - } - } else { -- VNC_DEBUG("Telling client we support auth %d\n", vs->auth); - vnc_write_u8(vs, 1); /* num auth */ - vnc_write_u8(vs, vs->auth); - vnc_read_when(vs, protocol_client_auth, 1); -@@ -3946,12 +3944,14 @@ void vnc_display_open(const char *id, Error **errp) - sasl, false, errp) < 0) { - goto fail; - } -+ trace_vnc_auth_init(vd, 0, vd->auth, vd->subauth); - - if (vnc_display_setup_auth(&vd->ws_auth, &vd->ws_subauth, - vd->tlscreds, password, - sasl, true, errp) < 0) { - goto fail; - } -+ trace_vnc_auth_init(vd, 1, vd->ws_auth, vd->ws_subauth); - - #ifdef CONFIG_VNC_SASL - if ((saslErr = sasl_server_init(NULL, "qemu-kvm")) != SASL_OK) { --- -1.8.3.1 - diff --git a/SOURCES/kvm-ui-add-tracing-of-VNC-operations-related-to-QIOChann.patch b/SOURCES/kvm-ui-add-tracing-of-VNC-operations-related-to-QIOChann.patch deleted file mode 100644 index 1d98881..0000000 --- a/SOURCES/kvm-ui-add-tracing-of-VNC-operations-related-to-QIOChann.patch +++ /dev/null @@ -1,163 +0,0 @@ -From 5707c2b3cc6e0312302642914154689d8afda7a0 Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Mon, 5 Feb 2018 11:09:56 +0100 -Subject: [PATCH 02/20] ui: add tracing of VNC operations related to QIOChannel - -RH-Author: Daniel P. Berrange -Message-id: <20180205111012.6210-2-berrange@redhat.com> -Patchwork-id: 78884 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 01/17] ui: add tracing of VNC operations related to QIOChannel -Bugzilla: 1527404 -RH-Acked-by: Gerd Hoffmann -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Thomas Huth - -From: "Daniel P. Berrange" - -Trace anything which opens/closes/wraps a QIOChannel in the -VNC server. - -Signed-off-by: Daniel P. Berrange -Message-id: 20170921121528.23935-2-berrange@redhat.com -Signed-off-by: Gerd Hoffmann -(cherry picked from commit ad6374c43e572e6e53020a97e72e9ea525b08334) -Signed-off-by: Miroslav Rezanina ---- - ui/trace-events | 6 ++++++ - ui/vnc-auth-vencrypt.c | 2 ++ - ui/vnc-ws.c | 6 +++--- - ui/vnc.c | 11 ++++++++--- - 4 files changed, 19 insertions(+), 6 deletions(-) - -diff --git a/ui/trace-events b/ui/trace-events -index 34c2213..e4c02e4 100644 ---- a/ui/trace-events -+++ b/ui/trace-events -@@ -29,6 +29,12 @@ vnc_key_event_ext(bool down, int sym, int keycode, const char *name) "down %d, s - vnc_key_event_map(bool down, int sym, int keycode, const char *name) "down %d, sym 0x%x -> keycode 0x%x [%s]" - vnc_key_sync_numlock(bool on) "%d" - vnc_key_sync_capslock(bool on) "%d" -+vnc_client_eof(void *state, void *ioc) "VNC client EOF state=%p ioc=%p" -+vnc_client_io_error(void *state, void *ioc, const char *msg) "VNC client I/O error state=%p ioc=%p errmsg=%s" -+vnc_client_connect(void *state, void *ioc) "VNC client connect state=%p ioc=%p" -+vnc_client_disconnect_start(void *state, void *ioc) "VNC client disconnect start state=%p ioc=%p" -+vnc_client_disconnect_finish(void *state, void *ioc) "VNC client disconnect finish state=%p ioc=%p" -+vnc_client_io_wrap(void *state, void *ioc, const char *type) "VNC client I/O wrap state=%p ioc=%p type=%s" - - # ui/input.c - input_event_key_number(int conidx, int number, const char *qcode, bool down) "con %d, key number 0x%x [%s], down %d" -diff --git a/ui/vnc-auth-vencrypt.c b/ui/vnc-auth-vencrypt.c -index c3eece4..2a3766a 100644 ---- a/ui/vnc-auth-vencrypt.c -+++ b/ui/vnc-auth-vencrypt.c -@@ -28,6 +28,7 @@ - #include "vnc.h" - #include "qapi/error.h" - #include "qemu/main-loop.h" -+#include "trace.h" - - static void start_auth_vencrypt_subauth(VncState *vs) - { -@@ -124,6 +125,7 @@ static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len - VNC_DEBUG("Start TLS VeNCrypt handshake process\n"); - object_unref(OBJECT(vs->ioc)); - vs->ioc = QIO_CHANNEL(tls); -+ trace_vnc_client_io_wrap(vs, vs->ioc, "tls"); - vs->tls = qio_channel_tls_get_session(tls); - - qio_channel_tls_handshake(tls, -diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c -index eaf3095..6ccad22 100644 ---- a/ui/vnc-ws.c -+++ b/ui/vnc-ws.c -@@ -23,6 +23,7 @@ - #include "vnc.h" - #include "io/channel-websock.h" - #include "qemu/bswap.h" -+#include "trace.h" - - static void vncws_tls_handshake_done(QIOTask *task, - gpointer user_data) -@@ -53,7 +54,6 @@ gboolean vncws_tls_handshake_io(QIOChannel *ioc G_GNUC_UNUSED, - QIOChannelTLS *tls; - Error *err = NULL; - -- VNC_DEBUG("TLS Websocket connection required\n"); - if (vs->ioc_tag) { - g_source_remove(vs->ioc_tag); - vs->ioc_tag = 0; -@@ -73,9 +73,9 @@ gboolean vncws_tls_handshake_io(QIOChannel *ioc G_GNUC_UNUSED, - - qio_channel_set_name(QIO_CHANNEL(tls), "vnc-ws-server-tls"); - -- VNC_DEBUG("Start TLS WS handshake process\n"); - object_unref(OBJECT(vs->ioc)); - vs->ioc = QIO_CHANNEL(tls); -+ trace_vnc_client_io_wrap(vs, vs->ioc, "tls"); - vs->tls = qio_channel_tls_get_session(tls); - - qio_channel_tls_handshake(tls, -@@ -116,7 +116,6 @@ gboolean vncws_handshake_io(QIOChannel *ioc G_GNUC_UNUSED, - VncState *vs = opaque; - QIOChannelWebsock *wioc; - -- VNC_DEBUG("Websocket negotiate starting\n"); - if (vs->ioc_tag) { - g_source_remove(vs->ioc_tag); - vs->ioc_tag = 0; -@@ -127,6 +126,7 @@ gboolean vncws_handshake_io(QIOChannel *ioc G_GNUC_UNUSED, - - object_unref(OBJECT(vs->ioc)); - vs->ioc = QIO_CHANNEL(wioc); -+ trace_vnc_client_io_wrap(vs, vs->ioc, "websock"); - - qio_channel_websock_handshake(wioc, - vncws_handshake_done, -diff --git a/ui/vnc.c b/ui/vnc.c -index 4e1d94f..66783ec 100644 ---- a/ui/vnc.c -+++ b/ui/vnc.c -@@ -1118,6 +1118,7 @@ static void vnc_disconnect_start(VncState *vs) - if (vs->disconnecting) { - return; - } -+ trace_vnc_client_disconnect_start(vs, vs->ioc); - vnc_set_share_mode(vs, VNC_SHARE_MODE_DISCONNECTED); - if (vs->ioc_tag) { - g_source_remove(vs->ioc_tag); -@@ -1131,6 +1132,8 @@ void vnc_disconnect_finish(VncState *vs) - { - int i; - -+ trace_vnc_client_disconnect_finish(vs, vs->ioc); -+ - vnc_jobs_join(vs); /* Wait encoding jobs */ - - vnc_lock_output(vs); -@@ -1184,11 +1187,12 @@ ssize_t vnc_client_io_error(VncState *vs, ssize_t ret, Error **errp) - { - if (ret <= 0) { - if (ret == 0) { -- VNC_DEBUG("Closing down client sock: EOF\n"); -+ trace_vnc_client_eof(vs, vs->ioc); - vnc_disconnect_start(vs); - } else if (ret != QIO_CHANNEL_ERR_BLOCK) { -- VNC_DEBUG("Closing down client sock: ret %zd (%s)\n", -- ret, errp ? error_get_pretty(*errp) : "Unknown"); -+ trace_vnc_client_io_error(vs, vs->ioc, -+ errp ? error_get_pretty(*errp) : -+ "Unknown"); - vnc_disconnect_start(vs); - } - -@@ -2885,6 +2889,7 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc, - bool first_client = QTAILQ_EMPTY(&vd->clients); - int i; - -+ trace_vnc_client_connect(vs, sioc); - vs->sioc = sioc; - object_ref(OBJECT(vs->sioc)); - vs->ioc = QIO_CHANNEL(sioc); --- -1.8.3.1 - diff --git a/SOURCES/kvm-ui-avoid-pointless-VNC-updates-if-framebuffer-isn-t-.patch b/SOURCES/kvm-ui-avoid-pointless-VNC-updates-if-framebuffer-isn-t-.patch deleted file mode 100644 index 226d370..0000000 --- a/SOURCES/kvm-ui-avoid-pointless-VNC-updates-if-framebuffer-isn-t-.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 116f4fa9b500042bf89698a2b319be75f28b9423 Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Mon, 5 Feb 2018 11:10:01 +0100 -Subject: [PATCH 07/20] ui: avoid pointless VNC updates if framebuffer isn't - dirty -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Daniel P. Berrange -Message-id: <20180205111012.6210-7-berrange@redhat.com> -Patchwork-id: 78888 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 06/17] ui: avoid pointless VNC updates if framebuffer isn't dirty -Bugzilla: 1527404 -RH-Acked-by: Gerd Hoffmann -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Thomas Huth - -From: "Daniel P. Berrange" - -The vnc_update_client() method checks the 'has_dirty' flag to see if there are -dirty regions that are pending to send to the client. Regardless of this flag, -if a forced update is requested, updates must be sent. For unknown reasons -though, the code also tries to sent updates if audio capture is enabled. This -makes no sense as audio capture state does not impact framebuffer contents, so -this check is removed. - -Signed-off-by: Daniel P. Berrange -Reviewed-by: Darren Kenny -Reviewed-by: Marc-André Lureau -Message-id: 20171218191228.31018-5-berrange@redhat.com -Signed-off-by: Gerd Hoffmann -(cherry picked from commit 3541b08475d51bddf8aded36576a0ff5a547a978) -Signed-off-by: Miroslav Rezanina ---- - ui/vnc.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ui/vnc.c b/ui/vnc.c -index 2a2e47c..e159fe6 100644 ---- a/ui/vnc.c -+++ b/ui/vnc.c -@@ -984,7 +984,7 @@ static int vnc_update_client(VncState *vs, int has_dirty) - return 0; - } - -- if (!vs->has_dirty && !vs->audio_cap && !vs->force_update) { -+ if (!vs->has_dirty && !vs->force_update) { - return 0; - } - --- -1.8.3.1 - diff --git a/SOURCES/kvm-ui-avoid-sign-extension-using-client-width-height.patch b/SOURCES/kvm-ui-avoid-sign-extension-using-client-width-height.patch deleted file mode 100644 index 2678876..0000000 --- a/SOURCES/kvm-ui-avoid-sign-extension-using-client-width-height.patch +++ /dev/null @@ -1,103 +0,0 @@ -From 31d7d5079364726d5a048d96e1e368173b83ab80 Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Mon, 5 Feb 2018 11:10:11 +0100 -Subject: [PATCH 17/20] ui: avoid sign extension using client width/height - -RH-Author: Daniel P. Berrange -Message-id: <20180205111012.6210-17-berrange@redhat.com> -Patchwork-id: 78889 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 16/17] ui: avoid sign extension using client width/height -Bugzilla: 1527404 -RH-Acked-by: Gerd Hoffmann -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Thomas Huth - -From: "Daniel P. Berrange" - -Pixman returns a signed int for the image width/height, but the VNC -protocol only permits a unsigned int16. Effective framebuffer size -is determined by the guest, limited by the video RAM size, so the -dimensions are unlikely to exceed the range of an unsigned int16, -but this is not currently validated. - -With the current use of 'int' for client width/height, the calculation -of offsets in vnc_update_throttle_offset() suffers from integer size -promotion and sign extension, causing coverity warnings - -*** CID 1385147: Integer handling issues (SIGN_EXTENSION) -/ui/vnc.c: 979 in vnc_update_throttle_offset() -973 * than that the client would already suffering awful audio -974 * glitches, so dropping samples is no worse really). -975 */ -976 static void vnc_update_throttle_offset(VncState *vs) -977 { -978 size_t offset = ->>> CID 1385147: Integer handling issues (SIGN_EXTENSION) ->>> Suspicious implicit sign extension: - "vs->client_pf.bytes_per_pixel" with type "unsigned char" (8 bits, - unsigned) is promoted in "vs->client_width * vs->client_height * - vs->client_pf.bytes_per_pixel" to type "int" (32 bits, signed), then - sign-extended to type "unsigned long" (64 bits, unsigned). If - "vs->client_width * vs->client_height * vs->client_pf.bytes_per_pixel" - is greater than 0x7FFFFFFF, the upper bits of the result will all be 1. -979 vs->client_width * vs->client_height * vs->client_pf.bytes_per_pixel; - -Change client_width / client_height to be a size_t to avoid sign -extension and integer promotion. Then validate that dimensions are in -range wrt the RFB protocol u16 limits. - -Signed-off-by: Daniel P. Berrange -Message-id: 20180118155254.17053-1-berrange@redhat.com -Signed-off-by: Gerd Hoffmann -(cherry picked from commit 4c956bd81e2e16afd19d38d1fdeba6d9faa8a1ae) -Signed-off-by: Miroslav Rezanina ---- - ui/vnc.c | 9 +++++++++ - ui/vnc.h | 4 ++-- - 2 files changed, 11 insertions(+), 2 deletions(-) - -diff --git a/ui/vnc.c b/ui/vnc.c -index b303930..fec4f4c 100644 ---- a/ui/vnc.c -+++ b/ui/vnc.c -@@ -672,6 +672,11 @@ static void vnc_desktop_resize(VncState *vs) - vs->client_height == pixman_image_get_height(vs->vd->server)) { - return; - } -+ -+ assert(pixman_image_get_width(vs->vd->server) < 65536 && -+ pixman_image_get_width(vs->vd->server) >= 0); -+ assert(pixman_image_get_height(vs->vd->server) < 65536 && -+ pixman_image_get_height(vs->vd->server) >= 0); - vs->client_width = pixman_image_get_width(vs->vd->server); - vs->client_height = pixman_image_get_height(vs->vd->server); - vnc_lock_output(vs); -@@ -2490,6 +2495,10 @@ static int protocol_client_init(VncState *vs, uint8_t *data, size_t len) - return 0; - } - -+ assert(pixman_image_get_width(vs->vd->server) < 65536 && -+ pixman_image_get_width(vs->vd->server) >= 0); -+ assert(pixman_image_get_height(vs->vd->server) < 65536 && -+ pixman_image_get_height(vs->vd->server) >= 0); - vs->client_width = pixman_image_get_width(vs->vd->server); - vs->client_height = pixman_image_get_height(vs->vd->server); - vnc_write_u16(vs, vs->client_width); -diff --git a/ui/vnc.h b/ui/vnc.h -index 0c33a5f..bbda054 100644 ---- a/ui/vnc.h -+++ b/ui/vnc.h -@@ -278,8 +278,8 @@ struct VncState - int last_x; - int last_y; - uint32_t last_bmask; -- int client_width; -- int client_height; -+ size_t client_width; /* limited to u16 by RFB proto */ -+ size_t client_height; /* limited to u16 by RFB proto */ - VncShareMode share_mode; - - uint32_t vnc_encoding; --- -1.8.3.1 - diff --git a/SOURCES/kvm-ui-correctly-advance-output-buffer-when-writing-SASL.patch b/SOURCES/kvm-ui-correctly-advance-output-buffer-when-writing-SASL.patch deleted file mode 100644 index 955f5b2..0000000 --- a/SOURCES/kvm-ui-correctly-advance-output-buffer-when-writing-SASL.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 95d2ea23e72d2df6299fcdaa700f5b31b79de741 Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Mon, 5 Feb 2018 11:10:12 +0100 -Subject: [PATCH 18/20] ui: correctly advance output buffer when writing SASL - data -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Daniel P. Berrange -Message-id: <20180205111012.6210-18-berrange@redhat.com> -Patchwork-id: 78891 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 17/17] ui: correctly advance output buffer when writing SASL data -Bugzilla: 1527404 -RH-Acked-by: Gerd Hoffmann -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Thomas Huth - -In this previous commit: - - commit 8f61f1c5a6bc06438a1172efa80bc7606594fa07 - Author: Daniel P. Berrange - Date: Mon Dec 18 19:12:20 2017 +0000 - - ui: track how much decoded data we consumed when doing SASL encoding - -I attempted to fix a flaw with tracking how much data had actually been -processed when encoding with SASL. With that flaw, the VNC server could -mistakenly discard queued data that had not been sent. - -The fix was not quite right though, because it merely decremented the -vs->output.offset value. This is effectively discarding data from the -end of the pending output buffer. We actually need to discard data from -the start of the pending output buffer. We also want to free memory that -is no longer required. The correct way to handle this is to use the -buffer_advance() helper method instead of directly manipulating the -offset value. - -Reported-by: Laszlo Ersek -Signed-off-by: Daniel P. Berrangé -Reviewed-by: Eric Blake -Reviewed-by: Laszlo Ersek -Message-id: 20180201155841.27509-1-berrange@redhat.com -Signed-off-by: Gerd Hoffmann -(cherry picked from commit 627ebec208a8809818589e17f4fce55a59420ad2) -Signed-off-by: Miroslav Rezanina ---- - ui/vnc-auth-sasl.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ui/vnc-auth-sasl.c b/ui/vnc-auth-sasl.c -index 74a5f51..fbccca8 100644 ---- a/ui/vnc-auth-sasl.c -+++ b/ui/vnc-auth-sasl.c -@@ -84,7 +84,7 @@ size_t vnc_client_write_sasl(VncState *vs) - } else { - vs->force_update_offset -= vs->sasl.encodedRawLength; - } -- vs->output.offset -= vs->sasl.encodedRawLength; -+ buffer_advance(&vs->output, vs->sasl.encodedRawLength); - vs->sasl.encoded = NULL; - vs->sasl.encodedOffset = vs->sasl.encodedLength = 0; - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-ui-correctly-reset-framebuffer-update-state-after-pr.patch b/SOURCES/kvm-ui-correctly-reset-framebuffer-update-state-after-pr.patch deleted file mode 100644 index 915d775..0000000 --- a/SOURCES/kvm-ui-correctly-reset-framebuffer-update-state-after-pr.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 0165d714e9150595c6bceb0d538018d486d7c519 Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Mon, 5 Feb 2018 11:10:04 +0100 -Subject: [PATCH 10/20] ui: correctly reset framebuffer update state after - processing dirty regions -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Daniel P. Berrange -Message-id: <20180205111012.6210-10-berrange@redhat.com> -Patchwork-id: 78885 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 09/17] ui: correctly reset framebuffer update state after processing dirty regions -Bugzilla: 1527404 -RH-Acked-by: Gerd Hoffmann -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Thomas Huth - -From: "Daniel P. Berrange" - -According to the RFB protocol, a client sends one or more framebuffer update -requests to the server. The server can reply with a single framebuffer update -response, that covers all previously received requests. Once the client has -read this update from the server, it may send further framebuffer update -requests to monitor future changes. The client is free to delay sending the -framebuffer update request if it needs to throttle the amount of data it is -reading from the server. - -The QEMU VNC server, however, has never correctly handled the framebuffer -update requests. Once QEMU has received an update request, it will continue to -send client updates forever, even if the client hasn't asked for further -updates. This prevents the client from throttling back data it gets from the -server. This change fixes the flawed logic such that after a set of updates are -sent out, QEMU waits for a further update request before sending more data. - -Signed-off-by: Daniel P. Berrange -Reviewed-by: Darren Kenny -Reviewed-by: Marc-André Lureau -Message-id: 20171218191228.31018-8-berrange@redhat.com -Signed-off-by: Gerd Hoffmann -(cherry picked from commit 728a7ac95484a7ba5e624ccbac4c1326571576b0) -Signed-off-by: Miroslav Rezanina ---- - ui/vnc.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ui/vnc.c b/ui/vnc.c -index 2320421..3707b87 100644 ---- a/ui/vnc.c -+++ b/ui/vnc.c -@@ -1031,7 +1031,7 @@ static int vnc_update_client(VncState *vs, int has_dirty) - } - - vnc_job_push(job); -- vs->update = VNC_STATE_UPDATE_INCREMENTAL; -+ vs->update = VNC_STATE_UPDATE_NONE; - vs->has_dirty = 0; - return n; - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-ui-fix-VNC-client-throttling-when-audio-capture-is-a.patch b/SOURCES/kvm-ui-fix-VNC-client-throttling-when-audio-capture-is-a.patch deleted file mode 100644 index e9585b2..0000000 --- a/SOURCES/kvm-ui-fix-VNC-client-throttling-when-audio-capture-is-a.patch +++ /dev/null @@ -1,223 +0,0 @@ -From e961103621520003d54a8c7eac562c2b9e8436db Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Mon, 5 Feb 2018 11:10:06 +0100 -Subject: [PATCH 12/20] ui: fix VNC client throttling when audio capture is - active -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Daniel P. Berrange -Message-id: <20180205111012.6210-12-berrange@redhat.com> -Patchwork-id: 78883 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 11/17] ui: fix VNC client throttling when audio capture is active -Bugzilla: 1527404 -RH-Acked-by: Gerd Hoffmann -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Thomas Huth - -From: "Daniel P. Berrange" - -The VNC server must throttle data sent to the client to prevent the 'output' -buffer size growing without bound, if the client stops reading data off the -socket (either maliciously or due to stalled/slow network connection). - -The current throttling is very crude because it simply checks whether the -output buffer offset is zero. This check must be disabled if audio capture is -enabled, because when streaming audio the output buffer offset will rarely be -zero due to queued audio data, and so this would starve framebuffer updates. - -As a result, the VNC client can cause QEMU to allocate arbitrary amounts of RAM. -They can first start something in the guest that triggers lots of framebuffer -updates eg play a youtube video. Then enable audio capture, and simply never -read data back from the server. This can easily make QEMU's VNC server send -buffer consume 100MB of RAM per second, until the OOM killer starts reaping -processes (hopefully the rogue QEMU process, but it might pick others...). - -To address this we make the throttling more intelligent, so we can throttle -when audio capture is active too. To determine how to throttle incremental -updates or audio data, we calculate a size threshold. Normally the threshold is -the approximate number of bytes associated with a single complete framebuffer -update. ie width * height * bytes per pixel. We'll send incremental updates -until we hit this threshold, at which point we'll stop sending updates until -data has been written to the wire, causing the output buffer offset to fall -back below the threshold. - -If audio capture is enabled, we increase the size of the threshold to also -allow for upto 1 seconds worth of audio data samples. ie nchannels * bytes -per sample * frequency. This allows the output buffer to have a mixture of -incremental framebuffer updates and audio data queued, but once the threshold -is exceeded, audio data will be dropped and incremental updates will be -throttled. - -This unbounded memory growth affects all VNC server configurations supported by -QEMU, with no workaround possible. The mitigating factor is that it can only be -triggered by a client that has authenticated with the VNC server, and who is -able to trigger a large quantity of framebuffer updates or audio samples from -the guest OS. Mostly they'll just succeed in getting the OOM killer to kill -their own QEMU process, but its possible other processes can get taken out as -collateral damage. - -This is a more general variant of the similar unbounded memory usage flaw in -the websockets server, that was previously assigned CVE-2017-15268, and fixed -in 2.11 by: - - commit a7b20a8efa28e5f22c26c06cd06c2f12bc863493 - Author: Daniel P. Berrange - Date: Mon Oct 9 14:43:42 2017 +0100 - - io: monitor encoutput buffer size from websocket GSource - -This new general memory usage flaw has been assigned CVE-2017-15124, and is -partially fixed by this patch. - -Signed-off-by: Daniel P. Berrange -Reviewed-by: Darren Kenny -Reviewed-by: Marc-André Lureau -Message-id: 20171218191228.31018-10-berrange@redhat.com -Signed-off-by: Gerd Hoffmann -(cherry picked from commit e2b72cb6e0443d90d7ab037858cb6834b6cca852) -Signed-off-by: Miroslav Rezanina ---- - ui/vnc.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- - ui/vnc.h | 6 ++++++ - 2 files changed, 70 insertions(+), 8 deletions(-) - -diff --git a/ui/vnc.c b/ui/vnc.c -index 2b04050..e132b74 100644 ---- a/ui/vnc.c -+++ b/ui/vnc.c -@@ -60,6 +60,7 @@ static QTAILQ_HEAD(, VncDisplay) vnc_displays = - - static int vnc_cursor_define(VncState *vs); - static void vnc_release_modifiers(VncState *vs); -+static void vnc_update_throttle_offset(VncState *vs); - - static void vnc_set_share_mode(VncState *vs, VncShareMode mode) - { -@@ -766,6 +767,7 @@ static void vnc_dpy_switch(DisplayChangeListener *dcl, - vnc_set_area_dirty(vs->dirty, vd, 0, 0, - vnc_width(vd), - vnc_height(vd)); -+ vnc_update_throttle_offset(vs); - } - } - -@@ -961,16 +963,67 @@ static int find_and_clear_dirty_height(VncState *vs, - return h; - } - -+/* -+ * Figure out how much pending data we should allow in the output -+ * buffer before we throttle incremental display updates, and/or -+ * drop audio samples. -+ * -+ * We allow for equiv of 1 full display's worth of FB updates, -+ * and 1 second of audio samples. If audio backlog was larger -+ * than that the client would already suffering awful audio -+ * glitches, so dropping samples is no worse really). -+ */ -+static void vnc_update_throttle_offset(VncState *vs) -+{ -+ size_t offset = -+ vs->client_width * vs->client_height * vs->client_pf.bytes_per_pixel; -+ -+ if (vs->audio_cap) { -+ int freq = vs->as.freq; -+ /* We don't limit freq when reading settings from client, so -+ * it could be upto MAX_INT in size. 48khz is a sensible -+ * upper bound for trustworthy clients */ -+ int bps; -+ if (freq > 48000) { -+ freq = 48000; -+ } -+ switch (vs->as.fmt) { -+ default: -+ case AUD_FMT_U8: -+ case AUD_FMT_S8: -+ bps = 1; -+ break; -+ case AUD_FMT_U16: -+ case AUD_FMT_S16: -+ bps = 2; -+ break; -+ case AUD_FMT_U32: -+ case AUD_FMT_S32: -+ bps = 4; -+ break; -+ } -+ offset += freq * bps * vs->as.nchannels; -+ } -+ -+ /* Put a floor of 1MB on offset, so that if we have a large pending -+ * buffer and the display is resized to a small size & back again -+ * we don't suddenly apply a tiny send limit -+ */ -+ offset = MAX(offset, 1024 * 1024); -+ -+ vs->throttle_output_offset = offset; -+} -+ - static bool vnc_should_update(VncState *vs) - { - switch (vs->update) { - case VNC_STATE_UPDATE_NONE: - break; - case VNC_STATE_UPDATE_INCREMENTAL: -- /* Only allow incremental updates if the output buffer -- * is empty, or if audio capture is enabled. -+ /* Only allow incremental updates if the pending send queue -+ * is less than the permitted threshold - */ -- if (!vs->output.offset || vs->audio_cap) { -+ if (vs->output.offset < vs->throttle_output_offset) { - return true; - } - break; -@@ -1084,11 +1137,13 @@ static void audio_capture(void *opaque, void *buf, int size) - VncState *vs = opaque; - - vnc_lock_output(vs); -- vnc_write_u8(vs, VNC_MSG_SERVER_QEMU); -- vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO); -- vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_DATA); -- vnc_write_u32(vs, size); -- vnc_write(vs, buf, size); -+ if (vs->output.offset < vs->throttle_output_offset) { -+ vnc_write_u8(vs, VNC_MSG_SERVER_QEMU); -+ vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO); -+ vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_DATA); -+ vnc_write_u32(vs, size); -+ vnc_write(vs, buf, size); -+ } - vnc_unlock_output(vs); - vnc_flush(vs); - } -@@ -2288,6 +2343,7 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len) - break; - } - -+ vnc_update_throttle_offset(vs); - vnc_read_when(vs, protocol_client_msg, 1); - return 0; - } -diff --git a/ui/vnc.h b/ui/vnc.h -index b9d310e..8fe6959 100644 ---- a/ui/vnc.h -+++ b/ui/vnc.h -@@ -298,6 +298,12 @@ struct VncState - - VncClientInfo *info; - -+ /* We allow multiple incremental updates or audio capture -+ * samples to be queued in output buffer, provided the -+ * buffer size doesn't exceed this threshold. The value -+ * is calculating dynamically based on framebuffer size -+ * and audio sample settings in vnc_update_throttle_offset() */ -+ size_t throttle_output_offset; - Buffer output; - Buffer input; - /* current output mode information */ --- -1.8.3.1 - diff --git a/SOURCES/kvm-ui-fix-VNC-client-throttling-when-forced-update-is-r.patch b/SOURCES/kvm-ui-fix-VNC-client-throttling-when-forced-update-is-r.patch deleted file mode 100644 index 79bb35e..0000000 --- a/SOURCES/kvm-ui-fix-VNC-client-throttling-when-forced-update-is-r.patch +++ /dev/null @@ -1,201 +0,0 @@ -From bf44407132cb0c39e59bb2f7f72bde9a7b085c70 Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Mon, 5 Feb 2018 11:10:07 +0100 -Subject: [PATCH 13/20] ui: fix VNC client throttling when forced update is - requested -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Daniel P. Berrange -Message-id: <20180205111012.6210-13-berrange@redhat.com> -Patchwork-id: 78882 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 12/17] ui: fix VNC client throttling when forced update is requested -Bugzilla: 1527404 -RH-Acked-by: Gerd Hoffmann -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Thomas Huth - -From: "Daniel P. Berrange" - -The VNC server must throttle data sent to the client to prevent the 'output' -buffer size growing without bound, if the client stops reading data off the -socket (either maliciously or due to stalled/slow network connection). - -The current throttling is very crude because it simply checks whether the -output buffer offset is zero. This check is disabled if the client has requested -a forced update, because we want to send these as soon as possible. - -As a result, the VNC client can cause QEMU to allocate arbitrary amounts of RAM. -They can first start something in the guest that triggers lots of framebuffer -updates eg play a youtube video. Then repeatedly send full framebuffer update -requests, but never read data back from the server. This can easily make QEMU's -VNC server send buffer consume 100MB of RAM per second, until the OOM killer -starts reaping processes (hopefully the rogue QEMU process, but it might pick -others...). - -To address this we make the throttling more intelligent, so we can throttle -full updates. When we get a forced update request, we keep track of exactly how -much data we put on the output buffer. We will not process a subsequent forced -update request until this data has been fully sent on the wire. We always allow -one forced update request to be in flight, regardless of what data is queued -for incremental updates or audio data. The slight complication is that we do -not initially know how much data an update will send, as this is done in the -background by the VNC job thread. So we must track the fact that the job thread -has an update pending, and not process any further updates until this job is -has been completed & put data on the output buffer. - -This unbounded memory growth affects all VNC server configurations supported by -QEMU, with no workaround possible. The mitigating factor is that it can only be -triggered by a client that has authenticated with the VNC server, and who is -able to trigger a large quantity of framebuffer updates or audio samples from -the guest OS. Mostly they'll just succeed in getting the OOM killer to kill -their own QEMU process, but its possible other processes can get taken out as -collateral damage. - -This is a more general variant of the similar unbounded memory usage flaw in -the websockets server, that was previously assigned CVE-2017-15268, and fixed -in 2.11 by: - - commit a7b20a8efa28e5f22c26c06cd06c2f12bc863493 - Author: Daniel P. Berrange - Date: Mon Oct 9 14:43:42 2017 +0100 - - io: monitor encoutput buffer size from websocket GSource - -This new general memory usage flaw has been assigned CVE-2017-15124, and is -partially fixed by this patch. - -Signed-off-by: Daniel P. Berrange -Reviewed-by: Darren Kenny -Reviewed-by: Marc-André Lureau -Message-id: 20171218191228.31018-11-berrange@redhat.com -Signed-off-by: Gerd Hoffmann -(cherry picked from commit ada8d2e4369ea49677d8672ac81bce73eefd5b54) -Signed-off-by: Miroslav Rezanina ---- - ui/vnc-auth-sasl.c | 5 +++++ - ui/vnc-jobs.c | 5 +++++ - ui/vnc.c | 28 ++++++++++++++++++++++++---- - ui/vnc.h | 7 +++++++ - 4 files changed, 41 insertions(+), 4 deletions(-) - -diff --git a/ui/vnc-auth-sasl.c b/ui/vnc-auth-sasl.c -index 761493b..8c1cdde 100644 ---- a/ui/vnc-auth-sasl.c -+++ b/ui/vnc-auth-sasl.c -@@ -79,6 +79,11 @@ long vnc_client_write_sasl(VncState *vs) - - vs->sasl.encodedOffset += ret; - if (vs->sasl.encodedOffset == vs->sasl.encodedLength) { -+ if (vs->sasl.encodedRawLength >= vs->force_update_offset) { -+ vs->force_update_offset = 0; -+ } else { -+ vs->force_update_offset -= vs->sasl.encodedRawLength; -+ } - vs->output.offset -= vs->sasl.encodedRawLength; - vs->sasl.encoded = NULL; - vs->sasl.encodedOffset = vs->sasl.encodedLength = 0; -diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c -index f786777..e326679 100644 ---- a/ui/vnc-jobs.c -+++ b/ui/vnc-jobs.c -@@ -152,6 +152,11 @@ void vnc_jobs_consume_buffer(VncState *vs) - vs->ioc, G_IO_IN | G_IO_OUT, vnc_client_io, vs, NULL); - } - buffer_move(&vs->output, &vs->jobs_buffer); -+ -+ if (vs->job_update == VNC_STATE_UPDATE_FORCE) { -+ vs->force_update_offset = vs->output.offset; -+ } -+ vs->job_update = VNC_STATE_UPDATE_NONE; - } - flush = vs->ioc != NULL && vs->abort != true; - vnc_unlock_output(vs); -diff --git a/ui/vnc.c b/ui/vnc.c -index e132b74..7f2210f 100644 ---- a/ui/vnc.c -+++ b/ui/vnc.c -@@ -1021,14 +1021,28 @@ static bool vnc_should_update(VncState *vs) - break; - case VNC_STATE_UPDATE_INCREMENTAL: - /* Only allow incremental updates if the pending send queue -- * is less than the permitted threshold -+ * is less than the permitted threshold, and the job worker -+ * is completely idle. - */ -- if (vs->output.offset < vs->throttle_output_offset) { -+ if (vs->output.offset < vs->throttle_output_offset && -+ vs->job_update == VNC_STATE_UPDATE_NONE) { - return true; - } - break; - case VNC_STATE_UPDATE_FORCE: -- return true; -+ /* Only allow forced updates if the pending send queue -+ * does not contain a previous forced update, and the -+ * job worker is completely idle. -+ * -+ * Note this means we'll queue a forced update, even if -+ * the output buffer size is otherwise over the throttle -+ * output limit. -+ */ -+ if (vs->force_update_offset == 0 && -+ vs->job_update == VNC_STATE_UPDATE_NONE) { -+ return true; -+ } -+ break; - } - return false; - } -@@ -1096,8 +1110,9 @@ static int vnc_update_client(VncState *vs, int has_dirty) - } - } - -- vnc_job_push(job); -+ vs->job_update = vs->update; - vs->update = VNC_STATE_UPDATE_NONE; -+ vnc_job_push(job); - vs->has_dirty = 0; - return n; - } -@@ -1332,6 +1347,11 @@ static ssize_t vnc_client_write_plain(VncState *vs) - if (!ret) - return 0; - -+ if (ret >= vs->force_update_offset) { -+ vs->force_update_offset = 0; -+ } else { -+ vs->force_update_offset -= ret; -+ } - buffer_advance(&vs->output, ret); - - if (vs->output.offset == 0) { -diff --git a/ui/vnc.h b/ui/vnc.h -index 8fe6959..3f4cd4d 100644 ---- a/ui/vnc.h -+++ b/ui/vnc.h -@@ -271,6 +271,7 @@ struct VncState - - VncDisplay *vd; - VncStateUpdate update; /* Most recent pending request from client */ -+ VncStateUpdate job_update; /* Currently processed by job thread */ - int has_dirty; - uint32_t features; - int absolute; -@@ -298,6 +299,12 @@ struct VncState - - VncClientInfo *info; - -+ /* Job thread bottom half has put data for a forced update -+ * into the output buffer. This offset points to the end of -+ * the update data in the output buffer. This lets us determine -+ * when a force update is fully sent to the client, allowing -+ * us to process further forced updates. */ -+ size_t force_update_offset; - /* We allow multiple incremental updates or audio capture - * samples to be queued in output buffer, provided the - * buffer size doesn't exceed this threshold. The value --- -1.8.3.1 - diff --git a/SOURCES/kvm-ui-fix-dcl-unregister.patch b/SOURCES/kvm-ui-fix-dcl-unregister.patch deleted file mode 100644 index ae4f07e..0000000 --- a/SOURCES/kvm-ui-fix-dcl-unregister.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0632da4d9e2ec1e445840299f1e0fbda7a61bef4 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Fri, 12 Jan 2018 13:47:48 +0100 -Subject: [PATCH 07/12] ui: fix dcl unregister -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Gerd Hoffmann -Message-id: <20180112134748.13701-2-kraxel@redhat.com> -Patchwork-id: 78568 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 1/1] ui: fix dcl unregister -Bugzilla: 1510809 -RH-Acked-by: John Snow -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Laszlo Ersek - -register checks for dcl->ds being NULL, to avoid registering -the same dcl twice. - -Therefore dcl->ds must be cleared on unregister, otherwise -un-registering and re-registering doesn't work. - -Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1510809 -Signed-off-by: Gerd Hoffmann -Reviewed-by: Marc-André Lureau -Message-id: 20171109105154.29414-1-kraxel@redhat.com -(cherry picked from commit 777c5f1e436d334a57b650b6951c13d8d2799df0) -Signed-off-by: Miroslav Rezanina ---- - ui/console.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/ui/console.c b/ui/console.c -index 2616f9c..6967fd4 100644 ---- a/ui/console.c -+++ b/ui/console.c -@@ -1489,6 +1489,7 @@ void unregister_displaychangelistener(DisplayChangeListener *dcl) - dcl->con->dcls--; - } - QLIST_REMOVE(dcl, next); -+ dcl->ds = NULL; - gui_setup_refresh(ds); - } - --- -1.8.3.1 - diff --git a/SOURCES/kvm-ui-introduce-enum-to-track-VNC-client-framebuffer-up.patch b/SOURCES/kvm-ui-introduce-enum-to-track-VNC-client-framebuffer-up.patch deleted file mode 100644 index f04cb75..0000000 --- a/SOURCES/kvm-ui-introduce-enum-to-track-VNC-client-framebuffer-up.patch +++ /dev/null @@ -1,121 +0,0 @@ -From 408b757578e8d9b96756c3753fb6661cd812d62f Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Mon, 5 Feb 2018 11:10:03 +0100 -Subject: [PATCH 09/20] ui: introduce enum to track VNC client framebuffer - update request state -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Daniel P. Berrange -Message-id: <20180205111012.6210-9-berrange@redhat.com> -Patchwork-id: 78879 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 08/17] ui: introduce enum to track VNC client framebuffer update request state -Bugzilla: 1527404 -RH-Acked-by: Gerd Hoffmann -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Thomas Huth - -From: "Daniel P. Berrange" - -Currently the VNC servers tracks whether a client has requested an incremental -or forced update with two boolean flags. There are only really 3 distinct -states to track, so create an enum to more accurately reflect permitted states. - -Signed-off-by: Daniel P. Berrange -Reviewed-by: Darren Kenny -Reviewed-by: Marc-André Lureau -Message-id: 20171218191228.31018-7-berrange@redhat.com -Signed-off-by: Gerd Hoffmann -(cherry picked from commit fef1bbadfb2c3027208eb3d14b43e1bdb51166ca) -Signed-off-by: Miroslav Rezanina ---- - ui/vnc.c | 21 +++++++++++---------- - ui/vnc.h | 9 +++++++-- - 2 files changed, 18 insertions(+), 12 deletions(-) - -diff --git a/ui/vnc.c b/ui/vnc.c -index e159fe6..2320421 100644 ---- a/ui/vnc.c -+++ b/ui/vnc.c -@@ -975,16 +975,17 @@ static int vnc_update_client(VncState *vs, int has_dirty) - } - - vs->has_dirty += has_dirty; -- if (!vs->need_update) { -+ if (vs->update == VNC_STATE_UPDATE_NONE) { - return 0; - } - -- if (vs->output.offset && !vs->audio_cap && !vs->force_update) { -+ if (vs->output.offset && !vs->audio_cap && -+ vs->update != VNC_STATE_UPDATE_FORCE) { - /* kernel send buffers are full -> drop frames to throttle */ - return 0; - } - -- if (!vs->has_dirty && !vs->force_update) { -+ if (!vs->has_dirty && vs->update != VNC_STATE_UPDATE_FORCE) { - return 0; - } - -@@ -1030,7 +1031,7 @@ static int vnc_update_client(VncState *vs, int has_dirty) - } - - vnc_job_push(job); -- vs->force_update = 0; -+ vs->update = VNC_STATE_UPDATE_INCREMENTAL; - vs->has_dirty = 0; - return n; - } -@@ -1869,14 +1870,14 @@ static void ext_key_event(VncState *vs, int down, - static void framebuffer_update_request(VncState *vs, int incremental, - int x, int y, int w, int h) - { -- vs->need_update = 1; -- - if (incremental) { -- return; -+ if (vs->update != VNC_STATE_UPDATE_FORCE) { -+ vs->update = VNC_STATE_UPDATE_INCREMENTAL; -+ } -+ } else { -+ vs->update = VNC_STATE_UPDATE_FORCE; -+ vnc_set_area_dirty(vs->dirty, vs->vd, x, y, w, h); - } -- -- vs->force_update = 1; -- vnc_set_area_dirty(vs->dirty, vs->vd, x, y, w, h); - } - - static void send_ext_key_event_ack(VncState *vs) -diff --git a/ui/vnc.h b/ui/vnc.h -index 694cf32..b9d310e 100644 ---- a/ui/vnc.h -+++ b/ui/vnc.h -@@ -252,6 +252,12 @@ struct VncJob - QTAILQ_ENTRY(VncJob) next; - }; - -+typedef enum { -+ VNC_STATE_UPDATE_NONE, -+ VNC_STATE_UPDATE_INCREMENTAL, -+ VNC_STATE_UPDATE_FORCE, -+} VncStateUpdate; -+ - struct VncState - { - QIOChannelSocket *sioc; /* The underlying socket */ -@@ -264,8 +270,7 @@ struct VncState - * vnc-jobs-async.c */ - - VncDisplay *vd; -- int need_update; -- int force_update; -+ VncStateUpdate update; /* Most recent pending request from client */ - int has_dirty; - uint32_t features; - int absolute; --- -1.8.3.1 - diff --git a/SOURCES/kvm-ui-mix-misleading-comments-return-types-of-VNC-I-O-h.patch b/SOURCES/kvm-ui-mix-misleading-comments-return-types-of-VNC-I-O-h.patch deleted file mode 100644 index bb46077..0000000 --- a/SOURCES/kvm-ui-mix-misleading-comments-return-types-of-VNC-I-O-h.patch +++ /dev/null @@ -1,193 +0,0 @@ -From a04141c5a3565ac437ff7093f36ddf0fb60acdd5 Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Mon, 5 Feb 2018 11:10:10 +0100 -Subject: [PATCH 16/20] ui: mix misleading comments & return types of VNC I/O - helper methods -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Daniel P. Berrange -Message-id: <20180205111012.6210-16-berrange@redhat.com> -Patchwork-id: 78892 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 15/17] ui: mix misleading comments & return types of VNC I/O helper methods -Bugzilla: 1527404 -RH-Acked-by: Gerd Hoffmann -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Thomas Huth - -From: "Daniel P. Berrange" - -While the QIOChannel APIs for reading/writing data return ssize_t, with negative -value indicating an error, the VNC code passes this return value through the -vnc_client_io_error() method. This detects the error condition, disconnects the -client and returns 0 to indicate error. Thus all the VNC helper methods should -return size_t (unsigned), and misleading comments which refer to the possibility -of negative return values need fixing. - -Signed-off-by: Daniel P. Berrange -Reviewed-by: Darren Kenny -Reviewed-by: Marc-André Lureau -Message-id: 20171218191228.31018-14-berrange@redhat.com -Signed-off-by: Gerd Hoffmann -(cherry picked from commit 30b80fd5269257f55203b7072c505b4ebaab5115) -Signed-off-by: Miroslav Rezanina ---- - ui/vnc-auth-sasl.c | 8 ++++---- - ui/vnc-auth-sasl.h | 4 ++-- - ui/vnc.c | 29 +++++++++++++++-------------- - ui/vnc.h | 6 +++--- - 4 files changed, 24 insertions(+), 23 deletions(-) - -diff --git a/ui/vnc-auth-sasl.c b/ui/vnc-auth-sasl.c -index 8c1cdde..74a5f51 100644 ---- a/ui/vnc-auth-sasl.c -+++ b/ui/vnc-auth-sasl.c -@@ -48,9 +48,9 @@ void vnc_sasl_client_cleanup(VncState *vs) - } - - --long vnc_client_write_sasl(VncState *vs) -+size_t vnc_client_write_sasl(VncState *vs) - { -- long ret; -+ size_t ret; - - VNC_DEBUG("Write SASL: Pending output %p size %zd offset %zd " - "Encoded: %p size %d offset %d\n", -@@ -106,9 +106,9 @@ long vnc_client_write_sasl(VncState *vs) - } - - --long vnc_client_read_sasl(VncState *vs) -+size_t vnc_client_read_sasl(VncState *vs) - { -- long ret; -+ size_t ret; - uint8_t encoded[4096]; - const char *decoded; - unsigned int decodedLen; -diff --git a/ui/vnc-auth-sasl.h b/ui/vnc-auth-sasl.h -index b9d8de1..2ae224e 100644 ---- a/ui/vnc-auth-sasl.h -+++ b/ui/vnc-auth-sasl.h -@@ -65,8 +65,8 @@ struct VncDisplaySASL { - - void vnc_sasl_client_cleanup(VncState *vs); - --long vnc_client_read_sasl(VncState *vs); --long vnc_client_write_sasl(VncState *vs); -+size_t vnc_client_read_sasl(VncState *vs); -+size_t vnc_client_write_sasl(VncState *vs); - - void start_auth_sasl(VncState *vs); - -diff --git a/ui/vnc.c b/ui/vnc.c -index 26f58bc..b303930 100644 ---- a/ui/vnc.c -+++ b/ui/vnc.c -@@ -1272,7 +1272,7 @@ void vnc_disconnect_finish(VncState *vs) - g_free(vs); - } - --ssize_t vnc_client_io_error(VncState *vs, ssize_t ret, Error **errp) -+size_t vnc_client_io_error(VncState *vs, ssize_t ret, Error **errp) - { - if (ret <= 0) { - if (ret == 0) { -@@ -1315,9 +1315,9 @@ void vnc_client_error(VncState *vs) - * - * Returns the number of bytes written, which may be less than - * the requested 'datalen' if the socket would block. Returns -- * -1 on error, and disconnects the client socket. -+ * 0 on I/O error, and disconnects the client socket. - */ --ssize_t vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen) -+size_t vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen) - { - Error *err = NULL; - ssize_t ret; -@@ -1335,13 +1335,13 @@ ssize_t vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen) - * will switch the FD poll() handler back to read monitoring. - * - * Returns the number of bytes written, which may be less than -- * the buffered output data if the socket would block. Returns -- * -1 on error, and disconnects the client socket. -+ * the buffered output data if the socket would block. Returns -+ * 0 on I/O error, and disconnects the client socket. - */ --static ssize_t vnc_client_write_plain(VncState *vs) -+static size_t vnc_client_write_plain(VncState *vs) - { - size_t offset; -- ssize_t ret; -+ size_t ret; - - #ifdef CONFIG_VNC_SASL - VNC_DEBUG("Write Plain: Pending output %p size %zd offset %zd. Wait SSF %d\n", -@@ -1442,9 +1442,9 @@ void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting) - * - * Returns the number of bytes read, which may be less than - * the requested 'datalen' if the socket would block. Returns -- * -1 on error, and disconnects the client socket. -+ * 0 on I/O error or EOF, and disconnects the client socket. - */ --ssize_t vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen) -+size_t vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen) - { - ssize_t ret; - Error *err = NULL; -@@ -1460,12 +1460,13 @@ ssize_t vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen) - * when not using any SASL SSF encryption layers. Will read as much - * data as possible without blocking. - * -- * Returns the number of bytes read. Returns -1 on error, and -- * disconnects the client socket. -+ * Returns the number of bytes read, which may be less than -+ * the requested 'datalen' if the socket would block. Returns -+ * 0 on I/O error or EOF, and disconnects the client socket. - */ --static ssize_t vnc_client_read_plain(VncState *vs) -+static size_t vnc_client_read_plain(VncState *vs) - { -- ssize_t ret; -+ size_t ret; - VNC_DEBUG("Read plain %p size %zd offset %zd\n", - vs->input.buffer, vs->input.capacity, vs->input.offset); - buffer_reserve(&vs->input, 4096); -@@ -1491,7 +1492,7 @@ static void vnc_jobs_bh(void *opaque) - */ - static int vnc_client_read(VncState *vs) - { -- ssize_t ret; -+ size_t ret; - - #ifdef CONFIG_VNC_SASL - if (vs->sasl.conn && vs->sasl.runSSF) -diff --git a/ui/vnc.h b/ui/vnc.h -index 3f4cd4d..0c33a5f 100644 ---- a/ui/vnc.h -+++ b/ui/vnc.h -@@ -524,8 +524,8 @@ gboolean vnc_client_io(QIOChannel *ioc, - GIOCondition condition, - void *opaque); - --ssize_t vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen); --ssize_t vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen); -+size_t vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen); -+size_t vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen); - - /* Protocol I/O functions */ - void vnc_write(VncState *vs, const void *data, size_t len); -@@ -544,7 +544,7 @@ uint32_t read_u32(uint8_t *data, size_t offset); - - /* Protocol stage functions */ - void vnc_client_error(VncState *vs); --ssize_t vnc_client_io_error(VncState *vs, ssize_t ret, Error **errp); -+size_t vnc_client_io_error(VncState *vs, ssize_t ret, Error **errp); - - void start_client_init(VncState *vs); - void start_auth_vnc(VncState *vs); --- -1.8.3.1 - diff --git a/SOURCES/kvm-ui-place-a-hard-cap-on-VNC-server-output-buffer-size.patch b/SOURCES/kvm-ui-place-a-hard-cap-on-VNC-server-output-buffer-size.patch deleted file mode 100644 index be78da0..0000000 --- a/SOURCES/kvm-ui-place-a-hard-cap-on-VNC-server-output-buffer-size.patch +++ /dev/null @@ -1,105 +0,0 @@ -From e3dbec9458073f71290e226ede55734ac4fe7e5d Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Mon, 5 Feb 2018 11:10:08 +0100 -Subject: [PATCH 14/20] ui: place a hard cap on VNC server output buffer size -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Daniel P. Berrange -Message-id: <20180205111012.6210-14-berrange@redhat.com> -Patchwork-id: 78890 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 13/17] ui: place a hard cap on VNC server output buffer size -Bugzilla: 1527404 -RH-Acked-by: Gerd Hoffmann -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Thomas Huth - -From: "Daniel P. Berrange" - -The previous patches fix problems with throttling of forced framebuffer updates -and audio data capture that would cause the QEMU output buffer size to grow -without bound. Those fixes are graceful in that once the client catches up with -reading data from the server, everything continues operating normally. - -There is some data which the server sends to the client that is impractical to -throttle. Specifically there are various pseudo framebuffer update encodings to -inform the client of things like desktop resizes, pointer changes, audio -playback start/stop, LED state and so on. These generally only involve sending -a very small amount of data to the client, but a malicious guest might be able -to do things that trigger these changes at a very high rate. Throttling them is -not practical as missed or delayed events would cause broken behaviour for the -client. - -This patch thus takes a more forceful approach of setting an absolute upper -bound on the amount of data we permit to be present in the output buffer at -any time. The previous patch set a threshold for throttling the output buffer -by allowing an amount of data equivalent to one complete framebuffer update and -one seconds worth of audio data. On top of this it allowed for one further -forced framebuffer update to be queued. - -To be conservative, we thus take that throttling threshold and multiply it by -5 to form an absolute upper bound. If this bound is hit during vnc_write() we -forceably disconnect the client, refusing to queue further data. This limit is -high enough that it should never be hit unless a malicious client is trying to -exploit the sever, or the network is completely saturated preventing any sending -of data on the socket. - -This completes the fix for CVE-2017-15124 started in the previous patches. - -Signed-off-by: Daniel P. Berrange -Reviewed-by: Darren Kenny -Reviewed-by: Marc-André Lureau -Message-id: 20171218191228.31018-12-berrange@redhat.com -Signed-off-by: Gerd Hoffmann -(cherry picked from commit f887cf165db20f405cb8805c716bd363aaadf815) -Signed-off-by: Miroslav Rezanina ---- - ui/vnc.c | 29 +++++++++++++++++++++++++++++ - 1 file changed, 29 insertions(+) - -diff --git a/ui/vnc.c b/ui/vnc.c -index 7f2210f..a7aff91 100644 ---- a/ui/vnc.c -+++ b/ui/vnc.c -@@ -1521,8 +1521,37 @@ gboolean vnc_client_io(QIOChannel *ioc G_GNUC_UNUSED, - } - - -+/* -+ * Scale factor to apply to vs->throttle_output_offset when checking for -+ * hard limit. Worst case normal usage could be x2, if we have a complete -+ * incremental update and complete forced update in the output buffer. -+ * So x3 should be good enough, but we pick x5 to be conservative and thus -+ * (hopefully) never trigger incorrectly. -+ */ -+#define VNC_THROTTLE_OUTPUT_LIMIT_SCALE 5 -+ - void vnc_write(VncState *vs, const void *data, size_t len) - { -+ if (vs->disconnecting) { -+ return; -+ } -+ /* Protection against malicious client/guest to prevent our output -+ * buffer growing without bound if client stops reading data. This -+ * should rarely trigger, because we have earlier throttling code -+ * which stops issuing framebuffer updates and drops audio data -+ * if the throttle_output_offset value is exceeded. So we only reach -+ * this higher level if a huge number of pseudo-encodings get -+ * triggered while data can't be sent on the socket. -+ * -+ * NB throttle_output_offset can be zero during early protocol -+ * handshake, or from the job thread's VncState clone -+ */ -+ if (vs->throttle_output_offset != 0 && -+ vs->output.offset > (vs->throttle_output_offset * -+ VNC_THROTTLE_OUTPUT_LIMIT_SCALE)) { -+ vnc_disconnect_start(vs); -+ return; -+ } - buffer_reserve(&vs->output, len); - - if (vs->ioc != NULL && buffer_empty(&vs->output)) { --- -1.8.3.1 - diff --git a/SOURCES/kvm-ui-refactor-code-for-determining-if-an-update-should.patch b/SOURCES/kvm-ui-refactor-code-for-determining-if-an-update-should.patch deleted file mode 100644 index 1500b9c..0000000 --- a/SOURCES/kvm-ui-refactor-code-for-determining-if-an-update-should.patch +++ /dev/null @@ -1,83 +0,0 @@ -From c13d50cb093c4409dd2db6023fc0f6adfe4927d8 Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Mon, 5 Feb 2018 11:10:05 +0100 -Subject: [PATCH 11/20] ui: refactor code for determining if an update should - be sent to the client -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Daniel P. Berrange -Message-id: <20180205111012.6210-11-berrange@redhat.com> -Patchwork-id: 78887 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 10/17] ui: refactor code for determining if an update should be sent to the client -Bugzilla: 1527404 -RH-Acked-by: Gerd Hoffmann -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Thomas Huth - -From: "Daniel P. Berrange" - -The logic for determining if it is possible to send an update to the client -will become more complicated shortly, so pull it out into a separate method -for easier extension later. - -Signed-off-by: Daniel P. Berrange -Reviewed-by: Darren Kenny -Reviewed-by: Marc-André Lureau -Message-id: 20171218191228.31018-9-berrange@redhat.com -Signed-off-by: Gerd Hoffmann -(cherry picked from commit 0bad834228b9ee63e4239108d02dcb94568254d0) -Signed-off-by: Miroslav Rezanina ---- - ui/vnc.c | 27 ++++++++++++++++++++------- - 1 file changed, 20 insertions(+), 7 deletions(-) - -diff --git a/ui/vnc.c b/ui/vnc.c -index 3707b87..2b04050 100644 ---- a/ui/vnc.c -+++ b/ui/vnc.c -@@ -961,6 +961,25 @@ static int find_and_clear_dirty_height(VncState *vs, - return h; - } - -+static bool vnc_should_update(VncState *vs) -+{ -+ switch (vs->update) { -+ case VNC_STATE_UPDATE_NONE: -+ break; -+ case VNC_STATE_UPDATE_INCREMENTAL: -+ /* Only allow incremental updates if the output buffer -+ * is empty, or if audio capture is enabled. -+ */ -+ if (!vs->output.offset || vs->audio_cap) { -+ return true; -+ } -+ break; -+ case VNC_STATE_UPDATE_FORCE: -+ return true; -+ } -+ return false; -+} -+ - static int vnc_update_client(VncState *vs, int has_dirty) - { - VncDisplay *vd = vs->vd; -@@ -975,13 +994,7 @@ static int vnc_update_client(VncState *vs, int has_dirty) - } - - vs->has_dirty += has_dirty; -- if (vs->update == VNC_STATE_UPDATE_NONE) { -- return 0; -- } -- -- if (vs->output.offset && !vs->audio_cap && -- vs->update != VNC_STATE_UPDATE_FORCE) { -- /* kernel send buffers are full -> drop frames to throttle */ -+ if (!vnc_should_update(vs)) { - return 0; - } - --- -1.8.3.1 - diff --git a/SOURCES/kvm-ui-remove-redundant-indentation-in-vnc_client_update.patch b/SOURCES/kvm-ui-remove-redundant-indentation-in-vnc_client_update.patch deleted file mode 100644 index aeb1123..0000000 --- a/SOURCES/kvm-ui-remove-redundant-indentation-in-vnc_client_update.patch +++ /dev/null @@ -1,172 +0,0 @@ -From aefded16955d95827bab7b8145388b6de872da38 Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Mon, 5 Feb 2018 11:10:00 +0100 -Subject: [PATCH 06/20] ui: remove redundant indentation in vnc_client_update -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Daniel P. Berrange -Message-id: <20180205111012.6210-6-berrange@redhat.com> -Patchwork-id: 78876 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 05/17] ui: remove redundant indentation in vnc_client_update -Bugzilla: 1527404 -RH-Acked-by: Gerd Hoffmann -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Thomas Huth - -From: "Daniel P. Berrange" - -Now that previous dead / unreachable code has been removed, we can simplify -the indentation in the vnc_client_update method. - -Signed-off-by: Daniel P. Berrange -Reviewed-by: Darren Kenny -Reviewed-by: Marc-André Lureau -Message-id: 20171218191228.31018-4-berrange@redhat.com -Signed-off-by: Gerd Hoffmann -(cherry picked from commit b939eb89b6f320544a9328fa908d881d0024c1ee) -Signed-off-by: Miroslav Rezanina ---- - ui/vnc.c | 112 ++++++++++++++++++++++++++++++++------------------------------- - 1 file changed, 57 insertions(+), 55 deletions(-) - -diff --git a/ui/vnc.c b/ui/vnc.c -index 1d2b3a8..2a2e47c 100644 ---- a/ui/vnc.c -+++ b/ui/vnc.c -@@ -963,74 +963,76 @@ static int find_and_clear_dirty_height(VncState *vs, - - static int vnc_update_client(VncState *vs, int has_dirty) - { -+ VncDisplay *vd = vs->vd; -+ VncJob *job; -+ int y; -+ int height, width; -+ int n = 0; -+ - if (vs->disconnecting) { - vnc_disconnect_finish(vs); - return 0; - } - - vs->has_dirty += has_dirty; -- if (vs->need_update) { -- VncDisplay *vd = vs->vd; -- VncJob *job; -- int y; -- int height, width; -- int n = 0; -- -- if (vs->output.offset && !vs->audio_cap && !vs->force_update) -- /* kernel send buffers are full -> drop frames to throttle */ -- return 0; -+ if (!vs->need_update) { -+ return 0; -+ } - -- if (!vs->has_dirty && !vs->audio_cap && !vs->force_update) -- return 0; -+ if (vs->output.offset && !vs->audio_cap && !vs->force_update) { -+ /* kernel send buffers are full -> drop frames to throttle */ -+ return 0; -+ } - -- /* -- * Send screen updates to the vnc client using the server -- * surface and server dirty map. guest surface updates -- * happening in parallel don't disturb us, the next pass will -- * send them to the client. -- */ -- job = vnc_job_new(vs); -- -- height = pixman_image_get_height(vd->server); -- width = pixman_image_get_width(vd->server); -- -- y = 0; -- for (;;) { -- int x, h; -- unsigned long x2; -- unsigned long offset = find_next_bit((unsigned long *) &vs->dirty, -- height * VNC_DIRTY_BPL(vs), -- y * VNC_DIRTY_BPL(vs)); -- if (offset == height * VNC_DIRTY_BPL(vs)) { -- /* no more dirty bits */ -+ if (!vs->has_dirty && !vs->audio_cap && !vs->force_update) { -+ return 0; -+ } -+ -+ /* -+ * Send screen updates to the vnc client using the server -+ * surface and server dirty map. guest surface updates -+ * happening in parallel don't disturb us, the next pass will -+ * send them to the client. -+ */ -+ job = vnc_job_new(vs); -+ -+ height = pixman_image_get_height(vd->server); -+ width = pixman_image_get_width(vd->server); -+ -+ y = 0; -+ for (;;) { -+ int x, h; -+ unsigned long x2; -+ unsigned long offset = find_next_bit((unsigned long *) &vs->dirty, -+ height * VNC_DIRTY_BPL(vs), -+ y * VNC_DIRTY_BPL(vs)); -+ if (offset == height * VNC_DIRTY_BPL(vs)) { -+ /* no more dirty bits */ -+ break; -+ } -+ y = offset / VNC_DIRTY_BPL(vs); -+ x = offset % VNC_DIRTY_BPL(vs); -+ x2 = find_next_zero_bit((unsigned long *) &vs->dirty[y], -+ VNC_DIRTY_BPL(vs), x); -+ bitmap_clear(vs->dirty[y], x, x2 - x); -+ h = find_and_clear_dirty_height(vs, y, x, x2, height); -+ x2 = MIN(x2, width / VNC_DIRTY_PIXELS_PER_BIT); -+ if (x2 > x) { -+ n += vnc_job_add_rect(job, x * VNC_DIRTY_PIXELS_PER_BIT, y, -+ (x2 - x) * VNC_DIRTY_PIXELS_PER_BIT, h); -+ } -+ if (!x && x2 == width / VNC_DIRTY_PIXELS_PER_BIT) { -+ y += h; -+ if (y == height) { - break; - } -- y = offset / VNC_DIRTY_BPL(vs); -- x = offset % VNC_DIRTY_BPL(vs); -- x2 = find_next_zero_bit((unsigned long *) &vs->dirty[y], -- VNC_DIRTY_BPL(vs), x); -- bitmap_clear(vs->dirty[y], x, x2 - x); -- h = find_and_clear_dirty_height(vs, y, x, x2, height); -- x2 = MIN(x2, width / VNC_DIRTY_PIXELS_PER_BIT); -- if (x2 > x) { -- n += vnc_job_add_rect(job, x * VNC_DIRTY_PIXELS_PER_BIT, y, -- (x2 - x) * VNC_DIRTY_PIXELS_PER_BIT, h); -- } -- if (!x && x2 == width / VNC_DIRTY_PIXELS_PER_BIT) { -- y += h; -- if (y == height) { -- break; -- } -- } - } -- -- vnc_job_push(job); -- vs->force_update = 0; -- vs->has_dirty = 0; -- return n; - } - -- return 0; -+ vnc_job_push(job); -+ vs->force_update = 0; -+ vs->has_dirty = 0; -+ return n; - } - - /* audio */ --- -1.8.3.1 - diff --git a/SOURCES/kvm-ui-remove-sync-parameter-from-vnc_update_client.patch b/SOURCES/kvm-ui-remove-sync-parameter-from-vnc_update_client.patch deleted file mode 100644 index 2f0e485..0000000 --- a/SOURCES/kvm-ui-remove-sync-parameter-from-vnc_update_client.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 5f140826bcb807ea47063b0b65d62b8ebc4a2c7f Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Mon, 5 Feb 2018 11:09:58 +0100 -Subject: [PATCH 04/20] ui: remove 'sync' parameter from vnc_update_client -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Daniel P. Berrange -Message-id: <20180205111012.6210-4-berrange@redhat.com> -Patchwork-id: 78878 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 03/17] ui: remove 'sync' parameter from vnc_update_client -Bugzilla: 1527404 -RH-Acked-by: Gerd Hoffmann -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Thomas Huth - -From: "Daniel P. Berrange" - -There is only one caller of vnc_update_client and that always passes false -for the 'sync' parameter. - -Signed-off-by: Daniel P. Berrange -Reviewed-by: Darren Kenny -Reviewed-by: Marc-André Lureau -Message-id: 20171218191228.31018-2-berrange@redhat.com -Signed-off-by: Gerd Hoffmann -(cherry picked from commit 6af998db05aec9af95a06f84ad94f1b96785e667) -Signed-off-by: Miroslav Rezanina ---- - ui/vnc.c | 11 +++-------- - 1 file changed, 3 insertions(+), 8 deletions(-) - -diff --git a/ui/vnc.c b/ui/vnc.c -index 1275bba..6ed738b 100644 ---- a/ui/vnc.c -+++ b/ui/vnc.c -@@ -596,7 +596,7 @@ VncInfo2List *qmp_query_vnc_servers(Error **errp) - 3) resolutions > 1024 - */ - --static int vnc_update_client(VncState *vs, int has_dirty, bool sync); -+static int vnc_update_client(VncState *vs, int has_dirty); - static void vnc_disconnect_start(VncState *vs); - - static void vnc_colordepth(VncState *vs); -@@ -961,7 +961,7 @@ static int find_and_clear_dirty_height(VncState *vs, - return h; - } - --static int vnc_update_client(VncState *vs, int has_dirty, bool sync) -+static int vnc_update_client(VncState *vs, int has_dirty) - { - if (vs->disconnecting) { - vnc_disconnect_finish(vs); -@@ -1025,9 +1025,6 @@ static int vnc_update_client(VncState *vs, int has_dirty, bool sync) - } - - vnc_job_push(job); -- if (sync) { -- vnc_jobs_join(vs); -- } - vs->force_update = 0; - vs->has_dirty = 0; - return n; -@@ -1035,8 +1032,6 @@ static int vnc_update_client(VncState *vs, int has_dirty, bool sync) - - if (vs->disconnecting) { - vnc_disconnect_finish(vs); -- } else if (sync) { -- vnc_jobs_join(vs); - } - - return 0; -@@ -2863,7 +2858,7 @@ static void vnc_refresh(DisplayChangeListener *dcl) - vnc_unlock_display(vd); - - QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) { -- rects += vnc_update_client(vs, has_dirty, false); -+ rects += vnc_update_client(vs, has_dirty); - /* vs might be free()ed here */ - } - --- -1.8.3.1 - diff --git a/SOURCES/kvm-ui-remove-unreachable-code-in-vnc_update_client.patch b/SOURCES/kvm-ui-remove-unreachable-code-in-vnc_update_client.patch deleted file mode 100644 index da5cdc0..0000000 --- a/SOURCES/kvm-ui-remove-unreachable-code-in-vnc_update_client.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 11a0ca31dff62ede8b272420cc527f8e4dd102a7 Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Mon, 5 Feb 2018 11:09:59 +0100 -Subject: [PATCH 05/20] ui: remove unreachable code in vnc_update_client -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Daniel P. Berrange -Message-id: <20180205111012.6210-5-berrange@redhat.com> -Patchwork-id: 78875 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 04/17] ui: remove unreachable code in vnc_update_client -Bugzilla: 1527404 -RH-Acked-by: Gerd Hoffmann -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Thomas Huth - -From: "Daniel P. Berrange" - -A previous commit: - - commit 5a8be0f73d6f60ff08746377eb09ca459f39deab - Author: Gerd Hoffmann - Date: Wed Jul 13 12:21:20 2016 +0200 - - vnc: make sure we finish disconnect - -Added a check for vs->disconnecting at the very start of the -vnc_update_client method. This means that the very next "if" -statement check for !vs->disconnecting always evaluates true, -and is thus redundant. This in turn means the vs->disconnecting -check at the very end of the method never evaluates true, and -is thus unreachable code. - -Signed-off-by: Daniel P. Berrange -Reviewed-by: Darren Kenny -Reviewed-by: Marc-André Lureau -Message-id: 20171218191228.31018-3-berrange@redhat.com -Signed-off-by: Gerd Hoffmann -(cherry picked from commit c53df961617736f94731d94b62c2954c261d2bae) -Signed-off-by: Miroslav Rezanina ---- - ui/vnc.c | 6 +----- - 1 file changed, 1 insertion(+), 5 deletions(-) - -diff --git a/ui/vnc.c b/ui/vnc.c -index 6ed738b..1d2b3a8 100644 ---- a/ui/vnc.c -+++ b/ui/vnc.c -@@ -969,7 +969,7 @@ static int vnc_update_client(VncState *vs, int has_dirty) - } - - vs->has_dirty += has_dirty; -- if (vs->need_update && !vs->disconnecting) { -+ if (vs->need_update) { - VncDisplay *vd = vs->vd; - VncJob *job; - int y; -@@ -1030,10 +1030,6 @@ static int vnc_update_client(VncState *vs, int has_dirty) - return n; - } - -- if (vs->disconnecting) { -- vnc_disconnect_finish(vs); -- } -- - return 0; - } - --- -1.8.3.1 - diff --git a/SOURCES/kvm-ui-track-how-much-decoded-data-we-consumed-when-doin.patch b/SOURCES/kvm-ui-track-how-much-decoded-data-we-consumed-when-doin.patch deleted file mode 100644 index f7242d2..0000000 --- a/SOURCES/kvm-ui-track-how-much-decoded-data-we-consumed-when-doin.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 61e62d3b4e8d0eb3715cbffcec580d5d236421a0 Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Mon, 5 Feb 2018 11:10:02 +0100 -Subject: [PATCH 08/20] ui: track how much decoded data we consumed when doing - SASL encoding -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Daniel P. Berrange -Message-id: <20180205111012.6210-8-berrange@redhat.com> -Patchwork-id: 78877 -O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 07/17] ui: track how much decoded data we consumed when doing SASL encoding -Bugzilla: 1527404 -RH-Acked-by: Gerd Hoffmann -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Thomas Huth - -From: "Daniel P. Berrange" - -When we encode data for writing with SASL, we encode the entire pending output -buffer. The subsequent write, however, may not be able to send the full encoded -data in one go though, particularly with a slow network. So we delay setting the -output buffer offset back to zero until all the SASL encoded data is sent. - -Between encoding the data and completing sending of the SASL encoded data, -however, more data might have been placed on the pending output buffer. So it -is not valid to set offset back to zero. Instead we must keep track of how much -data we consumed during encoding and subtract only that amount. - -With the current bug we would be throwing away some pending data without having -sent it at all. By sheer luck this did not previously cause any serious problem -because appending data to the send buffer is always an atomic action, so we -only ever throw away complete RFB protocol messages. In the case of frame buffer -updates we'd catch up fairly quickly, so no obvious problem was visible. - -Signed-off-by: Daniel P. Berrange -Reviewed-by: Darren Kenny -Reviewed-by: Marc-André Lureau -Message-id: 20171218191228.31018-6-berrange@redhat.com -Signed-off-by: Gerd Hoffmann -(cherry picked from commit 8f61f1c5a6bc06438a1172efa80bc7606594fa07) -Signed-off-by: Miroslav Rezanina ---- - ui/vnc-auth-sasl.c | 3 ++- - ui/vnc-auth-sasl.h | 1 + - 2 files changed, 3 insertions(+), 1 deletion(-) - -diff --git a/ui/vnc-auth-sasl.c b/ui/vnc-auth-sasl.c -index 23f2828..761493b 100644 ---- a/ui/vnc-auth-sasl.c -+++ b/ui/vnc-auth-sasl.c -@@ -67,6 +67,7 @@ long vnc_client_write_sasl(VncState *vs) - if (err != SASL_OK) - return vnc_client_io_error(vs, -1, NULL); - -+ vs->sasl.encodedRawLength = vs->output.offset; - vs->sasl.encodedOffset = 0; - } - -@@ -78,7 +79,7 @@ long vnc_client_write_sasl(VncState *vs) - - vs->sasl.encodedOffset += ret; - if (vs->sasl.encodedOffset == vs->sasl.encodedLength) { -- vs->output.offset = 0; -+ vs->output.offset -= vs->sasl.encodedRawLength; - vs->sasl.encoded = NULL; - vs->sasl.encodedOffset = vs->sasl.encodedLength = 0; - } -diff --git a/ui/vnc-auth-sasl.h b/ui/vnc-auth-sasl.h -index cb42745..b9d8de1 100644 ---- a/ui/vnc-auth-sasl.h -+++ b/ui/vnc-auth-sasl.h -@@ -53,6 +53,7 @@ struct VncStateSASL { - */ - const uint8_t *encoded; - unsigned int encodedLength; -+ unsigned int encodedRawLength; - unsigned int encodedOffset; - char *username; - char *mechlist; --- -1.8.3.1 - diff --git a/SOURCES/kvm-usb-drop-HOST_USB.patch b/SOURCES/kvm-usb-drop-HOST_USB.patch deleted file mode 100644 index 476a2b1..0000000 --- a/SOURCES/kvm-usb-drop-HOST_USB.patch +++ /dev/null @@ -1,73 +0,0 @@ -From ca6e32bce33eab1000eba5629e28832430896cbd Mon Sep 17 00:00:00 2001 -From: Thomas Huth -Date: Mon, 9 Oct 2017 12:32:37 +0200 -Subject: [PATCH 18/34] usb: drop HOST_USB - -RH-Author: Thomas Huth -Message-id: <1507552368-9245-2-git-send-email-thuth@redhat.com> -Patchwork-id: 77016 -O-Subject: [RHEL-7.5 qemu-kvm-ma PATCH 01/12] usb: drop HOST_USB -Bugzilla: 1492033 -RH-Acked-by: Cornelia Huck -RH-Acked-by: David Gibson -RH-Acked-by: Miroslav Rezanina - -From: Gerd Hoffmann - -Nowdays we use libusb for usb-host, so we don't have different code -for linux vs. bsd any more. So there is little reason to have the -HOST_USB variable, we can just write things directly into the Makefile -and avoid a pointless indirection. - -Signed-off-by: Gerd Hoffmann -Reviewed-by: Fam Zheng -Reviewed-by: Thomas Huth -Message-id: 20170908111217.21985-2-kraxel@redhat.com -(cherry picked from commit 4e5ee5b21c84fe3023a64b5cc2e12a52ab0597c1) -Signed-off-by: Miroslav Rezanina - -Conflicts: - configure (simple conflict in the context of the removed hunk) ---- - configure | 7 ------- - hw/usb/Makefile.objs | 6 +++++- - 2 files changed, 5 insertions(+), 8 deletions(-) - -diff --git a/configure b/configure -index 5cb65d0..457b2ff 100755 ---- a/configure -+++ b/configure -@@ -5968,13 +5968,6 @@ if test "$live_block_ops" = "yes" ; then - echo "CONFIG_LIVE_BLOCK_OPS=y" >> $config_host_mak - fi - --# USB host support --if test "$libusb" = "yes"; then -- echo "HOST_USB=libusb legacy" >> $config_host_mak --else -- echo "HOST_USB=stub" >> $config_host_mak --fi -- - # TPM passthrough support? - if test "$tpm" = "yes"; then - echo 'CONFIG_TPM=$(CONFIG_SOFTMMU)' >> $config_host_mak -diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs -index 97f1c456..a43ebbc 100644 ---- a/hw/usb/Makefile.objs -+++ b/hw/usb/Makefile.objs -@@ -38,7 +38,11 @@ endif - common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o - - # usb pass-through --common-obj-y += $(patsubst %,host-%.o,$(HOST_USB)) -+ifeq ($(CONFIG_LIBUSB),y) -+common-obj-y += host-libusb.o host-legacy.o -+else -+common-obj-y += host-stub.o -+endif - - ifeq ($(CONFIG_USB_LIBUSB),y) - common-obj-$(CONFIG_XEN) += xen-usb.o --- -1.8.3.1 - diff --git a/SOURCES/kvm-usb-fix-host-stub.c-build-race.patch b/SOURCES/kvm-usb-fix-host-stub.c-build-race.patch deleted file mode 100644 index b7a3f34..0000000 --- a/SOURCES/kvm-usb-fix-host-stub.c-build-race.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 08426497468ec35d4dadd65df19abc5cfa6cd436 Mon Sep 17 00:00:00 2001 -From: Thomas Huth -Date: Mon, 9 Oct 2017 12:32:40 +0200 -Subject: [PATCH 21/34] usb: fix host-stub.c build race - -RH-Author: Thomas Huth -Message-id: <1507552368-9245-5-git-send-email-thuth@redhat.com> -Patchwork-id: 77021 -O-Subject: [RHEL-7.5 qemu-kvm-ma PATCH 04/12] usb: fix host-stub.c build race -Bugzilla: 1492033 -RH-Acked-by: Cornelia Huck -RH-Acked-by: David Gibson -RH-Acked-by: Miroslav Rezanina - -From: Gerd Hoffmann - -Suggested-by: Thomas Huth -Signed-off-by: Gerd Hoffmann -Reviewed-by: Thomas Huth -Message-id: 20171004125210.7817-1-kraxel@redhat.com -(cherry picked from commit eea6ae20379dca837631d603c3bed03e5128189f) -Signed-off-by: Miroslav Rezanina ---- - hw/usb/Makefile.objs | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs -index 01c18cf..53c4765 100644 ---- a/hw/usb/Makefile.objs -+++ b/hw/usb/Makefile.objs -@@ -43,6 +43,7 @@ common-obj-y += host-libusb.o host-legacy.o - else - common-obj-y += host-stub.o - endif -+common-obj-$(CONFIG_ALL) += host-stub.o - - ifeq ($(CONFIG_USB_LIBUSB),y) - common-obj-$(CONFIG_XEN) += xen-usb.o --- -1.8.3.1 - diff --git a/SOURCES/kvm-usb-fix-libusb-config-variable-name.patch b/SOURCES/kvm-usb-fix-libusb-config-variable-name.patch deleted file mode 100644 index b227410..0000000 --- a/SOURCES/kvm-usb-fix-libusb-config-variable-name.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 6c6a4d0d8f5d83ee57b83a85889426389141498c Mon Sep 17 00:00:00 2001 -From: Thomas Huth -Date: Mon, 9 Oct 2017 12:32:39 +0200 -Subject: [PATCH 20/34] usb: fix libusb config variable name. - -RH-Author: Thomas Huth -Message-id: <1507552368-9245-4-git-send-email-thuth@redhat.com> -Patchwork-id: 77023 -O-Subject: [RHEL-7.5 qemu-kvm-ma PATCH 03/12] usb: fix libusb config variable name. -Bugzilla: 1492033 -RH-Acked-by: Cornelia Huck -RH-Acked-by: David Gibson -RH-Acked-by: Miroslav Rezanina - -From: Gerd Hoffmann - -Cc: Jan Kiszka -Fixes: 4e5ee5b21c84fe3023a64b5cc2e12a52ab0597c1 -Signed-off-by: Gerd Hoffmann -Tested-by: Jan Kiszka -Message-id: 20170926063820.30773-1-kraxel@redhat.com -(cherry picked from commit 275d477a1adb084a47859507b20b05e7d65f8e8d) -Signed-off-by: Miroslav Rezanina ---- - hw/usb/Makefile.objs | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs -index 757e365..01c18cf 100644 ---- a/hw/usb/Makefile.objs -+++ b/hw/usb/Makefile.objs -@@ -38,7 +38,7 @@ endif - common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o - - # usb pass-through --ifeq ($(CONFIG_LIBUSB)$(CONFIG_USB),yy) -+ifeq ($(CONFIG_USB_LIBUSB)$(CONFIG_USB),yy) - common-obj-y += host-libusb.o host-legacy.o - else - common-obj-y += host-stub.o --- -1.8.3.1 - diff --git a/SOURCES/kvm-usb-hcd-xhci-test-add-a-test-for-ccid-hotplug.patch b/SOURCES/kvm-usb-hcd-xhci-test-add-a-test-for-ccid-hotplug.patch new file mode 100644 index 0000000..9748f93 --- /dev/null +++ b/SOURCES/kvm-usb-hcd-xhci-test-add-a-test-for-ccid-hotplug.patch @@ -0,0 +1,66 @@ +From 175943dc22bc1ff3622fd5132656375f22306f27 Mon Sep 17 00:00:00 2001 +From: Serhii Popovych +Date: Mon, 9 Jul 2018 11:31:17 +0200 +Subject: [PATCH 27/89] usb-hcd-xhci-test: add a test for ccid hotplug +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Serhii Popovych +Message-id: <1531135878-18813-3-git-send-email-spopovyc@redhat.com> +Patchwork-id: 81267 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v2 2/3] usb-hcd-xhci-test: add a test for ccid hotplug +Bugzilla: 1556678 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Marc-André Lureau +RH-Acked-by: David Gibson + +From: Marc-André Lureau + +Signed-off-by: Marc-André Lureau +Message-id: 20180531195119.22021-5-marcandre.lureau@redhat.com +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 1a3ff20e67330a15d62b00c2916e3541872103c0) +Signed-off-by: Serhii Popovych +Signed-off-by: Miroslav Rezanina + +Conflicts: + tests/usb-hcd-xhci-test.c + +Due to disabled UAS that adds if/endif and comment line. +--- + tests/usb-hcd-xhci-test.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/tests/usb-hcd-xhci-test.c b/tests/usb-hcd-xhci-test.c +index 192b7f7..8c3fb36 100644 +--- a/tests/usb-hcd-xhci-test.c ++++ b/tests/usb-hcd-xhci-test.c +@@ -37,6 +37,15 @@ static void test_usb_uas_hotplug(void) + } + #endif + ++static void test_usb_ccid_hotplug(void) ++{ ++ qtest_qmp_device_add("usb-ccid", "ccid", NULL); ++ qtest_qmp_device_del("ccid"); ++ /* check the device can be added again */ ++ qtest_qmp_device_add("usb-ccid", "ccid", NULL); ++ qtest_qmp_device_del("ccid"); ++} ++ + int main(int argc, char **argv) + { + int ret; +@@ -48,6 +57,8 @@ int main(int argc, char **argv) + #if 0 /* Disabled for Red Hat Enterprise Linux 7 */ + qtest_add_func("/xhci/pci/hotplug/usb-uas", test_usb_uas_hotplug); + #endif ++ qtest_add_func("/xhci/pci/hotplug/usb-ccid", test_usb_ccid_hotplug); ++ + qtest_start("-device nec-usb-xhci,id=xhci" + " -drive id=drive0,if=none,file=null-co://,format=raw"); + ret = g_test_run(); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-usb-host-skip-open-on-pending-postload-bh.patch b/SOURCES/kvm-usb-host-skip-open-on-pending-postload-bh.patch new file mode 100644 index 0000000..318dcd7 --- /dev/null +++ b/SOURCES/kvm-usb-host-skip-open-on-pending-postload-bh.patch @@ -0,0 +1,78 @@ +From 05af6159ba18882c0bdef512abd3c852b515430b Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 13 Jun 2018 14:07:30 +0200 +Subject: [PATCH 03/57] usb-host: skip open on pending postload bh + +RH-Author: Gerd Hoffmann +Message-id: <20180613140730.16401-2-kraxel@redhat.com> +Patchwork-id: 80667 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/1] usb-host: skip open on pending postload bh +Bugzilla: 1572851 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Laurent Vivier + +usb-host emulates a device unplug after live migration, because the +device state is unknown and unplug/replug makes sure the guest +re-initializes the device into a working state. This can't be done in +post-load though, so post-load just schedules a bottom half which +executes after vmload is complete. + +It can happen that the device autoscan timer hits the race window +between scheduling and running the bottom half, which in turn can +triggers an assert(). + +Fix that issue by just ignoring the usb_host_open() call in case the +bottom half didn't execute yet. + +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1572851 +Signed-off-by: Gerd Hoffmann +Message-id: 20180503062932.17233-1-kraxel@redhat.com +(cherry picked from commit 3280ea8edede3814553aa19fa27a58daedd48ad9) +Signed-off-by: Miroslav Rezanina +--- + hw/usb/host-libusb.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c +index 1b0be07..0290fb8 100644 +--- a/hw/usb/host-libusb.c ++++ b/hw/usb/host-libusb.c +@@ -102,6 +102,7 @@ struct USBHostDevice { + /* callbacks & friends */ + QEMUBH *bh_nodev; + QEMUBH *bh_postld; ++ bool bh_postld_pending; + Notifier exit; + + /* request queues */ +@@ -866,6 +867,10 @@ static int usb_host_open(USBHostDevice *s, libusb_device *dev) + int rc; + Error *local_err = NULL; + ++ if (s->bh_postld_pending) { ++ return -1; ++ } ++ + trace_usb_host_open_started(bus_num, addr); + + if (s->dh != NULL) { +@@ -1524,6 +1529,7 @@ static void usb_host_post_load_bh(void *opaque) + if (udev->attached) { + usb_device_detach(udev); + } ++ dev->bh_postld_pending = false; + usb_host_auto_check(NULL); + } + +@@ -1535,6 +1541,7 @@ static int usb_host_post_load(void *opaque, int version_id) + dev->bh_postld = qemu_bh_new(usb_host_post_load_bh, dev); + } + qemu_bh_schedule(dev->bh_postld); ++ dev->bh_postld_pending = true; + return 0; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-usb-only-build-usb-host-with-CONFIG_USB-y.patch b/SOURCES/kvm-usb-only-build-usb-host-with-CONFIG_USB-y.patch deleted file mode 100644 index b7a6065..0000000 --- a/SOURCES/kvm-usb-only-build-usb-host-with-CONFIG_USB-y.patch +++ /dev/null @@ -1,43 +0,0 @@ -From fb5cc24e24e0b53f0679e911c959a060c945bdff Mon Sep 17 00:00:00 2001 -From: Thomas Huth -Date: Mon, 9 Oct 2017 12:32:38 +0200 -Subject: [PATCH 19/34] usb: only build usb-host with CONFIG_USB=y - -RH-Author: Thomas Huth -Message-id: <1507552368-9245-3-git-send-email-thuth@redhat.com> -Patchwork-id: 77019 -O-Subject: [RHEL-7.5 qemu-kvm-ma PATCH 02/12] usb: only build usb-host with CONFIG_USB=y -Bugzilla: 1492033 -RH-Acked-by: Cornelia Huck -RH-Acked-by: David Gibson -RH-Acked-by: Miroslav Rezanina - -From: Gerd Hoffmann - -Signed-off-by: Gerd Hoffmann -Reviewed-by: Fam Zheng -Reviewed-by: Thomas Huth -Tested-by: Thomas Huth -Message-id: 20170908111217.21985-3-kraxel@redhat.com -(cherry picked from commit 2041649f0b04f61869589571ddf5ecd4f0695ea2) -Signed-off-by: Miroslav Rezanina ---- - hw/usb/Makefile.objs | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs -index a43ebbc..757e365 100644 ---- a/hw/usb/Makefile.objs -+++ b/hw/usb/Makefile.objs -@@ -38,7 +38,7 @@ endif - common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o - - # usb pass-through --ifeq ($(CONFIG_LIBUSB),y) -+ifeq ($(CONFIG_LIBUSB)$(CONFIG_USB),yy) - common-obj-y += host-libusb.o host-legacy.o - else - common-obj-y += host-stub.o --- -1.8.3.1 - diff --git a/SOURCES/kvm-usb-storage-Add-rerror-werror-properties.patch b/SOURCES/kvm-usb-storage-Add-rerror-werror-properties.patch new file mode 100644 index 0000000..30b26da --- /dev/null +++ b/SOURCES/kvm-usb-storage-Add-rerror-werror-properties.patch @@ -0,0 +1,104 @@ +From 222934faee20b22e77f711d6bc5d986c2e1fd297 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Mon, 2 Jul 2018 12:20:17 +0200 +Subject: [PATCH 51/57] usb-storage: Add rerror/werror properties + +RH-Author: Kevin Wolf +Message-id: <20180702122017.29664-2-kwolf@redhat.com> +Patchwork-id: 81183 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 1/1] usb-storage: Add rerror/werror properties +Bugzilla: 1595180 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Max Reitz +RH-Acked-by: John Snow + +The error handling policy was traditionally set with -drive, but with +-blockdev it is no longer possible to set frontend options. scsi-disk +(and other block devices) have long supported qdev properties to +configure the error handling policy, so let's add these options to +usb-storage as well and just forward them to the internal scsi-disk +instance. + +Signed-off-by: Kevin Wolf +Reviewed-by: Markus Armbruster +(cherry picked from commit b8efb36b9e99dbea7370139c0866b97a933f78d4) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + hw/scsi/scsi-bus.c | 11 ++++++++++- + hw/usb/dev-storage.c | 2 ++ + include/hw/scsi/scsi.h | 2 ++ + 3 files changed, 14 insertions(+), 1 deletion(-) + +diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c +index 9646743..5905f6b 100644 +--- a/hw/scsi/scsi-bus.c ++++ b/hw/scsi/scsi-bus.c +@@ -226,6 +226,8 @@ static void scsi_qdev_unrealize(DeviceState *qdev, Error **errp) + SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk, + int unit, bool removable, int bootindex, + bool share_rw, ++ BlockdevOnError rerror, ++ BlockdevOnError werror, + const char *serial, Error **errp) + { + const char *driver; +@@ -262,6 +264,10 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk, + object_unparent(OBJECT(dev)); + return NULL; + } ++ ++ qdev_prop_set_enum(dev, "rerror", rerror); ++ qdev_prop_set_enum(dev, "werror", werror); ++ + object_property_set_bool(OBJECT(dev), true, "realized", &err); + if (err != NULL) { + error_propagate(errp, err); +@@ -285,7 +291,10 @@ void scsi_bus_legacy_handle_cmdline(SCSIBus *bus) + } + qemu_opts_loc_restore(dinfo->opts); + scsi_bus_legacy_add_drive(bus, blk_by_legacy_dinfo(dinfo), +- unit, false, -1, false, NULL, &error_fatal); ++ unit, false, -1, false, ++ BLOCKDEV_ON_ERROR_AUTO, ++ BLOCKDEV_ON_ERROR_AUTO, ++ NULL, &error_fatal); + } + loc_pop(&loc); + } +diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c +index b56c75a..68e2062 100644 +--- a/hw/usb/dev-storage.c ++++ b/hw/usb/dev-storage.c +@@ -634,6 +634,7 @@ static void usb_msd_storage_realize(USBDevice *dev, Error **errp) + &usb_msd_scsi_info_storage, NULL); + scsi_dev = scsi_bus_legacy_add_drive(&s->bus, blk, 0, !!s->removable, + s->conf.bootindex, s->conf.share_rw, ++ s->conf.rerror, s->conf.werror, + dev->serial, + errp); + blk_unref(blk); +@@ -687,6 +688,7 @@ static const VMStateDescription vmstate_usb_msd = { + + static Property msd_properties[] = { + DEFINE_BLOCK_PROPERTIES(MSDState, conf), ++ DEFINE_BLOCK_ERROR_PROPERTIES(MSDState, conf), + DEFINE_PROP_BIT("removable", MSDState, removable, 0, false), + DEFINE_PROP_END_OF_LIST(), + }; +diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h +index e35137e..1a7290d 100644 +--- a/include/hw/scsi/scsi.h ++++ b/include/hw/scsi/scsi.h +@@ -154,6 +154,8 @@ static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d) + SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk, + int unit, bool removable, int bootindex, + bool share_rw, ++ BlockdevOnError rerror, ++ BlockdevOnError werror, + const char *serial, Error **errp); + void scsi_bus_legacy_handle_cmdline(SCSIBus *bus); + void scsi_legacy_handle_cmdline(void); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-usb-storage-Fix-share-rw-option-parsing.patch b/SOURCES/kvm-usb-storage-Fix-share-rw-option-parsing.patch deleted file mode 100644 index 188a2ea..0000000 --- a/SOURCES/kvm-usb-storage-Fix-share-rw-option-parsing.patch +++ /dev/null @@ -1,102 +0,0 @@ -From b2e6b34cedd32864edaa28dd7b7f8a8bf9578569 Mon Sep 17 00:00:00 2001 -From: Fam Zheng -Date: Mon, 29 Jan 2018 05:38:19 +0100 -Subject: [PATCH 7/8] usb-storage: Fix share-rw option parsing - -RH-Author: Fam Zheng -Message-id: <20180129053819.14507-1-famz@redhat.com> -Patchwork-id: 78734 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH] usb-storage: Fix share-rw option parsing -Bugzilla: 1525324 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: John Snow -RH-Acked-by: Jeffrey Cody - -Because usb-storage creates an internal scsi device, we should propagate -options. We already do so for bootindex etc, but failed to take care of -share-rw. Fix it in an apparent way: add a new parameter to -scsi_bus_legacy_add_drive and pass in s->conf.share_rw. - -Cc: qemu-stable@nongnu.org -Signed-off-by: Fam Zheng -Reviewed-by: Darren Kenny -Message-id: 20180117005222.4781-1-famz@redhat.com -Signed-off-by: Gerd Hoffmann -(cherry picked from commit 395b95395934785ca86baafd314d0c31b307d16d) -Signed-off-by: Fam Zheng -Signed-off-by: Miroslav Rezanina - -Conflicts: - hw/usb/dev-storage.c -Contextual conflict. Upstream has cleaned up err parameter in ceff3e1f0 -(hw/block: Use errp directly rather than local_err), which is an -unrelated code refactoring and has other dependencies. ---- - hw/scsi/scsi-bus.c | 9 ++++++++- - hw/usb/dev-storage.c | 3 ++- - include/hw/scsi/scsi.h | 1 + - 3 files changed, 11 insertions(+), 2 deletions(-) - -diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c -index 97c9525..26148aa 100644 ---- a/hw/scsi/scsi-bus.c -+++ b/hw/scsi/scsi-bus.c -@@ -224,6 +224,7 @@ static void scsi_qdev_unrealize(DeviceState *qdev, Error **errp) - /* handle legacy '-drive if=scsi,...' cmd line args */ - SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk, - int unit, bool removable, int bootindex, -+ bool share_rw, - const char *serial, Error **errp) - { - const char *driver; -@@ -254,6 +255,12 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk, - object_unparent(OBJECT(dev)); - return NULL; - } -+ object_property_set_bool(OBJECT(dev), share_rw, "share-rw", &err); -+ if (err != NULL) { -+ error_propagate(errp, err); -+ object_unparent(OBJECT(dev)); -+ return NULL; -+ } - object_property_set_bool(OBJECT(dev), true, "realized", &err); - if (err != NULL) { - error_propagate(errp, err); -@@ -292,7 +299,7 @@ void scsi_bus_legacy_handle_cmdline(SCSIBus *bus, bool deprecated) - #endif - } - scsi_bus_legacy_add_drive(bus, blk_by_legacy_dinfo(dinfo), -- unit, false, -1, NULL, &error_fatal); -+ unit, false, -1, false, NULL, &error_fatal); - } - loc_pop(&loc); - } -diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c -index 8a61ec9..ff18ad5 100644 ---- a/hw/usb/dev-storage.c -+++ b/hw/usb/dev-storage.c -@@ -635,7 +635,8 @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp) - scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev), - &usb_msd_scsi_info_storage, NULL); - scsi_dev = scsi_bus_legacy_add_drive(&s->bus, blk, 0, !!s->removable, -- s->conf.bootindex, dev->serial, -+ s->conf.bootindex, s->conf.share_rw, -+ dev->serial, - &err); - blk_unref(blk); - if (!scsi_dev) { -diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h -index 23a8ee6..802a647 100644 ---- a/include/hw/scsi/scsi.h -+++ b/include/hw/scsi/scsi.h -@@ -151,6 +151,7 @@ static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d) - - SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk, - int unit, bool removable, int bootindex, -+ bool share_rw, - const char *serial, Error **errp); - void scsi_bus_legacy_handle_cmdline(SCSIBus *bus, bool deprecated); - void scsi_legacy_handle_cmdline(void); --- -1.8.3.1 - diff --git a/SOURCES/kvm-util-async-use-atomic_mb_set-in-qemu_bh_cancel.patch b/SOURCES/kvm-util-async-use-atomic_mb_set-in-qemu_bh_cancel.patch deleted file mode 100644 index cbe5166..0000000 --- a/SOURCES/kvm-util-async-use-atomic_mb_set-in-qemu_bh_cancel.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 550b4bcc2758e8df86570bc1afb29de34a1694fe Mon Sep 17 00:00:00 2001 -From: Stefan Hajnoczi -Date: Mon, 13 Nov 2017 16:29:39 +0100 -Subject: [PATCH 03/30] util/async: use atomic_mb_set in qemu_bh_cancel - -RH-Author: Stefan Hajnoczi -Message-id: <20171113162939.5486-2-stefanha@redhat.com> -Patchwork-id: 77665 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 1/1] util/async: use atomic_mb_set in qemu_bh_cancel -Bugzilla: 1508886 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: John Snow -RH-Acked-by: Laurent Vivier - -From: Sergio Lopez - -Commit b7a745d added a qemu_bh_cancel call to the completion function -as an optimization to prevent it from unnecessarily rescheduling itself. - -This completion function is scheduled from worker_thread, after setting -the state of a ThreadPoolElement to THREAD_DONE. - -This was considered to be safe, as the completion function restarts the -loop just after the call to qemu_bh_cancel. But, as this loop lacks a HW -memory barrier, the read of req->state may actually happen _before_ the -call, seeing it still as THREAD_QUEUED, and ending the completion -function without having processed a pending TPE linked at pool->head: - - worker thread | I/O thread ------------------------------------------------------------------------- - | speculatively read req->state -req->state = THREAD_DONE; | -qemu_bh_schedule(p->completion_bh) | - bh->scheduled = 1; | - | qemu_bh_cancel(p->completion_bh) - | bh->scheduled = 0; - | if (req->state == THREAD_DONE) - | // sees THREAD_QUEUED - -The source of the misunderstanding was that qemu_bh_cancel is now being -used by the _consumer_ rather than the producer, and therefore now needs -to have acquire semantics just like e.g. aio_bh_poll. - -In some situations, if there are no other independent requests in the -same aio context that could eventually trigger the scheduling of the -completion function, the omitted TPE and all operations pending on it -will get stuck forever. - -[Added Sergio's updated wording about the HW memory barrier. ---Stefan] - -Signed-off-by: Sergio Lopez -Message-id: 20171108063447.2842-1-slp@redhat.com -Signed-off-by: Stefan Hajnoczi - -(cherry picked from commit ef6dada8b44e1e7c4bec5c1115903af9af415b50) - -Signed-off-by: Stefan Hajnoczi -Signed-off-by: Miroslav Rezanina ---- - util/async.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/util/async.c b/util/async.c -index 355af73..0e1bd87 100644 ---- a/util/async.c -+++ b/util/async.c -@@ -174,7 +174,7 @@ void qemu_bh_schedule(QEMUBH *bh) - */ - void qemu_bh_cancel(QEMUBH *bh) - { -- bh->scheduled = 0; -+ atomic_mb_set(&bh->scheduled, 0); - } - - /* This func is async.The bottom half will do the delete action at the finial --- -1.8.3.1 - diff --git a/SOURCES/kvm-util-async-use-qemu_aio_coroutine_enter-in-co_schedu.patch b/SOURCES/kvm-util-async-use-qemu_aio_coroutine_enter-in-co_schedu.patch new file mode 100644 index 0000000..0d689a6 --- /dev/null +++ b/SOURCES/kvm-util-async-use-qemu_aio_coroutine_enter-in-co_schedu.patch @@ -0,0 +1,77 @@ +From b700e58ee749512368c40a5f84b01c11d24903b9 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 14 Sep 2018 10:55:22 +0200 +Subject: [PATCH 31/49] util/async: use qemu_aio_coroutine_enter in + co_schedule_bh_cb + +RH-Author: Kevin Wolf +Message-id: <20180914105540.18077-25-kwolf@redhat.com> +Patchwork-id: 82176 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 24/42] util/async: use qemu_aio_coroutine_enter in co_schedule_bh_cb +Bugzilla: 1601212 +RH-Acked-by: John Snow +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +From: Sergio Lopez + +AIO Coroutines shouldn't by managed by an AioContext different than the +one assigned when they are created. aio_co_enter avoids entering a +coroutine from a different AioContext, calling aio_co_schedule instead. + +Scheduled coroutines are then entered by co_schedule_bh_cb using +qemu_coroutine_enter, which just calls qemu_aio_coroutine_enter with the +current AioContext obtained with qemu_get_current_aio_context. +Eventually, co->ctx will be set to the AioContext passed as an argument +to qemu_aio_coroutine_enter. + +This means that, if an IO Thread's AioConext is being processed by the +Main Thread (due to aio_poll being called with a BDS AioContext, as it +happens in AIO_WAIT_WHILE among other places), the AioContext from some +coroutines may be wrongly replaced with the one from the Main Thread. + +This is the root cause behind some crashes, mainly triggered by the +drain code at block/io.c. The most common are these abort and failed +assertion: + +util/async.c:aio_co_schedule +456 if (scheduled) { +457 fprintf(stderr, +458 "%s: Co-routine was already scheduled in '%s'\n", +459 __func__, scheduled); +460 abort(); +461 } + +util/qemu-coroutine-lock.c: +286 assert(mutex->holder == self); + +But it's also known to cause random errors at different locations, and +even SIGSEGV with broken coroutine backtraces. + +By using qemu_aio_coroutine_enter directly in co_schedule_bh_cb, we can +pass the correct AioContext as an argument, making sure co->ctx is not +wrongly altered. + +Signed-off-by: Sergio Lopez +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + util/async.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/util/async.c b/util/async.c +index 4dd9d95..5693191 100644 +--- a/util/async.c ++++ b/util/async.c +@@ -391,7 +391,7 @@ static void co_schedule_bh_cb(void *opaque) + + /* Protected by write barrier in qemu_aio_coroutine_enter */ + atomic_set(&co->scheduled, NULL); +- qemu_coroutine_enter(co); ++ qemu_aio_coroutine_enter(ctx, co); + aio_context_release(ctx); + } + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-util-implement-simple-iova-tree.patch b/SOURCES/kvm-util-implement-simple-iova-tree.patch new file mode 100644 index 0000000..2dac4a3 --- /dev/null +++ b/SOURCES/kvm-util-implement-simple-iova-tree.patch @@ -0,0 +1,322 @@ +From 87c2556917718a14f46ca4f9a4fc1095429866d7 Mon Sep 17 00:00:00 2001 +From: Peter Xu +Date: Mon, 3 Sep 2018 04:52:40 +0200 +Subject: [PATCH 25/29] util: implement simple iova tree + +RH-Author: Peter Xu +Message-id: <20180903045241.6456-9-peterx@redhat.com> +Patchwork-id: 82026 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 8/9] util: implement simple iova tree +Bugzilla: 1623859 +RH-Acked-by: Xiao Wang +RH-Acked-by: Auger Eric +RH-Acked-by: Michael S. Tsirkin + +Introduce a simplest iova tree implementation based on GTree. + +CC: QEMU Stable +Signed-off-by: Peter Xu +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit eecf5eedbdc0fc04f39abcf3afeedfbf21b25ca4) +Signed-off-by: Peter Xu +Signed-off-by: Miroslav Rezanina +--- + MAINTAINERS | 6 +++ + include/qemu/iova-tree.h | 134 +++++++++++++++++++++++++++++++++++++++++++++++ + util/Makefile.objs | 1 + + util/iova-tree.c | 114 ++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 255 insertions(+) + create mode 100644 include/qemu/iova-tree.h + create mode 100644 util/iova-tree.c + +diff --git a/MAINTAINERS b/MAINTAINERS +index 53d5216..1e32116 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -1787,6 +1787,12 @@ F: include/sysemu/replay.h + F: docs/replay.txt + F: stubs/replay.c + ++IOVA Tree ++M: Peter Xu ++S: Maintained ++F: include/qemu/iova-tree.h ++F: util/iova-tree.c ++ + Usermode Emulation + ------------------ + Overall +diff --git a/include/qemu/iova-tree.h b/include/qemu/iova-tree.h +new file mode 100644 +index 0000000..b061932 +--- /dev/null ++++ b/include/qemu/iova-tree.h +@@ -0,0 +1,134 @@ ++/* ++ * An very simplified iova tree implementation based on GTree. ++ * ++ * Copyright 2018 Red Hat, Inc. ++ * ++ * Authors: ++ * Peter Xu ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ */ ++#ifndef IOVA_TREE_H ++#define IOVA_TREE_H ++ ++/* ++ * Currently the iova tree will only allow to keep ranges ++ * information, and no extra user data is allowed for each element. A ++ * benefit is that we can merge adjacent ranges internally within the ++ * tree. It can save a lot of memory when the ranges are splitted but ++ * mostly continuous. ++ * ++ * Note that current implementation does not provide any thread ++ * protections. Callers of the iova tree should be responsible ++ * for the thread safety issue. ++ */ ++ ++#include "qemu/osdep.h" ++#include "exec/memory.h" ++#include "exec/hwaddr.h" ++ ++#define IOVA_OK (0) ++#define IOVA_ERR_INVALID (-1) /* Invalid parameters */ ++#define IOVA_ERR_OVERLAP (-2) /* IOVA range overlapped */ ++ ++typedef struct IOVATree IOVATree; ++typedef struct DMAMap { ++ hwaddr iova; ++ hwaddr translated_addr; ++ hwaddr size; /* Inclusive */ ++ IOMMUAccessFlags perm; ++} QEMU_PACKED DMAMap; ++typedef gboolean (*iova_tree_iterator)(DMAMap *map); ++ ++/** ++ * iova_tree_new: ++ * ++ * Create a new iova tree. ++ * ++ * Returns: the tree pointer when succeeded, or NULL if error. ++ */ ++IOVATree *iova_tree_new(void); ++ ++/** ++ * iova_tree_insert: ++ * ++ * @tree: the iova tree to insert ++ * @map: the mapping to insert ++ * ++ * Insert an iova range to the tree. If there is overlapped ++ * ranges, IOVA_ERR_OVERLAP will be returned. ++ * ++ * Return: 0 if succeeded, or <0 if error. ++ */ ++int iova_tree_insert(IOVATree *tree, DMAMap *map); ++ ++/** ++ * iova_tree_remove: ++ * ++ * @tree: the iova tree to remove range from ++ * @map: the map range to remove ++ * ++ * Remove mappings from the tree that are covered by the map range ++ * provided. The range does not need to be exactly what has inserted, ++ * all the mappings that are included in the provided range will be ++ * removed from the tree. Here map->translated_addr is meaningless. ++ * ++ * Return: 0 if succeeded, or <0 if error. ++ */ ++int iova_tree_remove(IOVATree *tree, DMAMap *map); ++ ++/** ++ * iova_tree_find: ++ * ++ * @tree: the iova tree to search from ++ * @map: the mapping to search ++ * ++ * Search for a mapping in the iova tree that overlaps with the ++ * mapping range specified. Only the first found mapping will be ++ * returned. ++ * ++ * Return: DMAMap pointer if found, or NULL if not found. Note that ++ * the returned DMAMap pointer is maintained internally. User should ++ * only read the content but never modify or free the content. Also, ++ * user is responsible to make sure the pointer is valid (say, no ++ * concurrent deletion in progress). ++ */ ++DMAMap *iova_tree_find(IOVATree *tree, DMAMap *map); ++ ++/** ++ * iova_tree_find_address: ++ * ++ * @tree: the iova tree to search from ++ * @iova: the iova address to find ++ * ++ * Similar to iova_tree_find(), but it tries to find mapping with ++ * range iova=iova & size=0. ++ * ++ * Return: same as iova_tree_find(). ++ */ ++DMAMap *iova_tree_find_address(IOVATree *tree, hwaddr iova); ++ ++/** ++ * iova_tree_foreach: ++ * ++ * @tree: the iova tree to iterate on ++ * @iterator: the interator for the mappings, return true to stop ++ * ++ * Iterate over the iova tree. ++ * ++ * Return: 1 if found any overlap, 0 if not, <0 if error. ++ */ ++void iova_tree_foreach(IOVATree *tree, iova_tree_iterator iterator); ++ ++/** ++ * iova_tree_destroy: ++ * ++ * @tree: the iova tree to destroy ++ * ++ * Destroy an existing iova tree. ++ * ++ * Return: None. ++ */ ++void iova_tree_destroy(IOVATree *tree); ++ ++#endif +diff --git a/util/Makefile.objs b/util/Makefile.objs +index 728c354..e1c3fed 100644 +--- a/util/Makefile.objs ++++ b/util/Makefile.objs +@@ -47,4 +47,5 @@ util-obj-y += qht.o + util-obj-y += range.o + util-obj-y += stats64.o + util-obj-y += systemd.o ++util-obj-y += iova-tree.o + util-obj-$(CONFIG_LINUX) += vfio-helpers.o +diff --git a/util/iova-tree.c b/util/iova-tree.c +new file mode 100644 +index 0000000..2d9cebf +--- /dev/null ++++ b/util/iova-tree.c +@@ -0,0 +1,114 @@ ++/* ++ * IOVA tree implementation based on GTree. ++ * ++ * Copyright 2018 Red Hat, Inc. ++ * ++ * Authors: ++ * Peter Xu ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ */ ++ ++#include ++#include "qemu/iova-tree.h" ++ ++struct IOVATree { ++ GTree *tree; ++}; ++ ++static int iova_tree_compare(gconstpointer a, gconstpointer b, gpointer data) ++{ ++ const DMAMap *m1 = a, *m2 = b; ++ ++ if (m1->iova > m2->iova + m2->size) { ++ return 1; ++ } ++ ++ if (m1->iova + m1->size < m2->iova) { ++ return -1; ++ } ++ ++ /* Overlapped */ ++ return 0; ++} ++ ++IOVATree *iova_tree_new(void) ++{ ++ IOVATree *iova_tree = g_new0(IOVATree, 1); ++ ++ /* We don't have values actually, no need to free */ ++ iova_tree->tree = g_tree_new_full(iova_tree_compare, NULL, g_free, NULL); ++ ++ return iova_tree; ++} ++ ++DMAMap *iova_tree_find(IOVATree *tree, DMAMap *map) ++{ ++ return g_tree_lookup(tree->tree, map); ++} ++ ++DMAMap *iova_tree_find_address(IOVATree *tree, hwaddr iova) ++{ ++ DMAMap map = { .iova = iova, .size = 0 }; ++ ++ return iova_tree_find(tree, &map); ++} ++ ++static inline void iova_tree_insert_internal(GTree *gtree, DMAMap *range) ++{ ++ /* Key and value are sharing the same range data */ ++ g_tree_insert(gtree, range, range); ++} ++ ++int iova_tree_insert(IOVATree *tree, DMAMap *map) ++{ ++ DMAMap *new; ++ ++ if (map->iova + map->size < map->iova || map->perm == IOMMU_NONE) { ++ return IOVA_ERR_INVALID; ++ } ++ ++ /* We don't allow to insert range that overlaps with existings */ ++ if (iova_tree_find(tree, map)) { ++ return IOVA_ERR_OVERLAP; ++ } ++ ++ new = g_new0(DMAMap, 1); ++ memcpy(new, map, sizeof(*new)); ++ iova_tree_insert_internal(tree->tree, new); ++ ++ return IOVA_OK; ++} ++ ++static gboolean iova_tree_traverse(gpointer key, gpointer value, ++ gpointer data) ++{ ++ iova_tree_iterator iterator = data; ++ DMAMap *map = key; ++ ++ g_assert(key == value); ++ ++ return iterator(map); ++} ++ ++void iova_tree_foreach(IOVATree *tree, iova_tree_iterator iterator) ++{ ++ g_tree_foreach(tree->tree, iova_tree_traverse, iterator); ++} ++ ++int iova_tree_remove(IOVATree *tree, DMAMap *map) ++{ ++ DMAMap *overlap; ++ ++ while ((overlap = iova_tree_find(tree, map))) { ++ g_tree_remove(tree->tree, overlap); ++ } ++ ++ return IOVA_OK; ++} ++ ++void iova_tree_destroy(IOVATree *tree) ++{ ++ g_tree_destroy(tree->tree); ++ g_free(tree); ++} +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vdi-Fix-vdi_co_do_create-return-value.patch b/SOURCES/kvm-vdi-Fix-vdi_co_do_create-return-value.patch new file mode 100644 index 0000000..4ea5742 --- /dev/null +++ b/SOURCES/kvm-vdi-Fix-vdi_co_do_create-return-value.patch @@ -0,0 +1,42 @@ +From e4a86a6c362d1c962c23241ebcbb090d71ea554f Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:37 +0200 +Subject: [PATCH 68/89] vdi: Fix vdi_co_do_create() return value + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-55-kwolf@redhat.com> +Patchwork-id: 81126 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 54/73] vdi: Fix vdi_co_do_create() return value +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +.bdrv_co_create() is supposed to return 0 on success, but vdi could +return a positive value instead. Fix this. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +Reviewed-by: Jeff Cody +(cherry picked from commit 53618dd83885cc551a3833e228cf714494602142) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/vdi.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/block/vdi.c b/block/vdi.c +index 41859a8..1d8ed67 100644 +--- a/block/vdi.c ++++ b/block/vdi.c +@@ -865,6 +865,7 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options, + } + } + ++ ret = 0; + exit: + blk_unref(blk); + bdrv_unref(bs_file); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vfio-Fix-vfio-kvm-group-registration.patch b/SOURCES/kvm-vfio-Fix-vfio-kvm-group-registration.patch deleted file mode 100644 index 3594ab0..0000000 --- a/SOURCES/kvm-vfio-Fix-vfio-kvm-group-registration.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 8c5380844c8f52663f497609cfb0a833e5f643e0 Mon Sep 17 00:00:00 2001 -From: Alex Williamson -Date: Thu, 14 Dec 2017 16:30:06 +0100 -Subject: [PATCH 6/6] vfio: Fix vfio-kvm group registration - -RH-Author: Alex Williamson -Message-id: <20171214162725.10938.41443.stgit@gimli.home> -Patchwork-id: 78402 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH] vfio: Fix vfio-kvm group registration -Bugzilla: 1520294 -RH-Acked-by: Auger Eric -RH-Acked-by: Peter Xu -RH-Acked-by: Miroslav Rezanina - -Commit 8c37faa475f3 ("vfio-pci, ppc64/spapr: Reorder group-to-container -attaching") moved registration of groups with the vfio-kvm device from -vfio_get_group() to vfio_connect_container(), but it missed the case -where a group is attached to an existing container and takes an early -exit. Perhaps this is a less common case on ppc64/spapr, but on x86 -(without viommu) all groups are connected to the same container and -thus only the first group gets registered with the vfio-kvm device. -This becomes a problem if we then hot-unplug the devices associated -with that first group and we end up with KVM being misinformed about -any vfio connections that might remain. Fix by including the call to -vfio_kvm_device_add_group() in this early exit path. - -Fixes: 8c37faa475f3 ("vfio-pci, ppc64/spapr: Reorder group-to-container attaching") -Cc: qemu-stable@nongnu.org # qemu-2.10+ -Reviewed-by: Alexey Kardashevskiy -Reviewed-by: Peter Xu -Tested-by: Peter Xu -Reviewed-by: Eric Auger -Tested-by: Eric Auger -Signed-off-by: Alex Williamson -(cherry picked from commit 2016986aedb6ea2839662eb5f60630f3e231bd1a) ---- - -Testing: hot unplug Intel 82576 PF which is not the first vfio-pci device -for the VM. Previous, libvirt log includes: - -Signed-off-by: Miroslav Rezanina ---- - hw/vfio/common.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/hw/vfio/common.c b/hw/vfio/common.c -index 7b2924c..7007878 100644 ---- a/hw/vfio/common.c -+++ b/hw/vfio/common.c -@@ -968,6 +968,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, - if (!ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &container->fd)) { - group->container = container; - QLIST_INSERT_HEAD(&container->group_list, group, container_next); -+ vfio_kvm_device_add_group(group); - return 0; - } - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-vfio-pci-Add-option-to-disable-GeForce-quirks.patch b/SOURCES/kvm-vfio-pci-Add-option-to-disable-GeForce-quirks.patch deleted file mode 100644 index a97bc21..0000000 --- a/SOURCES/kvm-vfio-pci-Add-option-to-disable-GeForce-quirks.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 7047cb9155990dec1ee27b2ce65445a13ef40f00 Mon Sep 17 00:00:00 2001 -From: Alex Williamson -Date: Tue, 13 Feb 2018 19:04:41 +0100 -Subject: [PATCH 14/15] vfio/pci: Add option to disable GeForce quirks - -RH-Author: Alex Williamson -Message-id: <20180213190441.27565.45691.stgit@gimli.home> -Patchwork-id: 78998 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH v2 1/2] vfio/pci: Add option to disable GeForce quirks -Bugzilla: 1508330 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Auger Eric -RH-Acked-by: Marcel Apfelbaum - -These quirks are necessary for GeForce, but not for Quadro/GRID/Tesla -assignment. Leaving them enabled is fully functional and provides the -most compatibility, but due to the unique NVIDIA MSI ACK behavior[1], -it also introduces latency in re-triggering the MSI interrupt. This -overhead is typically negligible, but has been shown to adversely -affect some (very) high interrupt rate applications. This adds the -vfio-pci device option "x-no-geforce-quirks=" which can be set to -"on" to disable this additional overhead. - -A follow-on optimization for GeForce might be to make use of an -ioeventfd to allow KVM to trigger an irqfd in the kernel vfio-pci -driver, avoiding the bounce through userspace to handle this device -write. - -[1] Background: the NVIDIA driver has been observed to issue a write -to the MMIO mirror of PCI config space in BAR0 in order to allow the -MSI interrupt for the device to retrigger. Older reports indicated a -write of 0xff to the (read-only) MSI capability ID register, while -more recently a write of 0x0 is observed at config space offset 0x704, -non-architected, extended config space of the device (BAR0 offset -0x88704). Virtualization of this range is only required for GeForce. - -Signed-off-by: Alex Williamson -(cherry picked from commit db32d0f43839627f54a1a7f8eee17baa770f52d2) -Signed-off-by: Miroslav Rezanina ---- - hw/vfio/pci-quirks.c | 9 ++++++--- - hw/vfio/pci.c | 2 ++ - hw/vfio/pci.h | 1 + - 3 files changed, 9 insertions(+), 3 deletions(-) - -diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c -index 4199771..e875cca 100644 ---- a/hw/vfio/pci-quirks.c -+++ b/hw/vfio/pci-quirks.c -@@ -541,7 +541,8 @@ static void vfio_vga_probe_nvidia_3d0_quirk(VFIOPCIDevice *vdev) - VFIOQuirk *quirk; - VFIONvidia3d0Quirk *data; - -- if (!vfio_pci_is(vdev, PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID) || -+ if (vdev->no_geforce_quirks || -+ !vfio_pci_is(vdev, PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID) || - !vdev->bars[1].region.size) { - return; - } -@@ -659,7 +660,8 @@ static void vfio_probe_nvidia_bar5_quirk(VFIOPCIDevice *vdev, int nr) - VFIONvidiaBAR5Quirk *bar5; - VFIOConfigWindowQuirk *window; - -- if (!vfio_pci_is(vdev, PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID) || -+ if (vdev->no_geforce_quirks || -+ !vfio_pci_is(vdev, PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID) || - !vdev->vga || nr != 5 || !vdev->bars[5].ioport) { - return; - } -@@ -753,7 +755,8 @@ static void vfio_probe_nvidia_bar0_quirk(VFIOPCIDevice *vdev, int nr) - VFIOQuirk *quirk; - VFIOConfigMirrorQuirk *mirror; - -- if (!vfio_pci_is(vdev, PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID) || -+ if (vdev->no_geforce_quirks || -+ !vfio_pci_is(vdev, PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID) || - !vfio_is_vga(vdev) || nr != 0) { - return; - } -diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c -index b3a2889..4cfb780 100644 ---- a/hw/vfio/pci.c -+++ b/hw/vfio/pci.c -@@ -2992,6 +2992,8 @@ static Property vfio_pci_dev_properties[] = { - DEFINE_PROP_BOOL("x-no-kvm-intx", VFIOPCIDevice, no_kvm_intx, false), - DEFINE_PROP_BOOL("x-no-kvm-msi", VFIOPCIDevice, no_kvm_msi, false), - DEFINE_PROP_BOOL("x-no-kvm-msix", VFIOPCIDevice, no_kvm_msix, false), -+ DEFINE_PROP_BOOL("x-no-geforce-quirks", VFIOPCIDevice, -+ no_geforce_quirks, false), - DEFINE_PROP_UINT32("x-pci-vendor-id", VFIOPCIDevice, vendor_id, PCI_ANY_ID), - DEFINE_PROP_UINT32("x-pci-device-id", VFIOPCIDevice, device_id, PCI_ANY_ID), - DEFINE_PROP_UINT32("x-pci-sub-vendor-id", VFIOPCIDevice, -diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h -index a8366bb..ed9172d 100644 ---- a/hw/vfio/pci.h -+++ b/hw/vfio/pci.h -@@ -143,6 +143,7 @@ typedef struct VFIOPCIDevice { - bool no_kvm_intx; - bool no_kvm_msi; - bool no_kvm_msix; -+ bool no_geforce_quirks; - } VFIOPCIDevice; - - uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len); --- -1.8.3.1 - diff --git a/SOURCES/kvm-vfio-pci-Default-display-option-to-off.patch b/SOURCES/kvm-vfio-pci-Default-display-option-to-off.patch new file mode 100644 index 0000000..e0392cb --- /dev/null +++ b/SOURCES/kvm-vfio-pci-Default-display-option-to-off.patch @@ -0,0 +1,46 @@ +From a58a90bf5d832135b8e36fdeafed35a92abe79bd Mon Sep 17 00:00:00 2001 +From: Alex Williamson +Date: Tue, 12 Jun 2018 14:51:43 +0200 +Subject: [PATCH 01/57] vfio/pci: Default display option to "off" + +RH-Author: Alex Williamson +Message-id: <20180612145121.14019.7760.stgit@gimli.home> +Patchwork-id: 80641 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH] vfio/pci: Default display option to "off" +Bugzilla: 1583050 +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Laurent Vivier + +Commit a9994687cb9b ("vfio/display: core & wireup") added display +support to vfio-pci with the default being "auto", which breaks +existing VMs when the vGPU requires GL support but had no previous +requirement for a GL compatible configuration. "Off" is the safer +default as we impose no new requirements to VM configurations. + +Fixes: a9994687cb9b ("vfio/display: core & wireup") +Cc: qemu-stable@nongnu.org +Cc: Gerd Hoffmann +Signed-off-by: Alex Williamson +(cherry picked from commit 8151a9c56d31eeeea872b8103c8b86d03c411667) +Signed-off-by: Miroslav Rezanina +--- + hw/vfio/pci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c +index 34b9d19..4683eb4 100644 +--- a/hw/vfio/pci.c ++++ b/hw/vfio/pci.c +@@ -3167,7 +3167,7 @@ static Property vfio_pci_dev_properties[] = { + DEFINE_PROP_PCI_HOST_DEVADDR("host", VFIOPCIDevice, host), + DEFINE_PROP_STRING("sysfsdev", VFIOPCIDevice, vbasedev.sysfsdev), + DEFINE_PROP_ON_OFF_AUTO("display", VFIOPCIDevice, +- display, ON_OFF_AUTO_AUTO), ++ display, ON_OFF_AUTO_OFF), + DEFINE_PROP_UINT32("x-intx-mmap-timeout-ms", VFIOPCIDevice, + intx.mmap_timeout, 1100), + DEFINE_PROP_BIT("x-vga", VFIOPCIDevice, features, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vfio-pci-do-not-set-the-PCIDevice-has_rom-attribute.patch b/SOURCES/kvm-vfio-pci-do-not-set-the-PCIDevice-has_rom-attribute.patch new file mode 100644 index 0000000..81812ca --- /dev/null +++ b/SOURCES/kvm-vfio-pci-do-not-set-the-PCIDevice-has_rom-attribute.patch @@ -0,0 +1,67 @@ +From 3483f36dbf965a4ca01c4a2d3bce1132340596d1 Mon Sep 17 00:00:00 2001 +From: "plai@redhat.com" +Date: Fri, 31 Aug 2018 16:25:52 +0200 +Subject: [PATCH 10/29] vfio/pci: do not set the PCIDevice 'has_rom' attribute +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: plai@redhat.com +Message-id: <1535732759-22481-3-git-send-email-plai@redhat.com> +Patchwork-id: 82004 +O-Subject: [RHEL7.6 PATCH BZ 1539280 2/9] vfio/pci: do not set the PCIDevice 'has_rom' attribute +Bugzilla: 1539280 +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Pankaj Gupta +RH-Acked-by: Miroslav Rezanina + +From: Cédric Le Goater + +PCI devices needing a ROM allocate an optional MemoryRegion with +pci_add_option_rom(). pci_del_option_rom() does the cleanup when the +device is destroyed. The only action taken by this routine is to call +vmstate_unregister_ram() which clears the id string of the optional +ROM RAMBlock and now, also flags the RAMBlock as non-migratable. This +was recently added by commit b895de502717 ("migration: discard +non-migratable RAMBlocks"), . + +VFIO devices do their own loading of the PCI option ROM in +vfio_pci_size_rom(). The memory region is switched to an I/O region +and the PCI attribute 'has_rom' is set but the RAMBlock of the ROM +region is not allocated. When the associated PCI device is deleted, +pci_del_option_rom() calls vmstate_unregister_ram() which tries to +flag a NULL RAMBlock, leading to a SEGV. + +It seems that 'has_rom' was set to have memory_region_destroy() +called, but since commit 469b046ead06 ("memory: remove +memory_region_destroy") this is not necessary anymore as the +MemoryRegion is freed automagically. + +Remove the PCIDevice 'has_rom' attribute setting in vfio. + +Fixes: b895de502717 ("migration: discard non-migratable RAMBlocks") +Signed-off-by: Cédric Le Goater +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Alex Williamson +(cherry picked from commit 26c0ae56386edacc8b0da40264748f59afedb1bb) +Signed-off-by: Paul Lai +Signed-off-by: Miroslav Rezanina +--- + hw/vfio/pci.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c +index 4683eb4..c00b91c 100644 +--- a/hw/vfio/pci.c ++++ b/hw/vfio/pci.c +@@ -990,7 +990,6 @@ static void vfio_pci_size_rom(VFIOPCIDevice *vdev) + pci_register_bar(&vdev->pdev, PCI_ROM_SLOT, + PCI_BASE_ADDRESS_SPACE_MEMORY, &vdev->pdev.rom); + +- vdev->pdev.has_rom = true; + vdev->rom_read_failed = false; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vga-add-ram_addr_t-cast.patch b/SOURCES/kvm-vga-add-ram_addr_t-cast.patch deleted file mode 100644 index b7ba905..0000000 --- a/SOURCES/kvm-vga-add-ram_addr_t-cast.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 1d5aa1e3de92a5ceff6c30e48c10275c5d3ce9ac Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Mon, 19 Mar 2018 14:34:58 +0100 -Subject: [PATCH 3/4] vga: add ram_addr_t cast - -RH-Author: Gerd Hoffmann -Message-id: <20180319143459.15364-2-kraxel@redhat.com> -Patchwork-id: 79361 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 1/2] vga: add ram_addr_t cast -Bugzilla: 1566878 -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Laszlo Ersek - -Reported by Coverity. - -Fixes: CID 1381409 -Signed-off-by: Gerd Hoffmann -Message-id: 20171010141323.14049-4-kraxel@redhat.com -(cherry picked from commit b0898b42ef099bc125db1fbf62b7f02b505ef3a2) -Signed-off-by: Miroslav Rezanina ---- - hw/display/vga.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/display/vga.c b/hw/display/vga.c -index b1cdf36..b6a3b95 100644 ---- a/hw/display/vga.c -+++ b/hw/display/vga.c -@@ -1488,7 +1488,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) - disp_width = width; - - region_start = (s->start_addr * 4); -- region_end = region_start + s->line_offset * height; -+ region_end = region_start + (ram_addr_t)s->line_offset * height; - if (region_end > s->vbe_size) { - /* wraps around (can happen with cirrus vbe modes) */ - region_start = 0; --- -1.8.3.1 - diff --git a/SOURCES/kvm-vga-catch-depth-0.patch b/SOURCES/kvm-vga-catch-depth-0.patch new file mode 100644 index 0000000..93f9889 --- /dev/null +++ b/SOURCES/kvm-vga-catch-depth-0.patch @@ -0,0 +1,82 @@ +From 18adbd3883efdd681ed30402c0127971bf058031 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Tue, 29 May 2018 10:57:04 +0200 +Subject: [PATCH 6/8] vga: catch depth 0 + +RH-Author: Gerd Hoffmann +Message-id: <20180529105704.21419-2-kraxel@redhat.com> +Patchwork-id: 80500 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/1] vga: catch depth 0 +Bugzilla: 1575541 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Stefan Hajnoczi + +depth == 0 is used to indicate 256 color modes. Our region calculation +goes wrong in that case. So detect that and just take the safe code +path we already have for the wraparound case. + +While being at it also catch depth == 15 (where our region size +calculation goes wrong too). And make the comment more verbose, +explaining what is going on here. + +Without this windows guest install might trigger an assert due to trying +to check dirty bitmap outside the snapshot region. + +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1575541 +Signed-off-by: Gerd Hoffmann +Message-id: 20180514103117.21059-1-kraxel@redhat.com +(cherry picked from commit a89fe6c329799e47aaa1663650f076b28808e186) +Signed-off-by: Miroslav Rezanina +--- + hw/display/vga.c | 23 ++++++++++++++++++----- + 1 file changed, 18 insertions(+), 5 deletions(-) + +diff --git a/hw/display/vga.c b/hw/display/vga.c +index 7218133..a7794f6 100644 +--- a/hw/display/vga.c ++++ b/hw/display/vga.c +@@ -1480,13 +1480,28 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) + + s->get_resolution(s, &width, &height); + disp_width = width; ++ depth = s->get_bpp(s); + + region_start = (s->start_addr * 4); + region_end = region_start + (ram_addr_t)s->line_offset * height; +- region_end += width * s->get_bpp(s) / 8; /* scanline length */ ++ region_end += width * depth / 8; /* scanline length */ + region_end -= s->line_offset; +- if (region_end > s->vbe_size) { +- /* wraps around (can happen with cirrus vbe modes) */ ++ if (region_end > s->vbe_size || depth == 0 || depth == 15) { ++ /* ++ * We land here on: ++ * - wraps around (can happen with cirrus vbe modes) ++ * - depth == 0 (256 color palette video mode) ++ * - depth == 15 ++ * ++ * Take the safe and slow route: ++ * - create a dirty bitmap snapshot for all vga memory. ++ * - force shadowing (so all vga memory access goes ++ * through vga_read_*() helpers). ++ * ++ * Given this affects only vga features which are pretty much ++ * unused by modern guests there should be no performance ++ * impact. ++ */ + region_start = 0; + region_end = s->vbe_size; + force_shadow = true; +@@ -1520,8 +1535,6 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) + } + } + +- depth = s->get_bpp(s); +- + /* + * Check whether we can share the surface with the backend + * or whether we need a shadow surface. We share native +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vga-check-the-validation-of-memory-addr-when-draw-te.patch b/SOURCES/kvm-vga-check-the-validation-of-memory-addr-when-draw-te.patch deleted file mode 100644 index 3f783fe..0000000 --- a/SOURCES/kvm-vga-check-the-validation-of-memory-addr-when-draw-te.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 3b2c6ef26bdde6363ca750008cef962076e2bf0f Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Fri, 26 Jan 2018 08:12:43 +0100 -Subject: [PATCH 6/8] vga: check the validation of memory addr when draw text - -RH-Author: Gerd Hoffmann -Message-id: <20180126081243.19785-2-kraxel@redhat.com> -Patchwork-id: 78712 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 1/1] vga: check the validation of memory addr when draw text -Bugzilla: 1534682 -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Miroslav Rezanina - -From: linzhecheng - -Start a vm with qemu-kvm -enable-kvm -vnc :66 -smp 1 -m 1024 -hda -redhat_5.11.qcow2 -device pcnet -vga cirrus, -then use VNC client to connect to VM, and excute the code below in guest -OS will lead to qemu crash: - -int main() - { - iopl(3); - srand(time(NULL)); - int a,b; - while(1){ - a = rand()%0x100; - b = 0x3c0 + (rand()%0x20); - outb(a,b); - } - return 0; -} - -The above code is writing the registers of VGA randomly. -We can write VGA CRT controller registers index 0x0C or 0x0D -(which is the start address register) to modify the -the display memory address of the upper left pixel -or character of the screen. The address may be out of the -range of vga ram. So we should check the validation of memory address -when reading or writing it to avoid segfault. - -Signed-off-by: linzhecheng -Message-id: 20180111132724.13744-1-linzhecheng@huawei.com -Fixes: CVE-2018-5683 -Signed-off-by: Gerd Hoffmann -(cherry picked from commit 191f59dc17396bb5a8da50f8c59b6e0a430711a4) -Signed-off-by: Miroslav Rezanina ---- - hw/display/vga.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/hw/display/vga.c b/hw/display/vga.c -index 06ca3da..b1cdf36 100644 ---- a/hw/display/vga.c -+++ b/hw/display/vga.c -@@ -1280,6 +1280,9 @@ static void vga_draw_text(VGACommonState *s, int full_update) - cx_min = width; - cx_max = -1; - for(cx = 0; cx < width; cx++) { -+ if (src + sizeof(uint16_t) > s->vram_ptr + s->vram_size) { -+ break; -+ } - ch_attr = *(uint16_t *)src; - if (full_update || ch_attr != *ch_attr_ptr || src == cursor_ptr) { - if (cx < cx_min) --- -1.8.3.1 - diff --git a/SOURCES/kvm-vga-drop-line_offset-variable.patch b/SOURCES/kvm-vga-drop-line_offset-variable.patch deleted file mode 100644 index e3c01dd..0000000 --- a/SOURCES/kvm-vga-drop-line_offset-variable.patch +++ /dev/null @@ -1,63 +0,0 @@ -From a66572373f31b1267b85f9e4da23a74b82280d14 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Fri, 20 Oct 2017 07:19:23 +0200 -Subject: [PATCH 01/19] vga: drop line_offset variable - -RH-Author: Gerd Hoffmann -Message-id: <20171020071925.9483-3-kraxel@redhat.com> -Patchwork-id: 77390 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 2/4] vga: drop line_offset variable -Bugzilla: 1501301 -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Laurent Vivier - -Signed-off-by: Gerd Hoffmann -(cherry picked from commit 362f811793ff6cb4d209ab61d76cc4f841bb5e46) -Signed-off-by: Miroslav Rezanina ---- - hw/display/vga.c | 7 +++---- - 1 file changed, 3 insertions(+), 4 deletions(-) - -diff --git a/hw/display/vga.c b/hw/display/vga.c -index 497c823..895e95c 100644 ---- a/hw/display/vga.c -+++ b/hw/display/vga.c -@@ -1464,7 +1464,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) - { - DisplaySurface *surface = qemu_console_surface(s->con); - int y1, y, update, linesize, y_start, double_scan, mask, depth; -- int width, height, shift_control, line_offset, bwidth, bits; -+ int width, height, shift_control, bwidth, bits; - ram_addr_t page0, page1; - DirtyBitmapSnapshot *snap = NULL; - int disp_width, multi_scan, multi_run; -@@ -1614,7 +1614,6 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) - s->cursor_invalidate(s); - } - -- line_offset = s->line_offset; - #if 0 - printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n", - width, height, v, line_offset, s->cr[9], s->cr[VGA_CRTC_MODE], -@@ -1629,7 +1628,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) - - if (!full_update) { - ram_addr_t region_start = addr1; -- ram_addr_t region_end = addr1 + line_offset * height; -+ ram_addr_t region_end = addr1 + s->line_offset * height; - vga_sync_dirty_bitmap(s); - if (s->line_compare < height) { - /* split screen mode */ -@@ -1681,7 +1680,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) - if (!multi_run) { - mask = (s->cr[VGA_CRTC_MODE] & 3) ^ 3; - if ((y1 & mask) == mask) -- addr1 += line_offset; -+ addr1 += s->line_offset; - y1++; - multi_run = multi_scan; - } else { --- -1.8.3.1 - diff --git a/SOURCES/kvm-vga-fix-display-update-region-calculation-split-scre.patch b/SOURCES/kvm-vga-fix-display-update-region-calculation-split-scre.patch deleted file mode 100644 index a1ba09d..0000000 --- a/SOURCES/kvm-vga-fix-display-update-region-calculation-split-scre.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 5a5e2e2d4f7cc2fd67fa970584f06a29ba69fc3a Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Thu, 5 Oct 2017 09:49:33 +0200 -Subject: [PATCH 02/69] vga: fix display update region calculation (split - screen) - -RH-Author: Gerd Hoffmann -Message-id: <20171005094933.19435-2-kraxel@redhat.com> -Patchwork-id: 76816 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 1/1] vga: fix display update region calculation (split screen) -Bugzilla: 1486648 -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Thomas Huth - -vga display update mis-calculated the region for the dirty bitmap -snapshot in case split screen mode is used. This can trigger an -assert in cpu_physical_memory_snapshot_get_dirty(). - -Impact: DoS for privileged guest users. - -Fixes: CVE-2017-13673 -Fixes: fec5e8c92becad223df9d972770522f64aafdb72 -Cc: P J P -Reported-by: David Buchanan -Signed-off-by: Gerd Hoffmann -Message-id: 20170828123307.15392-1-kraxel@redhat.com -(cherry picked from commit e65294157d4b69393b3f819c99f4f647452b48e3) -Signed-off-by: Miroslav Rezanina ---- - hw/display/vga.c | 10 ++++++++-- - 1 file changed, 8 insertions(+), 2 deletions(-) - -diff --git a/hw/display/vga.c b/hw/display/vga.c -index 4c2ee0b..497c823 100644 ---- a/hw/display/vga.c -+++ b/hw/display/vga.c -@@ -1628,9 +1628,15 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) - y1 = 0; - - if (!full_update) { -+ ram_addr_t region_start = addr1; -+ ram_addr_t region_end = addr1 + line_offset * height; - vga_sync_dirty_bitmap(s); -- snap = memory_region_snapshot_and_clear_dirty(&s->vram, addr1, -- line_offset * height, -+ if (s->line_compare < height) { -+ /* split screen mode */ -+ region_start = 0; -+ } -+ snap = memory_region_snapshot_and_clear_dirty(&s->vram, region_start, -+ region_end - region_start, - DIRTY_MEMORY_VGA); - } - --- -1.8.3.1 - diff --git a/SOURCES/kvm-vga-fix-region-calculation.patch b/SOURCES/kvm-vga-fix-region-calculation.patch deleted file mode 100644 index a4d234a..0000000 --- a/SOURCES/kvm-vga-fix-region-calculation.patch +++ /dev/null @@ -1,47 +0,0 @@ -From a4a396ff1f6bf512d8a1e65f692242d4332c615c Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Mon, 19 Mar 2018 14:34:59 +0100 -Subject: [PATCH 4/4] vga: fix region calculation - -RH-Author: Gerd Hoffmann -Message-id: <20180319143459.15364-3-kraxel@redhat.com> -Patchwork-id: 79360 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 2/2] vga: fix region calculation -Bugzilla: 1566878 -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Laszlo Ersek - -Typically the scanline length and the line offset are identical. But -in case they are not our calculation for region_end is incorrect. Using -line_offset is fine for all scanlines, except the last one where we have -to use the actual scanline length. - -Fixes: CVE-2018-7550 -Reported-by: Ross Lagerwall -Signed-off-by: Gerd Hoffmann -Reviewed-by: Prasad J Pandit -Tested-by: Ross Lagerwall -Message-id: 20180309143704.13420-1-kraxel@redhat.com -(cherry picked from commit 7cdc61becd095b64a786b2625f321624e7111f3d) -Signed-off-by: Miroslav Rezanina ---- - hw/display/vga.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/hw/display/vga.c b/hw/display/vga.c -index b6a3b95..f060f26 100644 ---- a/hw/display/vga.c -+++ b/hw/display/vga.c -@@ -1489,6 +1489,8 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) - - region_start = (s->start_addr * 4); - region_end = region_start + (ram_addr_t)s->line_offset * height; -+ region_end += width * s->get_bpp(s) / 8; /* scanline length */ -+ region_end -= s->line_offset; - if (region_end > s->vbe_size) { - /* wraps around (can happen with cirrus vbe modes) */ - region_start = 0; --- -1.8.3.1 - diff --git a/SOURCES/kvm-vga-handle-cirrus-vbe-mode-wraparounds.patch b/SOURCES/kvm-vga-handle-cirrus-vbe-mode-wraparounds.patch deleted file mode 100644 index ce3346e..0000000 --- a/SOURCES/kvm-vga-handle-cirrus-vbe-mode-wraparounds.patch +++ /dev/null @@ -1,114 +0,0 @@ -From cb36a048eaf475d3184e5fbecfa669d5d645f943 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Fri, 20 Oct 2017 07:19:24 +0200 -Subject: [PATCH 02/19] vga: handle cirrus vbe mode wraparounds. - -RH-Author: Gerd Hoffmann -Message-id: <20171020071925.9483-4-kraxel@redhat.com> -Patchwork-id: 77391 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 3/4] vga: handle cirrus vbe mode wraparounds. -Bugzilla: 1501301 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Laurent Vivier -RH-Acked-by: Dr. David Alan Gilbert - -Commit "3d90c62548 vga: stop passing pointers to vga_draw_line* -functions" is incomplete. It doesn't handle the case that the vga -rendering code tries to create a shared surface, i.e. a pixman image -backed by vga video memory. That can not work in case the guest display -wraps from end of video memory to the start. So force shadowing in that -case. Also adjust the snapshot region calculation. - -Can trigger with cirrus only, when programming vbe modes using the bochs -api (stdvga, also qxl and virtio-vga in vga compat mode) wrap arounds -can't happen. - -Fixes: CVE-2017-13672 -Fixes: 3d90c6254863693a6b13d918d2b8682e08bbc681 -Cc: P J P -Reported-by: David Buchanan -Signed-off-by: Gerd Hoffmann -Message-id: 20171010141323.14049-3-kraxel@redhat.com -(cherry picked from commit 28f77de26a4f9995458ddeb9d34bb06c0193bdc9) -Signed-off-by: Miroslav Rezanina ---- - hw/display/vga.c | 28 +++++++++++++++++++++------- - 1 file changed, 21 insertions(+), 7 deletions(-) - -diff --git a/hw/display/vga.c b/hw/display/vga.c -index 895e95c..06ca3da 100644 ---- a/hw/display/vga.c -+++ b/hw/display/vga.c -@@ -1465,13 +1465,13 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) - DisplaySurface *surface = qemu_console_surface(s->con); - int y1, y, update, linesize, y_start, double_scan, mask, depth; - int width, height, shift_control, bwidth, bits; -- ram_addr_t page0, page1; -+ ram_addr_t page0, page1, region_start, region_end; - DirtyBitmapSnapshot *snap = NULL; - int disp_width, multi_scan, multi_run; - uint8_t *d; - uint32_t v, addr1, addr; - vga_draw_line_func *vga_draw_line = NULL; -- bool share_surface; -+ bool share_surface, force_shadow = false; - pixman_format_code_t format; - #ifdef HOST_WORDS_BIGENDIAN - bool byteswap = !s->big_endian_fb; -@@ -1484,6 +1484,15 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) - s->get_resolution(s, &width, &height); - disp_width = width; - -+ region_start = (s->start_addr * 4); -+ region_end = region_start + s->line_offset * height; -+ if (region_end > s->vbe_size) { -+ /* wraps around (can happen with cirrus vbe modes) */ -+ region_start = 0; -+ region_end = s->vbe_size; -+ force_shadow = true; -+ } -+ - shift_control = (s->gr[VGA_GFX_MODE] >> 5) & 3; - double_scan = (s->cr[VGA_CRTC_MAX_SCAN] >> 7); - if (shift_control != 1) { -@@ -1523,7 +1532,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) - format = qemu_default_pixman_format(depth, !byteswap); - if (format) { - share_surface = dpy_gfx_check_format(s->con, format) -- && !s->force_shadow; -+ && !s->force_shadow && !force_shadow; - } else { - share_surface = false; - } -@@ -1627,8 +1636,6 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) - y1 = 0; - - if (!full_update) { -- ram_addr_t region_start = addr1; -- ram_addr_t region_end = addr1 + s->line_offset * height; - vga_sync_dirty_bitmap(s); - if (s->line_compare < height) { - /* split screen mode */ -@@ -1651,10 +1658,17 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) - addr = (addr & ~0x8000) | ((y1 & 2) << 14); - } - update = full_update; -- page0 = addr; -- page1 = addr + bwidth - 1; -+ page0 = addr & s->vbe_size_mask; -+ page1 = (addr + bwidth - 1) & s->vbe_size_mask; - if (full_update) { - update = 1; -+ } else if (page1 < page0) { -+ /* scanline wraps from end of video memory to the start */ -+ assert(force_shadow); -+ update = memory_region_snapshot_get_dirty(&s->vram, snap, -+ page0, 0); -+ update |= memory_region_snapshot_get_dirty(&s->vram, snap, -+ page1, 0); - } else { - update = memory_region_snapshot_get_dirty(&s->vram, snap, - page0, page1 - page0); --- -1.8.3.1 - diff --git a/SOURCES/kvm-vga-stop-passing-pointers-to-vga_draw_line-functions.patch b/SOURCES/kvm-vga-stop-passing-pointers-to-vga_draw_line-functions.patch deleted file mode 100644 index c35ea02..0000000 --- a/SOURCES/kvm-vga-stop-passing-pointers-to-vga_draw_line-functions.patch +++ /dev/null @@ -1,508 +0,0 @@ -From 26b9a8ca080307b0d01799f96f944fb32e1619f0 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Thu, 5 Oct 2017 09:11:41 +0200 -Subject: [PATCH 10/34] vga: stop passing pointers to vga_draw_line* functions - -RH-Author: Gerd Hoffmann -Message-id: <20171005091141.30358-2-kraxel@redhat.com> -Patchwork-id: 76814 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 1/1] vga: stop passing pointers to vga_draw_line* functions -Bugzilla: 1486643 -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Miroslav Rezanina - -Instead pass around the address (aka offset into vga memory). -Add vga_read_* helper functions which apply vbe_size_mask to -the address, to make sure the address stays within the valid -range, similar to the cirrus blitter fixes (commits ffaf857778 -and 026aeffcb4). - -Impact: DoS for privileged guest users. qemu crashes with -a segfault, when hitting the guard page after vga memory -allocation, while reading vga memory for display updates. - -Fixes: CVE-2017-13672 -Cc: P J P -Reported-by: David Buchanan -Signed-off-by: Gerd Hoffmann -Message-id: 20170828122906.18993-1-kraxel@redhat.com -(cherry picked from commit 3d90c6254863693a6b13d918d2b8682e08bbc681) -Signed-off-by: Miroslav Rezanina ---- - hw/display/vga-helpers.h | 202 ++++++++++++++++++++++++++--------------------- - hw/display/vga.c | 5 +- - hw/display/vga_int.h | 1 + - 3 files changed, 114 insertions(+), 94 deletions(-) - -diff --git a/hw/display/vga-helpers.h b/hw/display/vga-helpers.h -index 94f6de2..5a752b3 100644 ---- a/hw/display/vga-helpers.h -+++ b/hw/display/vga-helpers.h -@@ -95,20 +95,46 @@ static void vga_draw_glyph9(uint8_t *d, int linesize, - } while (--h); - } - -+static inline uint8_t vga_read_byte(VGACommonState *vga, uint32_t addr) -+{ -+ return vga->vram_ptr[addr & vga->vbe_size_mask]; -+} -+ -+static inline uint16_t vga_read_word_le(VGACommonState *vga, uint32_t addr) -+{ -+ uint32_t offset = addr & vga->vbe_size_mask & ~1; -+ uint16_t *ptr = (uint16_t *)(vga->vram_ptr + offset); -+ return lduw_le_p(ptr); -+} -+ -+static inline uint16_t vga_read_word_be(VGACommonState *vga, uint32_t addr) -+{ -+ uint32_t offset = addr & vga->vbe_size_mask & ~1; -+ uint16_t *ptr = (uint16_t *)(vga->vram_ptr + offset); -+ return lduw_be_p(ptr); -+} -+ -+static inline uint32_t vga_read_dword_le(VGACommonState *vga, uint32_t addr) -+{ -+ uint32_t offset = addr & vga->vbe_size_mask & ~3; -+ uint32_t *ptr = (uint32_t *)(vga->vram_ptr + offset); -+ return ldl_le_p(ptr); -+} -+ - /* - * 4 color mode - */ --static void vga_draw_line2(VGACommonState *s1, uint8_t *d, -- const uint8_t *s, int width) -+static void vga_draw_line2(VGACommonState *vga, uint8_t *d, -+ uint32_t addr, int width) - { - uint32_t plane_mask, *palette, data, v; - int x; - -- palette = s1->last_palette; -- plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf]; -+ palette = vga->last_palette; -+ plane_mask = mask16[vga->ar[VGA_ATC_PLANE_ENABLE] & 0xf]; - width >>= 3; - for(x = 0; x < width; x++) { -- data = ((uint32_t *)s)[0]; -+ data = vga_read_dword_le(vga, addr); - data &= plane_mask; - v = expand2[GET_PLANE(data, 0)]; - v |= expand2[GET_PLANE(data, 2)] << 2; -@@ -124,7 +150,7 @@ static void vga_draw_line2(VGACommonState *s1, uint8_t *d, - ((uint32_t *)d)[6] = palette[(v >> 4) & 0xf]; - ((uint32_t *)d)[7] = palette[(v >> 0) & 0xf]; - d += 32; -- s += 4; -+ addr += 4; - } - } - -@@ -134,17 +160,17 @@ static void vga_draw_line2(VGACommonState *s1, uint8_t *d, - /* - * 4 color mode, dup2 horizontal - */ --static void vga_draw_line2d2(VGACommonState *s1, uint8_t *d, -- const uint8_t *s, int width) -+static void vga_draw_line2d2(VGACommonState *vga, uint8_t *d, -+ uint32_t addr, int width) - { - uint32_t plane_mask, *palette, data, v; - int x; - -- palette = s1->last_palette; -- plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf]; -+ palette = vga->last_palette; -+ plane_mask = mask16[vga->ar[VGA_ATC_PLANE_ENABLE] & 0xf]; - width >>= 3; - for(x = 0; x < width; x++) { -- data = ((uint32_t *)s)[0]; -+ data = vga_read_dword_le(vga, addr); - data &= plane_mask; - v = expand2[GET_PLANE(data, 0)]; - v |= expand2[GET_PLANE(data, 2)] << 2; -@@ -160,24 +186,24 @@ static void vga_draw_line2d2(VGACommonState *s1, uint8_t *d, - PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]); - PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]); - d += 64; -- s += 4; -+ addr += 4; - } - } - - /* - * 16 color mode - */ --static void vga_draw_line4(VGACommonState *s1, uint8_t *d, -- const uint8_t *s, int width) -+static void vga_draw_line4(VGACommonState *vga, uint8_t *d, -+ uint32_t addr, int width) - { - uint32_t plane_mask, data, v, *palette; - int x; - -- palette = s1->last_palette; -- plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf]; -+ palette = vga->last_palette; -+ plane_mask = mask16[vga->ar[VGA_ATC_PLANE_ENABLE] & 0xf]; - width >>= 3; - for(x = 0; x < width; x++) { -- data = ((uint32_t *)s)[0]; -+ data = vga_read_dword_le(vga, addr); - data &= plane_mask; - v = expand4[GET_PLANE(data, 0)]; - v |= expand4[GET_PLANE(data, 1)] << 1; -@@ -192,24 +218,24 @@ static void vga_draw_line4(VGACommonState *s1, uint8_t *d, - ((uint32_t *)d)[6] = palette[(v >> 4) & 0xf]; - ((uint32_t *)d)[7] = palette[(v >> 0) & 0xf]; - d += 32; -- s += 4; -+ addr += 4; - } - } - - /* - * 16 color mode, dup2 horizontal - */ --static void vga_draw_line4d2(VGACommonState *s1, uint8_t *d, -- const uint8_t *s, int width) -+static void vga_draw_line4d2(VGACommonState *vga, uint8_t *d, -+ uint32_t addr, int width) - { - uint32_t plane_mask, data, v, *palette; - int x; - -- palette = s1->last_palette; -- plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf]; -+ palette = vga->last_palette; -+ plane_mask = mask16[vga->ar[VGA_ATC_PLANE_ENABLE] & 0xf]; - width >>= 3; - for(x = 0; x < width; x++) { -- data = ((uint32_t *)s)[0]; -+ data = vga_read_dword_le(vga, addr); - data &= plane_mask; - v = expand4[GET_PLANE(data, 0)]; - v |= expand4[GET_PLANE(data, 1)] << 1; -@@ -224,7 +250,7 @@ static void vga_draw_line4d2(VGACommonState *s1, uint8_t *d, - PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]); - PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]); - d += 64; -- s += 4; -+ addr += 4; - } - } - -@@ -233,21 +259,21 @@ static void vga_draw_line4d2(VGACommonState *s1, uint8_t *d, - * - * XXX: add plane_mask support (never used in standard VGA modes) - */ --static void vga_draw_line8d2(VGACommonState *s1, uint8_t *d, -- const uint8_t *s, int width) -+static void vga_draw_line8d2(VGACommonState *vga, uint8_t *d, -+ uint32_t addr, int width) - { - uint32_t *palette; - int x; - -- palette = s1->last_palette; -+ palette = vga->last_palette; - width >>= 3; - for(x = 0; x < width; x++) { -- PUT_PIXEL2(d, 0, palette[s[0]]); -- PUT_PIXEL2(d, 1, palette[s[1]]); -- PUT_PIXEL2(d, 2, palette[s[2]]); -- PUT_PIXEL2(d, 3, palette[s[3]]); -+ PUT_PIXEL2(d, 0, palette[vga_read_byte(vga, addr + 0)]); -+ PUT_PIXEL2(d, 1, palette[vga_read_byte(vga, addr + 1)]); -+ PUT_PIXEL2(d, 2, palette[vga_read_byte(vga, addr + 2)]); -+ PUT_PIXEL2(d, 3, palette[vga_read_byte(vga, addr + 3)]); - d += 32; -- s += 4; -+ addr += 4; - } - } - -@@ -256,63 +282,63 @@ static void vga_draw_line8d2(VGACommonState *s1, uint8_t *d, - * - * XXX: add plane_mask support (never used in standard VGA modes) - */ --static void vga_draw_line8(VGACommonState *s1, uint8_t *d, -- const uint8_t *s, int width) -+static void vga_draw_line8(VGACommonState *vga, uint8_t *d, -+ uint32_t addr, int width) - { - uint32_t *palette; - int x; - -- palette = s1->last_palette; -+ palette = vga->last_palette; - width >>= 3; - for(x = 0; x < width; x++) { -- ((uint32_t *)d)[0] = palette[s[0]]; -- ((uint32_t *)d)[1] = palette[s[1]]; -- ((uint32_t *)d)[2] = palette[s[2]]; -- ((uint32_t *)d)[3] = palette[s[3]]; -- ((uint32_t *)d)[4] = palette[s[4]]; -- ((uint32_t *)d)[5] = palette[s[5]]; -- ((uint32_t *)d)[6] = palette[s[6]]; -- ((uint32_t *)d)[7] = palette[s[7]]; -+ ((uint32_t *)d)[0] = palette[vga_read_byte(vga, addr + 0)]; -+ ((uint32_t *)d)[1] = palette[vga_read_byte(vga, addr + 1)]; -+ ((uint32_t *)d)[2] = palette[vga_read_byte(vga, addr + 2)]; -+ ((uint32_t *)d)[3] = palette[vga_read_byte(vga, addr + 3)]; -+ ((uint32_t *)d)[4] = palette[vga_read_byte(vga, addr + 4)]; -+ ((uint32_t *)d)[5] = palette[vga_read_byte(vga, addr + 5)]; -+ ((uint32_t *)d)[6] = palette[vga_read_byte(vga, addr + 6)]; -+ ((uint32_t *)d)[7] = palette[vga_read_byte(vga, addr + 7)]; - d += 32; -- s += 8; -+ addr += 8; - } - } - - /* - * 15 bit color - */ --static void vga_draw_line15_le(VGACommonState *s1, uint8_t *d, -- const uint8_t *s, int width) -+static void vga_draw_line15_le(VGACommonState *vga, uint8_t *d, -+ uint32_t addr, int width) - { - int w; - uint32_t v, r, g, b; - - w = width; - do { -- v = lduw_le_p((void *)s); -+ v = vga_read_word_le(vga, addr); - r = (v >> 7) & 0xf8; - g = (v >> 2) & 0xf8; - b = (v << 3) & 0xf8; - ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b); -- s += 2; -+ addr += 2; - d += 4; - } while (--w != 0); - } - --static void vga_draw_line15_be(VGACommonState *s1, uint8_t *d, -- const uint8_t *s, int width) -+static void vga_draw_line15_be(VGACommonState *vga, uint8_t *d, -+ uint32_t addr, int width) - { - int w; - uint32_t v, r, g, b; - - w = width; - do { -- v = lduw_be_p((void *)s); -+ v = vga_read_word_be(vga, addr); - r = (v >> 7) & 0xf8; - g = (v >> 2) & 0xf8; - b = (v << 3) & 0xf8; - ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b); -- s += 2; -+ addr += 2; - d += 4; - } while (--w != 0); - } -@@ -320,38 +346,38 @@ static void vga_draw_line15_be(VGACommonState *s1, uint8_t *d, - /* - * 16 bit color - */ --static void vga_draw_line16_le(VGACommonState *s1, uint8_t *d, -- const uint8_t *s, int width) -+static void vga_draw_line16_le(VGACommonState *vga, uint8_t *d, -+ uint32_t addr, int width) - { - int w; - uint32_t v, r, g, b; - - w = width; - do { -- v = lduw_le_p((void *)s); -+ v = vga_read_word_le(vga, addr); - r = (v >> 8) & 0xf8; - g = (v >> 3) & 0xfc; - b = (v << 3) & 0xf8; - ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b); -- s += 2; -+ addr += 2; - d += 4; - } while (--w != 0); - } - --static void vga_draw_line16_be(VGACommonState *s1, uint8_t *d, -- const uint8_t *s, int width) -+static void vga_draw_line16_be(VGACommonState *vga, uint8_t *d, -+ uint32_t addr, int width) - { - int w; - uint32_t v, r, g, b; - - w = width; - do { -- v = lduw_be_p((void *)s); -+ v = vga_read_word_be(vga, addr); - r = (v >> 8) & 0xf8; - g = (v >> 3) & 0xfc; - b = (v << 3) & 0xf8; - ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b); -- s += 2; -+ addr += 2; - d += 4; - } while (--w != 0); - } -@@ -359,36 +385,36 @@ static void vga_draw_line16_be(VGACommonState *s1, uint8_t *d, - /* - * 24 bit color - */ --static void vga_draw_line24_le(VGACommonState *s1, uint8_t *d, -- const uint8_t *s, int width) -+static void vga_draw_line24_le(VGACommonState *vga, uint8_t *d, -+ uint32_t addr, int width) - { - int w; - uint32_t r, g, b; - - w = width; - do { -- b = s[0]; -- g = s[1]; -- r = s[2]; -+ b = vga_read_byte(vga, addr + 0); -+ g = vga_read_byte(vga, addr + 1); -+ r = vga_read_byte(vga, addr + 2); - ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b); -- s += 3; -+ addr += 3; - d += 4; - } while (--w != 0); - } - --static void vga_draw_line24_be(VGACommonState *s1, uint8_t *d, -- const uint8_t *s, int width) -+static void vga_draw_line24_be(VGACommonState *vga, uint8_t *d, -+ uint32_t addr, int width) - { - int w; - uint32_t r, g, b; - - w = width; - do { -- r = s[0]; -- g = s[1]; -- b = s[2]; -+ r = vga_read_byte(vga, addr + 0); -+ g = vga_read_byte(vga, addr + 1); -+ b = vga_read_byte(vga, addr + 2); - ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b); -- s += 3; -+ addr += 3; - d += 4; - } while (--w != 0); - } -@@ -396,44 +422,36 @@ static void vga_draw_line24_be(VGACommonState *s1, uint8_t *d, - /* - * 32 bit color - */ --static void vga_draw_line32_le(VGACommonState *s1, uint8_t *d, -- const uint8_t *s, int width) -+static void vga_draw_line32_le(VGACommonState *vga, uint8_t *d, -+ uint32_t addr, int width) - { --#ifndef HOST_WORDS_BIGENDIAN -- memcpy(d, s, width * 4); --#else - int w; - uint32_t r, g, b; - - w = width; - do { -- b = s[0]; -- g = s[1]; -- r = s[2]; -+ b = vga_read_byte(vga, addr + 0); -+ g = vga_read_byte(vga, addr + 1); -+ r = vga_read_byte(vga, addr + 2); - ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b); -- s += 4; -+ addr += 4; - d += 4; - } while (--w != 0); --#endif - } - --static void vga_draw_line32_be(VGACommonState *s1, uint8_t *d, -- const uint8_t *s, int width) -+static void vga_draw_line32_be(VGACommonState *vga, uint8_t *d, -+ uint32_t addr, int width) - { --#ifdef HOST_WORDS_BIGENDIAN -- memcpy(d, s, width * 4); --#else - int w; - uint32_t r, g, b; - - w = width; - do { -- r = s[1]; -- g = s[2]; -- b = s[3]; -+ r = vga_read_byte(vga, addr + 1); -+ g = vga_read_byte(vga, addr + 2); -+ b = vga_read_byte(vga, addr + 3); - ((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b); -- s += 4; -+ addr += 4; - d += 4; - } while (--w != 0); --#endif - } -diff --git a/hw/display/vga.c b/hw/display/vga.c -index 63421f9..4c2ee0b 100644 ---- a/hw/display/vga.c -+++ b/hw/display/vga.c -@@ -1005,7 +1005,7 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val) - } - - typedef void vga_draw_line_func(VGACommonState *s1, uint8_t *d, -- const uint8_t *s, int width); -+ uint32_t srcaddr, int width); - - #include "vga-helpers.h" - -@@ -1660,7 +1660,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) - if (y_start < 0) - y_start = y; - if (!(is_buffer_shared(surface))) { -- vga_draw_line(s, d, s->vram_ptr + addr, width); -+ vga_draw_line(s, d, addr, width); - if (s->cursor_draw_line) - s->cursor_draw_line(s, d, y); - } -@@ -2164,6 +2164,7 @@ void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate) - if (!s->vbe_size) { - s->vbe_size = s->vram_size; - } -+ s->vbe_size_mask = s->vbe_size - 1; - - s->is_vbe_vmstate = 1; - memory_region_init_ram_nomigrate(&s->vram, obj, "vga.vram", s->vram_size, -diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h -index dd6c958..ad34a1f 100644 ---- a/hw/display/vga_int.h -+++ b/hw/display/vga_int.h -@@ -94,6 +94,7 @@ typedef struct VGACommonState { - uint32_t vram_size; - uint32_t vram_size_mb; /* property */ - uint32_t vbe_size; -+ uint32_t vbe_size_mask; - uint32_t latch; - bool has_chain4_alias; - MemoryRegion chain4_alias; --- -1.8.3.1 - diff --git a/SOURCES/kvm-vhdx-Fix-vhdx_co_create-return-value.patch b/SOURCES/kvm-vhdx-Fix-vhdx_co_create-return-value.patch new file mode 100644 index 0000000..1e89787 --- /dev/null +++ b/SOURCES/kvm-vhdx-Fix-vhdx_co_create-return-value.patch @@ -0,0 +1,43 @@ +From 8510a5a2d268749fd0a55072375ba8e4618717b0 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Tue, 26 Jun 2018 09:48:38 +0200 +Subject: [PATCH 69/89] vhdx: Fix vhdx_co_create() return value + +RH-Author: Kevin Wolf +Message-id: <20180626094856.6924-56-kwolf@redhat.com> +Patchwork-id: 81127 +O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH v2 55/73] vhdx: Fix vhdx_co_create() return value +Bugzilla: 1513543 +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng + +.bdrv_co_create() is supposed to return 0 on success, but vhdx could +return a positive value instead. Fix this. + +Signed-off-by: Kevin Wolf +Reviewed-by: Max Reitz +Reviewed-by: Jeff Cody +(cherry picked from commit 4a5f2779bad769184550869931937acd0707ec3b) +Signed-off-by: Kevin Wolf +Signed-off-by: Miroslav Rezanina +--- + block/vhdx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/block/vhdx.c b/block/vhdx.c +index 6731298..31ac53b 100644 +--- a/block/vhdx.c ++++ b/block/vhdx.c +@@ -1950,7 +1950,7 @@ static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts, + goto delete_and_exit; + } + +- ++ ret = 0; + delete_and_exit: + blk_unref(blk); + bdrv_unref(bs); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vhost-Release-memory-references-on-cleanup.patch b/SOURCES/kvm-vhost-Release-memory-references-on-cleanup.patch deleted file mode 100644 index 23bf245..0000000 --- a/SOURCES/kvm-vhost-Release-memory-references-on-cleanup.patch +++ /dev/null @@ -1,60 +0,0 @@ -From f221643835f73976adf07ebe355176b09decb558 Mon Sep 17 00:00:00 2001 -From: Alex Williamson -Date: Mon, 11 Sep 2017 20:43:08 +0200 -Subject: [PATCH 01/34] vhost: Release memory references on cleanup - -RH-Author: Alex Williamson -Message-id: <20170911204254.12489.22036.stgit@redhat.home> -Patchwork-id: 76307 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 1/1] vhost: Release memory references on cleanup -Bugzilla: 1489670 -RH-Acked-by: John Snow -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Auger Eric - -vhost registers a MemoryListener where it adds and removes references -to MemoryRegions as the MemoryRegionSections pass through. The -region_add callback is invoked for each existing section when the -MemoryListener is registered, but unregistering the MemoryListener -performs no reciprocal region_del callback. It's therefore the -owner of the MemoryListener's responsibility to cleanup any persistent -changes, such as these memory references, after unregistering. - -The consequence of this bug is that if we have both a vhost device -and a vfio device, the vhost device will reference any mmap'd MMIO of -the vfio device via this MemoryListener. If the vhost device is then -removed, those references remain outstanding. If we then attempt to -remove the vfio device, it never gets finalized and the only way to -release the kernel file descriptors is to terminate the QEMU process. - -Fixes: dfde4e6e1a86 ("memory: add ref/unref calls") -Cc: Michael S. Tsirkin -Cc: Paolo Bonzini -Cc: qemu-stable@nongnu.org # v1.6.0+ -Signed-off-by: Alex Williamson -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit ee4c112846a0f2ac4fe5601918b0a2642ac8e2ed) -Signed-off-by: Miroslav Rezanina ---- - hw/virtio/vhost.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c -index 6eddb09..b737ca9 100644 ---- a/hw/virtio/vhost.c -+++ b/hw/virtio/vhost.c -@@ -1356,6 +1356,10 @@ void vhost_dev_cleanup(struct vhost_dev *hdev) - if (hdev->mem) { - /* those are only safe after successful init */ - memory_listener_unregister(&hdev->memory_listener); -+ for (i = 0; i < hdev->n_mem_sections; ++i) { -+ MemoryRegionSection *section = &hdev->mem_sections[i]; -+ memory_region_unref(section->mr); -+ } - QLIST_REMOVE(hdev, entry); - } - if (hdev->migration_blocker) { --- -1.8.3.1 - diff --git a/SOURCES/kvm-vhost-allow-backends-to-filter-memory-sections.patch b/SOURCES/kvm-vhost-allow-backends-to-filter-memory-sections.patch new file mode 100644 index 0000000..b0338d3 --- /dev/null +++ b/SOURCES/kvm-vhost-allow-backends-to-filter-memory-sections.patch @@ -0,0 +1,117 @@ +From 6f1ec0b51c03a266c26f3108bbdf45987f01b53f Mon Sep 17 00:00:00 2001 +From: "plai@redhat.com" +Date: Thu, 21 Jun 2018 18:54:41 +0200 +Subject: [PATCH 32/57] vhost: allow backends to filter memory sections + +RH-Author: plai@redhat.com +Message-id: <1529607285-9942-7-git-send-email-plai@redhat.com> +Patchwork-id: 80941 +O-Subject: [RHEL7.6 PATCH BZ 1526645 06/10] vhost: allow backends to filter memory sections +Bugzilla: 1526645 +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Maxime Coquelin +RH-Acked-by: Laurent Vivier + +From: Tiwei Bie + +This patch introduces a vhost op for vhost backends to allow +them to filter the memory sections that they can handle. + +Signed-off-by: Tiwei Bie +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 988a27754bbbc45698f7acb54352e5a1ae699514) +Signed-off-by: Paul Lai +Signed-off-by: Miroslav Rezanina +--- + hw/virtio/vhost-user.c | 11 +++++++++++ + hw/virtio/vhost.c | 9 +++++++-- + include/hw/virtio/vhost-backend.h | 4 ++++ + 3 files changed, 22 insertions(+), 2 deletions(-) + +diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c +index 85d8fd2..ebb946a 100644 +--- a/hw/virtio/vhost-user.c ++++ b/hw/virtio/vhost-user.c +@@ -1620,6 +1620,16 @@ vhost_user_crypto_close_session(struct vhost_dev *dev, uint64_t session_id) + return 0; + } + ++static bool vhost_user_mem_section_filter(struct vhost_dev *dev, ++ MemoryRegionSection *section) ++{ ++ bool result; ++ ++ result = memory_region_get_fd(section->mr) >= 0; ++ ++ return result; ++} ++ + const VhostOps user_ops = { + .backend_type = VHOST_BACKEND_TYPE_USER, + .vhost_backend_init = vhost_user_init, +@@ -1650,4 +1660,5 @@ const VhostOps user_ops = { + .vhost_set_config = vhost_user_set_config, + .vhost_crypto_create_session = vhost_user_crypto_create_session, + .vhost_crypto_close_session = vhost_user_crypto_close_session, ++ .vhost_backend_mem_section_filter = vhost_user_mem_section_filter, + }; +diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c +index 9d5850a..1ae68ff 100644 +--- a/hw/virtio/vhost.c ++++ b/hw/virtio/vhost.c +@@ -386,7 +386,7 @@ static int vhost_verify_ring_mappings(struct vhost_dev *dev, + return r; + } + +-static bool vhost_section(MemoryRegionSection *section) ++static bool vhost_section(struct vhost_dev *dev, MemoryRegionSection *section) + { + bool result; + bool log_dirty = memory_region_get_dirty_log_mask(section->mr) & +@@ -399,6 +399,11 @@ static bool vhost_section(MemoryRegionSection *section) + */ + result &= !log_dirty; + ++ if (result && dev->vhost_ops->vhost_backend_mem_section_filter) { ++ result &= ++ dev->vhost_ops->vhost_backend_mem_section_filter(dev, section); ++ } ++ + trace_vhost_section(section->mr->name, result); + return result; + } +@@ -632,7 +637,7 @@ static void vhost_region_addnop(MemoryListener *listener, + struct vhost_dev *dev = container_of(listener, struct vhost_dev, + memory_listener); + +- if (!vhost_section(section)) { ++ if (!vhost_section(dev, section)) { + return; + } + vhost_region_add_section(dev, section); +diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h +index 5dac61f..81283ec 100644 +--- a/include/hw/virtio/vhost-backend.h ++++ b/include/hw/virtio/vhost-backend.h +@@ -101,6 +101,9 @@ typedef int (*vhost_crypto_create_session_op)(struct vhost_dev *dev, + typedef int (*vhost_crypto_close_session_op)(struct vhost_dev *dev, + uint64_t session_id); + ++typedef bool (*vhost_backend_mem_section_filter_op)(struct vhost_dev *dev, ++ MemoryRegionSection *section); ++ + typedef struct VhostOps { + VhostBackendType backend_type; + vhost_backend_init vhost_backend_init; +@@ -138,6 +141,7 @@ typedef struct VhostOps { + vhost_set_config_op vhost_set_config; + vhost_crypto_create_session_op vhost_crypto_create_session; + vhost_crypto_close_session_op vhost_crypto_close_session; ++ vhost_backend_mem_section_filter_op vhost_backend_mem_section_filter; + } VhostOps; + + extern const VhostOps user_ops; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vhost-restore-avail-index-from-vring-used-index-on-d.patch b/SOURCES/kvm-vhost-restore-avail-index-from-vring-used-index-on-d.patch deleted file mode 100644 index ee714d2..0000000 --- a/SOURCES/kvm-vhost-restore-avail-index-from-vring-used-index-on-d.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 0166112bf9b190bb38208d507b7af4a6dca81063 Mon Sep 17 00:00:00 2001 -From: Maxime Coquelin -Date: Tue, 5 Dec 2017 09:28:39 +0100 -Subject: [PATCH 17/21] vhost: restore avail index from vring used index on - disconnection -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Maxime Coquelin -Message-id: <20171205092839.17597-3-maxime.coquelin@redhat.com> -Patchwork-id: 78141 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 2/2] vhost: restore avail index from vring used index on disconnection -Bugzilla: 1491909 -RH-Acked-by: wexu@redhat.com -RH-Acked-by: Marc-André Lureau -RH-Acked-by: Michael S. Tsirkin -RH-Acked-by: Xiao Wang - -vhost_virtqueue_stop() gets avail index value from the backend, -except if the backend is not responding. - -It happens when the backend crashes, and in this case, internal -state of the virtio queue is inconsistent, making packets -to corrupt the vring state. - -With a Linux guest, it results in following error message on -backend reconnection: - -[ 22.444905] virtio_net virtio0: output.0:id 0 is not a head! -[ 22.446746] net enp0s3: Unexpected TXQ (0) queue failure: -5 -[ 22.476360] net enp0s3: Unexpected TXQ (0) queue failure: -5 - -Fixes: 283e2c2adcb8 ("net: virtio-net discards TX data after link down") -Cc: qemu-stable@nongnu.org -Signed-off-by: Maxime Coquelin -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 2ae39a113af311cb56a0c35b7f212dafcef15303) -Signed-off-by: Maxime Coquelin -Signed-off-by: Miroslav Rezanina ---- - hw/virtio/vhost.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c -index b737ca9..76f6e1f 100644 ---- a/hw/virtio/vhost.c -+++ b/hw/virtio/vhost.c -@@ -1137,6 +1137,10 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev, - r = dev->vhost_ops->vhost_get_vring_base(dev, &state); - if (r < 0) { - VHOST_OPS_DEBUG("vhost VQ %d ring restore failed: %d", idx, r); -+ /* Connection to the backend is broken, so let's sync internal -+ * last avail idx to the device used idx. -+ */ -+ virtio_queue_restore_last_avail_idx(vdev, idx); - } else { - virtio_queue_set_last_avail_idx(vdev, idx, state.num); - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-vhost-user-add-Net-prefix-to-internal-state-structur.patch b/SOURCES/kvm-vhost-user-add-Net-prefix-to-internal-state-structur.patch new file mode 100644 index 0000000..0d5d1e8 --- /dev/null +++ b/SOURCES/kvm-vhost-user-add-Net-prefix-to-internal-state-structur.patch @@ -0,0 +1,200 @@ +From 3c3163e2db902b0c585971f73308b6dc90ed45a0 Mon Sep 17 00:00:00 2001 +From: "plai@redhat.com" +Date: Thu, 21 Jun 2018 18:54:36 +0200 +Subject: [PATCH 27/57] vhost-user: add Net prefix to internal state structure + +RH-Author: plai@redhat.com +Message-id: <1529607285-9942-2-git-send-email-plai@redhat.com> +Patchwork-id: 80943 +O-Subject: [RHEL7.6 PATCH BZ 1526645 01/10] vhost-user: add Net prefix to internal state structure +Bugzilla: 1526645 +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Maxime Coquelin +RH-Acked-by: Laurent Vivier + +From: Tiwei Bie + +We are going to introduce a shared vhost user state which +will be named as 'VhostUserState'. So add 'Net' prefix to +the existing internal state structure in the vhost-user +netdev to avoid conflict. + +Signed-off-by: Tiwei Bie +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 703878e2e0975123b1a89a006c0204c469333278) +Signed-off-by: Paul Lai +Signed-off-by: Miroslav Rezanina +--- + net/vhost-user.c | 38 +++++++++++++++++++------------------- + 1 file changed, 19 insertions(+), 19 deletions(-) + +diff --git a/net/vhost-user.c b/net/vhost-user.c +index e0f16c8..fa28aad 100644 +--- a/net/vhost-user.c ++++ b/net/vhost-user.c +@@ -20,38 +20,38 @@ + #include "qemu/option.h" + #include "trace.h" + +-typedef struct VhostUserState { ++typedef struct NetVhostUserState { + NetClientState nc; + CharBackend chr; /* only queue index 0 */ + VHostNetState *vhost_net; + guint watch; + uint64_t acked_features; + bool started; +-} VhostUserState; ++} NetVhostUserState; + + VHostNetState *vhost_user_get_vhost_net(NetClientState *nc) + { +- VhostUserState *s = DO_UPCAST(VhostUserState, nc, nc); ++ NetVhostUserState *s = DO_UPCAST(NetVhostUserState, nc, nc); + assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_USER); + return s->vhost_net; + } + + uint64_t vhost_user_get_acked_features(NetClientState *nc) + { +- VhostUserState *s = DO_UPCAST(VhostUserState, nc, nc); ++ NetVhostUserState *s = DO_UPCAST(NetVhostUserState, nc, nc); + assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_USER); + return s->acked_features; + } + + static void vhost_user_stop(int queues, NetClientState *ncs[]) + { +- VhostUserState *s; ++ NetVhostUserState *s; + int i; + + for (i = 0; i < queues; i++) { + assert(ncs[i]->info->type == NET_CLIENT_DRIVER_VHOST_USER); + +- s = DO_UPCAST(VhostUserState, nc, ncs[i]); ++ s = DO_UPCAST(NetVhostUserState, nc, ncs[i]); + + if (s->vhost_net) { + /* save acked features */ +@@ -68,7 +68,7 @@ static int vhost_user_start(int queues, NetClientState *ncs[], CharBackend *be) + { + VhostNetOptions options; + struct vhost_net *net = NULL; +- VhostUserState *s; ++ NetVhostUserState *s; + int max_queues; + int i; + +@@ -77,7 +77,7 @@ static int vhost_user_start(int queues, NetClientState *ncs[], CharBackend *be) + for (i = 0; i < queues; i++) { + assert(ncs[i]->info->type == NET_CLIENT_DRIVER_VHOST_USER); + +- s = DO_UPCAST(VhostUserState, nc, ncs[i]); ++ s = DO_UPCAST(NetVhostUserState, nc, ncs[i]); + + options.net_backend = ncs[i]; + options.opaque = be; +@@ -123,7 +123,7 @@ static ssize_t vhost_user_receive(NetClientState *nc, const uint8_t *buf, + without GUEST_ANNOUNCE capability. + */ + if (size == 60) { +- VhostUserState *s = DO_UPCAST(VhostUserState, nc, nc); ++ NetVhostUserState *s = DO_UPCAST(NetVhostUserState, nc, nc); + int r; + static int display_rarp_failure = 1; + char mac_addr[6]; +@@ -146,7 +146,7 @@ static ssize_t vhost_user_receive(NetClientState *nc, const uint8_t *buf, + + static void vhost_user_cleanup(NetClientState *nc) + { +- VhostUserState *s = DO_UPCAST(VhostUserState, nc, nc); ++ NetVhostUserState *s = DO_UPCAST(NetVhostUserState, nc, nc); + + if (s->vhost_net) { + vhost_net_cleanup(s->vhost_net); +@@ -180,7 +180,7 @@ static bool vhost_user_has_ufo(NetClientState *nc) + + static NetClientInfo net_vhost_user_info = { + .type = NET_CLIENT_DRIVER_VHOST_USER, +- .size = sizeof(VhostUserState), ++ .size = sizeof(NetVhostUserState), + .receive = vhost_user_receive, + .cleanup = vhost_user_cleanup, + .has_vnet_hdr = vhost_user_has_vnet_hdr, +@@ -190,7 +190,7 @@ static NetClientInfo net_vhost_user_info = { + static gboolean net_vhost_user_watch(GIOChannel *chan, GIOCondition cond, + void *opaque) + { +- VhostUserState *s = opaque; ++ NetVhostUserState *s = opaque; + + qemu_chr_fe_disconnect(&s->chr); + +@@ -203,7 +203,7 @@ static void chr_closed_bh(void *opaque) + { + const char *name = opaque; + NetClientState *ncs[MAX_QUEUE_NUM]; +- VhostUserState *s; ++ NetVhostUserState *s; + Error *err = NULL; + int queues; + +@@ -212,7 +212,7 @@ static void chr_closed_bh(void *opaque) + MAX_QUEUE_NUM); + assert(queues < MAX_QUEUE_NUM); + +- s = DO_UPCAST(VhostUserState, nc, ncs[0]); ++ s = DO_UPCAST(NetVhostUserState, nc, ncs[0]); + + qmp_set_link(name, false, &err); + vhost_user_stop(queues, ncs); +@@ -229,7 +229,7 @@ static void net_vhost_user_event(void *opaque, int event) + { + const char *name = opaque; + NetClientState *ncs[MAX_QUEUE_NUM]; +- VhostUserState *s; ++ NetVhostUserState *s; + Chardev *chr; + Error *err = NULL; + int queues; +@@ -239,7 +239,7 @@ static void net_vhost_user_event(void *opaque, int event) + MAX_QUEUE_NUM); + assert(queues < MAX_QUEUE_NUM); + +- s = DO_UPCAST(VhostUserState, nc, ncs[0]); ++ s = DO_UPCAST(NetVhostUserState, nc, ncs[0]); + chr = qemu_chr_fe_get_driver(&s->chr); + trace_vhost_user_event(chr->label, event); + switch (event) { +@@ -283,7 +283,7 @@ static int net_vhost_user_init(NetClientState *peer, const char *device, + { + Error *err = NULL; + NetClientState *nc, *nc0 = NULL; +- VhostUserState *s; ++ NetVhostUserState *s; + int i; + + assert(name); +@@ -296,7 +296,7 @@ static int net_vhost_user_init(NetClientState *peer, const char *device, + nc->queue_index = i; + if (!nc0) { + nc0 = nc; +- s = DO_UPCAST(VhostUserState, nc, nc); ++ s = DO_UPCAST(NetVhostUserState, nc, nc); + if (!qemu_chr_fe_init(&s->chr, chr, &err)) { + error_report_err(err); + return -1; +@@ -305,7 +305,7 @@ static int net_vhost_user_init(NetClientState *peer, const char *device, + + } + +- s = DO_UPCAST(VhostUserState, nc, nc0); ++ s = DO_UPCAST(NetVhostUserState, nc, nc0); + do { + if (qemu_chr_fe_wait_connected(&s->chr, &err) < 0) { + error_report_err(err); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vhost-user-allow-slave-to-send-fds-via-slave-channel.patch b/SOURCES/kvm-vhost-user-allow-slave-to-send-fds-via-slave-channel.patch new file mode 100644 index 0000000..b827d9b --- /dev/null +++ b/SOURCES/kvm-vhost-user-allow-slave-to-send-fds-via-slave-channel.patch @@ -0,0 +1,144 @@ +From 4395bef7b50eba7711d47a5a9064ef048cdee8d2 Mon Sep 17 00:00:00 2001 +From: "plai@redhat.com" +Date: Thu, 21 Jun 2018 18:54:42 +0200 +Subject: [PATCH 33/57] vhost-user: allow slave to send fds via slave channel + +RH-Author: plai@redhat.com +Message-id: <1529607285-9942-8-git-send-email-plai@redhat.com> +Patchwork-id: 80935 +O-Subject: [RHEL7.6 PATCH BZ 1526645 07/10] vhost-user: allow slave to send fds via slave channel +Bugzilla: 1526645 +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Maxime Coquelin +RH-Acked-by: Laurent Vivier + +From: Tiwei Bie + +Introduce VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD protocol +feature to allow slave to send at most 8 descriptors +in each message to master via ancillary data using the +slave channel. + +Suggested-by: Michael S. Tsirkin +Signed-off-by: Tiwei Bie +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 5f57fbeaaf7c4cd33152d7f2e449caab4d4209d9) +Signed-off-by: Paul Lai +Signed-off-by: Miroslav Rezanina +--- + docs/interop/vhost-user.txt | 5 +++++ + hw/virtio/vhost-user.c | 27 +++++++++++++++++---------- + 2 files changed, 22 insertions(+), 10 deletions(-) + +diff --git a/docs/interop/vhost-user.txt b/docs/interop/vhost-user.txt +index 534caab..682a683 100644 +--- a/docs/interop/vhost-user.txt ++++ b/docs/interop/vhost-user.txt +@@ -367,6 +367,10 @@ The fd is provided via VHOST_USER_SET_SLAVE_REQ_FD ancillary data. + A slave may then send VHOST_USER_SLAVE_* messages to the master + using this fd communication channel. + ++If VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD protocol feature is negotiated, ++slave can send file descriptors (at most 8 descriptors in each message) ++to master via ancillary data using this fd communication channel. ++ + Protocol features + ----------------- + +@@ -380,6 +384,7 @@ Protocol features + #define VHOST_USER_PROTOCOL_F_CRYPTO_SESSION 7 + #define VHOST_USER_PROTOCOL_F_PAGEFAULT 8 + #define VHOST_USER_PROTOCOL_F_CONFIG 9 ++#define VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD 10 + + Master message types + -------------------- +diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c +index ebb946a..e8027ad 100644 +--- a/hw/virtio/vhost-user.c ++++ b/hw/virtio/vhost-user.c +@@ -30,6 +30,7 @@ + + #define VHOST_MEMORY_MAX_NREGIONS 8 + #define VHOST_USER_F_PROTOCOL_FEATURES 30 ++#define VHOST_USER_SLAVE_MAX_FDS 8 + + /* + * Maximum size of virtio device config space +@@ -47,6 +48,7 @@ enum VhostUserProtocolFeature { + VHOST_USER_PROTOCOL_F_CRYPTO_SESSION = 7, + VHOST_USER_PROTOCOL_F_PAGEFAULT = 8, + VHOST_USER_PROTOCOL_F_CONFIG = 9, ++ VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD = 10, + VHOST_USER_PROTOCOL_F_MAX + }; + +@@ -854,10 +856,10 @@ static void slave_read(void *opaque) + int size, ret = 0; + struct iovec iov; + struct msghdr msgh; +- int fd = -1; ++ int fd[VHOST_USER_SLAVE_MAX_FDS]; + char control[CMSG_SPACE(sizeof(fd))]; + struct cmsghdr *cmsg; +- size_t fdsize; ++ int i, fdsize = 0; + + memset(&msgh, 0, sizeof(msgh)); + msgh.msg_iov = &iov; +@@ -865,6 +867,8 @@ static void slave_read(void *opaque) + msgh.msg_control = control; + msgh.msg_controllen = sizeof(control); + ++ memset(fd, -1, sizeof(fd)); ++ + /* Read header */ + iov.iov_base = &hdr; + iov.iov_len = VHOST_USER_HDR_SIZE; +@@ -885,7 +889,7 @@ static void slave_read(void *opaque) + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS) { + fdsize = cmsg->cmsg_len - CMSG_LEN(0); +- memcpy(&fd, CMSG_DATA(cmsg), fdsize); ++ memcpy(fd, CMSG_DATA(cmsg), fdsize); + break; + } + } +@@ -913,14 +917,15 @@ static void slave_read(void *opaque) + break; + default: + error_report("Received unexpected msg type."); +- if (fd != -1) { +- close(fd); +- } + ret = -EINVAL; + } + +- /* Message handlers need to make sure that fd will be consumed. */ +- fd = -1; ++ /* Close the remaining file descriptors. */ ++ for (i = 0; i < fdsize; i++) { ++ if (fd[i] != -1) { ++ close(fd[i]); ++ } ++ } + + /* + * REPLY_ACK feature handling. Other reply types has to be managed +@@ -954,8 +959,10 @@ err: + qemu_set_fd_handler(u->slave_fd, NULL, NULL, NULL); + close(u->slave_fd); + u->slave_fd = -1; +- if (fd != -1) { +- close(fd); ++ for (i = 0; i < fdsize; i++) { ++ if (fd[i] != -1) { ++ close(fd[i]); ++ } + } + return; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vhost-user-bridge-support-host-notifier.patch b/SOURCES/kvm-vhost-user-bridge-support-host-notifier.patch new file mode 100644 index 0000000..bd366fe --- /dev/null +++ b/SOURCES/kvm-vhost-user-bridge-support-host-notifier.patch @@ -0,0 +1,214 @@ +From c331104889ecc51581ead4a154d37ad4d054ca73 Mon Sep 17 00:00:00 2001 +From: "plai@redhat.com" +Date: Thu, 21 Jun 2018 18:54:40 +0200 +Subject: [PATCH 31/57] vhost-user-bridge: support host notifier + +RH-Author: plai@redhat.com +Message-id: <1529607285-9942-6-git-send-email-plai@redhat.com> +Patchwork-id: 80934 +O-Subject: [RHEL7.6 PATCH BZ 1526645 05/10] vhost-user-bridge: support host notifier +Bugzilla: 1526645 +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Maxime Coquelin +RH-Acked-by: Laurent Vivier + +From: Tiwei Bie + +This patch introduces the host notifier support in +vhost-user-bridge. A new option (-H) is added to use +the host notifier. This is mainly used to test the +host notifier implementation in vhost user. + +Signed-off-by: Tiwei Bie +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit e3af2928f8270498097af163bb023b633c0d8d1c) +Signed-off-by: Paul Lai +Signed-off-by: Miroslav Rezanina +--- + tests/vhost-user-bridge.c | 98 +++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 95 insertions(+), 3 deletions(-) + +diff --git a/tests/vhost-user-bridge.c b/tests/vhost-user-bridge.c +index e0605a5..0884294 100644 +--- a/tests/vhost-user-bridge.c ++++ b/tests/vhost-user-bridge.c +@@ -29,6 +29,7 @@ + + #define _FILE_OFFSET_BITS 64 + ++#include "qemu/atomic.h" + #include "qemu/osdep.h" + #include "qemu/iov.h" + #include "standard-headers/linux/virtio_net.h" +@@ -65,6 +66,11 @@ typedef struct VubrDev { + int sock; + int ready; + int quit; ++ struct { ++ int fd; ++ void *addr; ++ pthread_t thread; ++ } notifier; + } VubrDev; + + static void +@@ -445,14 +451,22 @@ static uint64_t + vubr_get_features(VuDev *dev) + { + return 1ULL << VIRTIO_NET_F_GUEST_ANNOUNCE | +- 1ULL << VIRTIO_NET_F_MRG_RXBUF; ++ 1ULL << VIRTIO_NET_F_MRG_RXBUF | ++ 1ULL << VIRTIO_F_VERSION_1; + } + + static void + vubr_queue_set_started(VuDev *dev, int qidx, bool started) + { ++ VubrDev *vubr = container_of(dev, VubrDev, vudev); + VuVirtq *vq = vu_get_queue(dev, qidx); + ++ if (started && vubr->notifier.fd >= 0) { ++ vu_set_queue_host_notifier(dev, vq, vubr->notifier.fd, ++ getpagesize(), ++ qidx * getpagesize()); ++ } ++ + if (qidx % 2 == 1) { + vu_set_queue_handler(dev, vq, started ? vubr_handle_tx : NULL); + } +@@ -522,6 +536,8 @@ vubr_new(const char *path, bool client) + vubr_die("socket"); + } + ++ dev->notifier.fd = -1; ++ + un.sun_family = AF_UNIX; + strcpy(un.sun_path, path); + len = sizeof(un.sun_family) + strlen(path); +@@ -559,6 +575,73 @@ vubr_new(const char *path, bool client) + return dev; + } + ++static void *notifier_thread(void *arg) ++{ ++ VuDev *dev = (VuDev *)arg; ++ VubrDev *vubr = container_of(dev, VubrDev, vudev); ++ int pagesize = getpagesize(); ++ int qidx; ++ ++ while (true) { ++ for (qidx = 0; qidx < VHOST_MAX_NR_VIRTQUEUE; qidx++) { ++ uint16_t *n = vubr->notifier.addr + pagesize * qidx; ++ ++ if (*n == qidx) { ++ *n = 0xffff; ++ /* We won't miss notifications if we reset ++ * the memory first. */ ++ smp_mb(); ++ ++ DPRINT("Got a notification for queue%d via host notifier.\n", ++ qidx); ++ ++ if (qidx % 2 == 1) { ++ vubr_handle_tx(dev, qidx); ++ } ++ } ++ usleep(1000); ++ } ++ } ++ ++ return NULL; ++} ++ ++static void ++vubr_host_notifier_setup(VubrDev *dev) ++{ ++ char template[] = "/tmp/vubr-XXXXXX"; ++ pthread_t thread; ++ size_t length; ++ void *addr; ++ int fd; ++ ++ length = getpagesize() * VHOST_MAX_NR_VIRTQUEUE; ++ ++ fd = mkstemp(template); ++ if (fd < 0) { ++ vubr_die("mkstemp()"); ++ } ++ ++ if (posix_fallocate(fd, 0, length) != 0) { ++ vubr_die("posix_fallocate()"); ++ } ++ ++ addr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); ++ if (addr == MAP_FAILED) { ++ vubr_die("mmap()"); ++ } ++ ++ memset(addr, 0xff, length); ++ ++ if (pthread_create(&thread, NULL, notifier_thread, &dev->vudev) != 0) { ++ vubr_die("pthread_create()"); ++ } ++ ++ dev->notifier.fd = fd; ++ dev->notifier.addr = addr; ++ dev->notifier.thread = thread; ++} ++ + static void + vubr_set_host(struct sockaddr_in *saddr, const char *host) + { +@@ -673,8 +756,9 @@ main(int argc, char *argv[]) + VubrDev *dev; + int opt; + bool client = false; ++ bool host_notifier = false; + +- while ((opt = getopt(argc, argv, "l:r:u:c")) != -1) { ++ while ((opt = getopt(argc, argv, "l:r:u:cH")) != -1) { + + switch (opt) { + case 'l': +@@ -693,6 +777,9 @@ main(int argc, char *argv[]) + case 'c': + client = true; + break; ++ case 'H': ++ host_notifier = true; ++ break; + default: + goto out; + } +@@ -708,6 +795,10 @@ main(int argc, char *argv[]) + return 1; + } + ++ if (host_notifier) { ++ vubr_host_notifier_setup(dev); ++ } ++ + vubr_backend_udp_setup(dev, lhost, lport, rhost, rport); + vubr_run(dev); + +@@ -717,7 +808,7 @@ main(int argc, char *argv[]) + + out: + fprintf(stderr, "Usage: %s ", argv[0]); +- fprintf(stderr, "[-c] [-u ud_socket_path] [-l lhost:lport] [-r rhost:rport]\n"); ++ fprintf(stderr, "[-c] [-H] [-u ud_socket_path] [-l lhost:lport] [-r rhost:rport]\n"); + fprintf(stderr, "\t-u path to unix doman socket. default: %s\n", + DEFAULT_UD_SOCKET); + fprintf(stderr, "\t-l local host and port. default: %s:%s\n", +@@ -725,6 +816,7 @@ out: + fprintf(stderr, "\t-r remote host and port. default: %s:%s\n", + DEFAULT_RHOST, DEFAULT_RPORT); + fprintf(stderr, "\t-c client mode\n"); ++ fprintf(stderr, "\t-H use host notifier\n"); + + return 1; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vhost-user-introduce-shared-vhost-user-state.patch b/SOURCES/kvm-vhost-user-introduce-shared-vhost-user-state.patch new file mode 100644 index 0000000..5e72573 --- /dev/null +++ b/SOURCES/kvm-vhost-user-introduce-shared-vhost-user-state.patch @@ -0,0 +1,560 @@ +From c957ec8a9629189e188747c48ed830599457e7c0 Mon Sep 17 00:00:00 2001 +From: "plai@redhat.com" +Date: Thu, 21 Jun 2018 18:54:43 +0200 +Subject: [PATCH 34/57] vhost-user: introduce shared vhost-user state + +RH-Author: plai@redhat.com +Message-id: <1529607285-9942-9-git-send-email-plai@redhat.com> +Patchwork-id: 80942 +O-Subject: [RHEL7.6 PATCH BZ 1526645 08/10] vhost-user: introduce shared vhost-user state +Bugzilla: 1526645 +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Maxime Coquelin +RH-Acked-by: Laurent Vivier + +From: Tiwei Bie + +When multi queue is enabled e.g. for a virtio-net device, +each queue pair will have a vhost_dev, and the only thing +shared between vhost devs currently is the chardev. This +patch introduces a vhost-user state structure which will +be shared by all vhost devs of the same virtio device. + +Signed-off-by: Tiwei Bie +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 4d0cf552d3a9585f380e8abdc313e4d416a56aa0) +Signed-off-by: Paul Lai +Signed-off-by: Miroslav Rezanina +--- + backends/cryptodev-vhost-user.c | 20 ++++++++++++++++- + hw/block/vhost-user-blk.c | 22 ++++++++++++++++++- + hw/scsi/vhost-user-scsi.c | 20 ++++++++++++++++- + hw/virtio/Makefile.objs | 2 +- + hw/virtio/vhost-stub.c | 10 +++++++++ + hw/virtio/vhost-user.c | 31 ++++++++++++++++++-------- + include/hw/virtio/vhost-user-blk.h | 2 ++ + include/hw/virtio/vhost-user-scsi.h | 2 ++ + include/hw/virtio/vhost-user.h | 20 +++++++++++++++++ + net/vhost-user.c | 44 ++++++++++++++++++++++++++++++------- + 10 files changed, 152 insertions(+), 21 deletions(-) + create mode 100644 include/hw/virtio/vhost-user.h + +diff --git a/backends/cryptodev-vhost-user.c b/backends/cryptodev-vhost-user.c +index 862d4f2..d52dacc 100644 +--- a/backends/cryptodev-vhost-user.c ++++ b/backends/cryptodev-vhost-user.c +@@ -26,6 +26,7 @@ + #include "qapi/error.h" + #include "qapi/qmp/qerror.h" + #include "qemu/error-report.h" ++#include "hw/virtio/vhost-user.h" + #include "standard-headers/linux/virtio_crypto.h" + #include "sysemu/cryptodev-vhost.h" + #include "chardev/char-fe.h" +@@ -46,6 +47,7 @@ + typedef struct CryptoDevBackendVhostUser { + CryptoDevBackend parent_obj; + ++ VhostUserState *vhost_user; + CharBackend chr; + char *chr_name; + bool opened; +@@ -102,7 +104,7 @@ cryptodev_vhost_user_start(int queues, + continue; + } + +- options.opaque = &s->chr; ++ options.opaque = s->vhost_user; + options.backend_type = VHOST_BACKEND_TYPE_USER; + options.cc = b->conf.peers.ccs[i]; + s->vhost_crypto[i] = cryptodev_vhost_init(&options); +@@ -185,6 +187,7 @@ static void cryptodev_vhost_user_init( + size_t i; + Error *local_err = NULL; + Chardev *chr; ++ VhostUserState *user; + CryptoDevBackendClient *cc; + CryptoDevBackendVhostUser *s = + CRYPTODEV_BACKEND_VHOST_USER(backend); +@@ -215,6 +218,15 @@ static void cryptodev_vhost_user_init( + } + } + ++ user = vhost_user_init(); ++ if (!user) { ++ error_setg(errp, "Failed to init vhost_user"); ++ return; ++ } ++ ++ user->chr = &s->chr; ++ s->vhost_user = user; ++ + qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, + cryptodev_vhost_user_event, NULL, s, NULL, true); + +@@ -299,6 +311,12 @@ static void cryptodev_vhost_user_cleanup( + backend->conf.peers.ccs[i] = NULL; + } + } ++ ++ if (s->vhost_user) { ++ vhost_user_cleanup(s->vhost_user); ++ g_free(s->vhost_user); ++ s->vhost_user = NULL; ++ } + } + + static void cryptodev_vhost_user_set_chardev(Object *obj, +diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c +index 262baca..4021d71 100644 +--- a/hw/block/vhost-user-blk.c ++++ b/hw/block/vhost-user-blk.c +@@ -229,6 +229,7 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) + { + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostUserBlk *s = VHOST_USER_BLK(vdev); ++ VhostUserState *user; + int i, ret; + + if (!s->chardev.chr) { +@@ -246,6 +247,15 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) + return; + } + ++ user = vhost_user_init(); ++ if (!user) { ++ error_setg(errp, "vhost-user-blk: failed to init vhost_user"); ++ return; ++ } ++ ++ user->chr = &s->chardev; ++ s->vhost_user = user; ++ + virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK, + sizeof(struct virtio_blk_config)); + +@@ -261,7 +271,7 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) + + vhost_dev_set_config_notifier(&s->dev, &blk_ops); + +- ret = vhost_dev_init(&s->dev, &s->chardev, VHOST_BACKEND_TYPE_USER, 0); ++ ret = vhost_dev_init(&s->dev, s->vhost_user, VHOST_BACKEND_TYPE_USER, 0); + if (ret < 0) { + error_setg(errp, "vhost-user-blk: vhost initialization failed: %s", + strerror(-ret)); +@@ -286,6 +296,10 @@ vhost_err: + virtio_err: + g_free(s->dev.vqs); + virtio_cleanup(vdev); ++ ++ vhost_user_cleanup(user); ++ g_free(user); ++ s->vhost_user = NULL; + } + + static void vhost_user_blk_device_unrealize(DeviceState *dev, Error **errp) +@@ -297,6 +311,12 @@ static void vhost_user_blk_device_unrealize(DeviceState *dev, Error **errp) + vhost_dev_cleanup(&s->dev); + g_free(s->dev.vqs); + virtio_cleanup(vdev); ++ ++ if (s->vhost_user) { ++ vhost_user_cleanup(s->vhost_user); ++ g_free(s->vhost_user); ++ s->vhost_user = NULL; ++ } + } + + static void vhost_user_blk_instance_init(Object *obj) +diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c +index 9389ed4..9355cfd 100644 +--- a/hw/scsi/vhost-user-scsi.c ++++ b/hw/scsi/vhost-user-scsi.c +@@ -69,6 +69,7 @@ static void vhost_user_scsi_realize(DeviceState *dev, Error **errp) + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev); + VHostUserSCSI *s = VHOST_USER_SCSI(dev); + VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); ++ VhostUserState *user; + Error *err = NULL; + int ret; + +@@ -85,19 +86,30 @@ static void vhost_user_scsi_realize(DeviceState *dev, Error **errp) + return; + } + ++ user = vhost_user_init(); ++ if (!user) { ++ error_setg(errp, "vhost-user-scsi: failed to init vhost_user"); ++ return; ++ } ++ user->chr = &vs->conf.chardev; ++ + vsc->dev.nvqs = 2 + vs->conf.num_queues; + vsc->dev.vqs = g_new(struct vhost_virtqueue, vsc->dev.nvqs); + vsc->dev.vq_index = 0; + vsc->dev.backend_features = 0; + +- ret = vhost_dev_init(&vsc->dev, (void *)&vs->conf.chardev, ++ ret = vhost_dev_init(&vsc->dev, user, + VHOST_BACKEND_TYPE_USER, 0); + if (ret < 0) { + error_setg(errp, "vhost-user-scsi: vhost initialization failed: %s", + strerror(-ret)); ++ vhost_user_cleanup(user); ++ g_free(user); + return; + } + ++ s->vhost_user = user; ++ + /* Channel and lun both are 0 for bootable vhost-user-scsi disk */ + vsc->channel = 0; + vsc->lun = 0; +@@ -117,6 +129,12 @@ static void vhost_user_scsi_unrealize(DeviceState *dev, Error **errp) + g_free(vsc->dev.vqs); + + virtio_scsi_common_unrealize(dev, errp); ++ ++ if (s->vhost_user) { ++ vhost_user_cleanup(s->vhost_user); ++ g_free(s->vhost_user); ++ s->vhost_user = NULL; ++ } + } + + static uint64_t vhost_user_scsi_get_features(VirtIODevice *vdev, +diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs +index a5a0936..00c6696 100644 +--- a/hw/virtio/Makefile.objs ++++ b/hw/virtio/Makefile.objs +@@ -12,5 +12,5 @@ obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock.o + #obj-$(CONFIG_VIRTIO_PCI) += virtio-crypto-pci.o + endif + +-common-obj-$(call lnot,$(CONFIG_LINUX)) += vhost-stub.o ++common-obj-$(call lnot,$(call land,$(CONFIG_VIRTIO),$(CONFIG_LINUX))) += vhost-stub.o + common-obj-$(CONFIG_ALL) += vhost-stub.o +diff --git a/hw/virtio/vhost-stub.c b/hw/virtio/vhost-stub.c +index 2d76cde..049089b 100644 +--- a/hw/virtio/vhost-stub.c ++++ b/hw/virtio/vhost-stub.c +@@ -1,7 +1,17 @@ + #include "qemu/osdep.h" + #include "hw/virtio/vhost.h" ++#include "hw/virtio/vhost-user.h" + + bool vhost_has_free_slot(void) + { + return true; + } ++ ++VhostUserState *vhost_user_init(void) ++{ ++ return NULL; ++} ++ ++void vhost_user_cleanup(VhostUserState *user) ++{ ++} +diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c +index e8027ad..a715c5c 100644 +--- a/hw/virtio/vhost-user.c ++++ b/hw/virtio/vhost-user.c +@@ -11,6 +11,7 @@ + #include "qemu/osdep.h" + #include "qapi/error.h" + #include "hw/virtio/vhost.h" ++#include "hw/virtio/vhost-user.h" + #include "hw/virtio/vhost-backend.h" + #include "hw/virtio/virtio-net.h" + #include "chardev/char-fe.h" +@@ -175,7 +176,8 @@ static VhostUserMsg m __attribute__ ((unused)); + + struct vhost_user { + struct vhost_dev *dev; +- CharBackend *chr; ++ /* Shared between vhost devs of the same virtio device */ ++ VhostUserState *user; + int slave_fd; + NotifierWithReturn postcopy_notifier; + struct PostCopyFD postcopy_fd; +@@ -201,7 +203,7 @@ static bool ioeventfd_enabled(void) + static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg) + { + struct vhost_user *u = dev->opaque; +- CharBackend *chr = u->chr; ++ CharBackend *chr = u->user->chr; + uint8_t *p = (uint8_t *) msg; + int r, size = VHOST_USER_HDR_SIZE; + +@@ -287,7 +289,7 @@ static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg, + int *fds, int fd_num) + { + struct vhost_user *u = dev->opaque; +- CharBackend *chr = u->chr; ++ CharBackend *chr = u->user->chr; + int ret, size = VHOST_USER_HDR_SIZE + msg->hdr.size; + + /* +@@ -1090,7 +1092,7 @@ static int vhost_user_postcopy_waker(struct PostCopyFD *pcfd, RAMBlock *rb, + static int vhost_user_postcopy_advise(struct vhost_dev *dev, Error **errp) + { + struct vhost_user *u = dev->opaque; +- CharBackend *chr = u->chr; ++ CharBackend *chr = u->user->chr; + int ufd; + VhostUserMsg msg = { + .hdr.request = VHOST_USER_POSTCOPY_ADVISE, +@@ -1228,7 +1230,7 @@ static int vhost_user_postcopy_notifier(NotifierWithReturn *notifier, + return 0; + } + +-static int vhost_user_init(struct vhost_dev *dev, void *opaque) ++static int vhost_user_backend_init(struct vhost_dev *dev, void *opaque) + { + uint64_t features, protocol_features; + struct vhost_user *u; +@@ -1237,7 +1239,7 @@ static int vhost_user_init(struct vhost_dev *dev, void *opaque) + assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER); + + u = g_new0(struct vhost_user, 1); +- u->chr = opaque; ++ u->user = opaque; + u->slave_fd = -1; + u->dev = dev; + dev->opaque = u; +@@ -1313,7 +1315,7 @@ static int vhost_user_init(struct vhost_dev *dev, void *opaque) + return 0; + } + +-static int vhost_user_cleanup(struct vhost_dev *dev) ++static int vhost_user_backend_cleanup(struct vhost_dev *dev) + { + struct vhost_user *u; + +@@ -1637,10 +1639,21 @@ static bool vhost_user_mem_section_filter(struct vhost_dev *dev, + return result; + } + ++VhostUserState *vhost_user_init(void) ++{ ++ VhostUserState *user = g_new0(struct VhostUserState, 1); ++ ++ return user; ++} ++ ++void vhost_user_cleanup(VhostUserState *user) ++{ ++} ++ + const VhostOps user_ops = { + .backend_type = VHOST_BACKEND_TYPE_USER, +- .vhost_backend_init = vhost_user_init, +- .vhost_backend_cleanup = vhost_user_cleanup, ++ .vhost_backend_init = vhost_user_backend_init, ++ .vhost_backend_cleanup = vhost_user_backend_cleanup, + .vhost_backend_memslots_limit = vhost_user_memslots_limit, + .vhost_set_log_base = vhost_user_set_log_base, + .vhost_set_mem_table = vhost_user_set_mem_table, +diff --git a/include/hw/virtio/vhost-user-blk.h b/include/hw/virtio/vhost-user-blk.h +index 5804cc9..f1258ae 100644 +--- a/include/hw/virtio/vhost-user-blk.h ++++ b/include/hw/virtio/vhost-user-blk.h +@@ -21,6 +21,7 @@ + #include "hw/block/block.h" + #include "chardev/char-fe.h" + #include "hw/virtio/vhost.h" ++#include "hw/virtio/vhost-user.h" + + #define TYPE_VHOST_USER_BLK "vhost-user-blk" + #define VHOST_USER_BLK(obj) \ +@@ -36,6 +37,7 @@ typedef struct VHostUserBlk { + uint32_t config_wce; + uint32_t config_ro; + struct vhost_dev dev; ++ VhostUserState *vhost_user; + } VHostUserBlk; + + #endif +diff --git a/include/hw/virtio/vhost-user-scsi.h b/include/hw/virtio/vhost-user-scsi.h +index 01861f7..3ec34ae 100644 +--- a/include/hw/virtio/vhost-user-scsi.h ++++ b/include/hw/virtio/vhost-user-scsi.h +@@ -21,6 +21,7 @@ + #include "hw/qdev.h" + #include "hw/virtio/virtio-scsi.h" + #include "hw/virtio/vhost.h" ++#include "hw/virtio/vhost-user.h" + #include "hw/virtio/vhost-scsi-common.h" + + #define TYPE_VHOST_USER_SCSI "vhost-user-scsi" +@@ -30,6 +31,7 @@ + typedef struct VHostUserSCSI { + VHostSCSICommon parent_obj; + uint64_t host_features; ++ VhostUserState *vhost_user; + } VHostUserSCSI; + + #endif /* VHOST_USER_SCSI_H */ +diff --git a/include/hw/virtio/vhost-user.h b/include/hw/virtio/vhost-user.h +new file mode 100644 +index 0000000..eb8bc0d +--- /dev/null ++++ b/include/hw/virtio/vhost-user.h +@@ -0,0 +1,20 @@ ++/* ++ * Copyright (c) 2017-2018 Intel Corporation ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2. ++ * See the COPYING file in the top-level directory. ++ */ ++ ++#ifndef HW_VIRTIO_VHOST_USER_H ++#define HW_VIRTIO_VHOST_USER_H ++ ++#include "chardev/char-fe.h" ++ ++typedef struct VhostUserState { ++ CharBackend *chr; ++} VhostUserState; ++ ++VhostUserState *vhost_user_init(void); ++void vhost_user_cleanup(VhostUserState *user); ++ ++#endif +diff --git a/net/vhost-user.c b/net/vhost-user.c +index fa28aad..608b837 100644 +--- a/net/vhost-user.c ++++ b/net/vhost-user.c +@@ -12,6 +12,7 @@ + #include "clients.h" + #include "net/vhost_net.h" + #include "net/vhost-user.h" ++#include "hw/virtio/vhost-user.h" + #include "chardev/char-fe.h" + #include "qapi/error.h" + #include "qapi/qapi-commands-net.h" +@@ -23,6 +24,7 @@ + typedef struct NetVhostUserState { + NetClientState nc; + CharBackend chr; /* only queue index 0 */ ++ VhostUserState *vhost_user; + VHostNetState *vhost_net; + guint watch; + uint64_t acked_features; +@@ -64,7 +66,8 @@ static void vhost_user_stop(int queues, NetClientState *ncs[]) + } + } + +-static int vhost_user_start(int queues, NetClientState *ncs[], CharBackend *be) ++static int vhost_user_start(int queues, NetClientState *ncs[], ++ VhostUserState *be) + { + VhostNetOptions options; + struct vhost_net *net = NULL; +@@ -144,7 +147,7 @@ static ssize_t vhost_user_receive(NetClientState *nc, const uint8_t *buf, + return size; + } + +-static void vhost_user_cleanup(NetClientState *nc) ++static void net_vhost_user_cleanup(NetClientState *nc) + { + NetVhostUserState *s = DO_UPCAST(NetVhostUserState, nc, nc); + +@@ -159,6 +162,11 @@ static void vhost_user_cleanup(NetClientState *nc) + s->watch = 0; + } + qemu_chr_fe_deinit(&s->chr, true); ++ if (s->vhost_user) { ++ vhost_user_cleanup(s->vhost_user); ++ g_free(s->vhost_user); ++ s->vhost_user = NULL; ++ } + } + + qemu_purge_queued_packets(nc); +@@ -182,7 +190,7 @@ static NetClientInfo net_vhost_user_info = { + .type = NET_CLIENT_DRIVER_VHOST_USER, + .size = sizeof(NetVhostUserState), + .receive = vhost_user_receive, +- .cleanup = vhost_user_cleanup, ++ .cleanup = net_vhost_user_cleanup, + .has_vnet_hdr = vhost_user_has_vnet_hdr, + .has_ufo = vhost_user_has_ufo, + }; +@@ -244,7 +252,7 @@ static void net_vhost_user_event(void *opaque, int event) + trace_vhost_user_event(chr->label, event); + switch (event) { + case CHR_EVENT_OPENED: +- if (vhost_user_start(queues, ncs, &s->chr) < 0) { ++ if (vhost_user_start(queues, ncs, s->vhost_user) < 0) { + qemu_chr_fe_disconnect(&s->chr); + return; + } +@@ -283,12 +291,19 @@ static int net_vhost_user_init(NetClientState *peer, const char *device, + { + Error *err = NULL; + NetClientState *nc, *nc0 = NULL; +- NetVhostUserState *s; ++ VhostUserState *user = NULL; ++ NetVhostUserState *s = NULL; + int i; + + assert(name); + assert(queues > 0); + ++ user = vhost_user_init(); ++ if (!user) { ++ error_report("failed to init vhost_user"); ++ goto err; ++ } ++ + for (i = 0; i < queues; i++) { + nc = qemu_new_net_client(&net_vhost_user_info, peer, device, name); + snprintf(nc->info_str, sizeof(nc->info_str), "vhost-user%d to %s", +@@ -299,17 +314,19 @@ static int net_vhost_user_init(NetClientState *peer, const char *device, + s = DO_UPCAST(NetVhostUserState, nc, nc); + if (!qemu_chr_fe_init(&s->chr, chr, &err)) { + error_report_err(err); +- return -1; ++ goto err; + } ++ user->chr = &s->chr; + } +- ++ s = DO_UPCAST(NetVhostUserState, nc, nc); ++ s->vhost_user = user; + } + + s = DO_UPCAST(NetVhostUserState, nc, nc0); + do { + if (qemu_chr_fe_wait_connected(&s->chr, &err) < 0) { + error_report_err(err); +- return -1; ++ goto err; + } + qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, + net_vhost_user_event, NULL, nc0->name, NULL, +@@ -319,6 +336,17 @@ static int net_vhost_user_init(NetClientState *peer, const char *device, + assert(s->vhost_net); + + return 0; ++ ++err: ++ if (user) { ++ vhost_user_cleanup(user); ++ g_free(user); ++ if (s) { ++ s->vhost_user = NULL; ++ } ++ } ++ ++ return -1; + } + + static Chardev *net_vhost_claim_chardev( +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vhost-user-support-receiving-file-descriptors-in-sla.patch b/SOURCES/kvm-vhost-user-support-receiving-file-descriptors-in-sla.patch new file mode 100644 index 0000000..0335f1c --- /dev/null +++ b/SOURCES/kvm-vhost-user-support-receiving-file-descriptors-in-sla.patch @@ -0,0 +1,106 @@ +From f625d197050d05d33172bd5e93d044155208befb Mon Sep 17 00:00:00 2001 +From: "plai@redhat.com" +Date: Thu, 21 Jun 2018 18:54:38 +0200 +Subject: [PATCH 29/57] vhost-user: support receiving file descriptors in + slave_read + +RH-Author: plai@redhat.com +Message-id: <1529607285-9942-4-git-send-email-plai@redhat.com> +Patchwork-id: 80933 +O-Subject: [RHEL7.6 PATCH BZ 1526645 03/10] vhost-user: support receiving file descriptors in slave_read +Bugzilla: 1526645 +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Maxime Coquelin +RH-Acked-by: Laurent Vivier + +From: Tiwei Bie + +Signed-off-by: Tiwei Bie +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 1f3a4519b1c107b5db2434b30638353978366b4d) +Signed-off-by: Paul Lai +Signed-off-by: Miroslav Rezanina +--- + hw/virtio/vhost-user.c | 41 ++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 40 insertions(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c +index 38da869..85d8fd2 100644 +--- a/hw/virtio/vhost-user.c ++++ b/hw/virtio/vhost-user.c +@@ -852,14 +852,44 @@ static void slave_read(void *opaque) + VhostUserHeader hdr = { 0, }; + VhostUserPayload payload = { 0, }; + int size, ret = 0; ++ struct iovec iov; ++ struct msghdr msgh; ++ int fd = -1; ++ char control[CMSG_SPACE(sizeof(fd))]; ++ struct cmsghdr *cmsg; ++ size_t fdsize; ++ ++ memset(&msgh, 0, sizeof(msgh)); ++ msgh.msg_iov = &iov; ++ msgh.msg_iovlen = 1; ++ msgh.msg_control = control; ++ msgh.msg_controllen = sizeof(control); + + /* Read header */ +- size = read(u->slave_fd, &hdr, VHOST_USER_HDR_SIZE); ++ iov.iov_base = &hdr; ++ iov.iov_len = VHOST_USER_HDR_SIZE; ++ ++ size = recvmsg(u->slave_fd, &msgh, 0); + if (size != VHOST_USER_HDR_SIZE) { + error_report("Failed to read from slave."); + goto err; + } + ++ if (msgh.msg_flags & MSG_CTRUNC) { ++ error_report("Truncated message."); ++ goto err; ++ } ++ ++ for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; ++ cmsg = CMSG_NXTHDR(&msgh, cmsg)) { ++ if (cmsg->cmsg_level == SOL_SOCKET && ++ cmsg->cmsg_type == SCM_RIGHTS) { ++ fdsize = cmsg->cmsg_len - CMSG_LEN(0); ++ memcpy(&fd, CMSG_DATA(cmsg), fdsize); ++ break; ++ } ++ } ++ + if (hdr.size > VHOST_USER_PAYLOAD_SIZE) { + error_report("Failed to read msg header." + " Size %d exceeds the maximum %zu.", hdr.size, +@@ -883,9 +913,15 @@ static void slave_read(void *opaque) + break; + default: + error_report("Received unexpected msg type."); ++ if (fd != -1) { ++ close(fd); ++ } + ret = -EINVAL; + } + ++ /* Message handlers need to make sure that fd will be consumed. */ ++ fd = -1; ++ + /* + * REPLY_ACK feature handling. Other reply types has to be managed + * directly in their request handlers. +@@ -918,6 +954,9 @@ err: + qemu_set_fd_handler(u->slave_fd, NULL, NULL, NULL); + close(u->slave_fd); + u->slave_fd = -1; ++ if (fd != -1) { ++ close(fd); ++ } + return; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vhost-user-support-registering-external-host-notifie.patch b/SOURCES/kvm-vhost-user-support-registering-external-host-notifie.patch new file mode 100644 index 0000000..8b013d9 --- /dev/null +++ b/SOURCES/kvm-vhost-user-support-registering-external-host-notifie.patch @@ -0,0 +1,314 @@ +From 3a5f44900a64ea2bdf809f1a8df8a4a255dbe014 Mon Sep 17 00:00:00 2001 +From: "plai@redhat.com" +Date: Thu, 21 Jun 2018 18:54:44 +0200 +Subject: [PATCH 35/57] vhost-user: support registering external host notifiers + +RH-Author: plai@redhat.com +Message-id: <1529607285-9942-10-git-send-email-plai@redhat.com> +Patchwork-id: 80940 +O-Subject: [RHEL7.6 PATCH BZ 1526645 09/10] vhost-user: support registering external host notifiers +Bugzilla: 1526645 +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Maxime Coquelin +RH-Acked-by: Laurent Vivier + +From: Tiwei Bie + +This patch introduces VHOST_USER_PROTOCOL_F_HOST_NOTIFIER. +With this feature negotiated, vhost-user backend can register +memory region based host notifiers. And it will allow the guest +driver in the VM to notify the hardware accelerator at the +vhost-user backend directly. + +Signed-off-by: Tiwei Bie +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 44866521bd6ea8e5152a87664dea1eee90c9438b) +Signed-off-by: Paul Lai +Signed-off-by: Miroslav Rezanina +--- + docs/interop/vhost-user.txt | 33 ++++++++++++ + hw/virtio/vhost-user.c | 113 +++++++++++++++++++++++++++++++++++++++++ + include/hw/virtio/vhost-user.h | 8 +++ + 3 files changed, 154 insertions(+) + +diff --git a/docs/interop/vhost-user.txt b/docs/interop/vhost-user.txt +index 682a683..d51fd58 100644 +--- a/docs/interop/vhost-user.txt ++++ b/docs/interop/vhost-user.txt +@@ -132,6 +132,16 @@ Depending on the request type, payload can be: + Payload: Size bytes array holding the contents of the virtio + device's configuration space + ++ * Vring area description ++ ----------------------- ++ | u64 | size | offset | ++ ----------------------- ++ ++ u64: a 64-bit integer contains vring index and flags ++ Size: a 64-bit size of this area ++ Offset: a 64-bit offset of this area from the start of the ++ supplied file descriptor ++ + In QEMU the vhost-user message is implemented with the following struct: + + typedef struct VhostUserMsg { +@@ -146,6 +156,7 @@ typedef struct VhostUserMsg { + VhostUserLog log; + struct vhost_iotlb_msg iotlb; + VhostUserConfig config; ++ VhostUserVringArea area; + }; + } QEMU_PACKED VhostUserMsg; + +@@ -385,6 +396,7 @@ Protocol features + #define VHOST_USER_PROTOCOL_F_PAGEFAULT 8 + #define VHOST_USER_PROTOCOL_F_CONFIG 9 + #define VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD 10 ++#define VHOST_USER_PROTOCOL_F_HOST_NOTIFIER 11 + + Master message types + -------------------- +@@ -782,6 +794,27 @@ Slave message types + the VHOST_USER_NEED_REPLY flag, master must respond with zero when + operation is successfully completed, or non-zero otherwise. + ++ * VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG ++ ++ Id: 3 ++ Equivalent ioctl: N/A ++ Slave payload: vring area description ++ Master payload: N/A ++ ++ Sets host notifier for a specified queue. The queue index is contained ++ in the u64 field of the vring area description. The host notifier is ++ described by the file descriptor (typically it's a VFIO device fd) which ++ is passed as ancillary data and the size (which is mmap size and should ++ be the same as host page size) and offset (which is mmap offset) carried ++ in the vring area description. QEMU can mmap the file descriptor based ++ on the size and offset to get a memory range. Registering a host notifier ++ means mapping this memory range to the VM as the specified queue's notify ++ MMIO region. Slave sends this request to tell QEMU to de-register the ++ existing notifier if any and register the new notifier if the request is ++ sent with a file descriptor. ++ This request should be sent only when VHOST_USER_PROTOCOL_F_HOST_NOTIFIER ++ protocol feature has been successfully negotiated. ++ + VHOST_USER_PROTOCOL_F_REPLY_ACK: + ------------------------------- + The original vhost-user specification only demands replies for certain +diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c +index a715c5c..c30fc3d 100644 +--- a/hw/virtio/vhost-user.c ++++ b/hw/virtio/vhost-user.c +@@ -13,6 +13,7 @@ + #include "hw/virtio/vhost.h" + #include "hw/virtio/vhost-user.h" + #include "hw/virtio/vhost-backend.h" ++#include "hw/virtio/virtio.h" + #include "hw/virtio/virtio-net.h" + #include "chardev/char-fe.h" + #include "sysemu/kvm.h" +@@ -50,6 +51,7 @@ enum VhostUserProtocolFeature { + VHOST_USER_PROTOCOL_F_PAGEFAULT = 8, + VHOST_USER_PROTOCOL_F_CONFIG = 9, + VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD = 10, ++ VHOST_USER_PROTOCOL_F_HOST_NOTIFIER = 11, + VHOST_USER_PROTOCOL_F_MAX + }; + +@@ -94,6 +96,7 @@ typedef enum VhostUserSlaveRequest { + VHOST_USER_SLAVE_NONE = 0, + VHOST_USER_SLAVE_IOTLB_MSG = 1, + VHOST_USER_SLAVE_CONFIG_CHANGE_MSG = 2, ++ VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG = 3, + VHOST_USER_SLAVE_MAX + } VhostUserSlaveRequest; + +@@ -138,6 +141,12 @@ static VhostUserConfig c __attribute__ ((unused)); + + sizeof(c.size) \ + + sizeof(c.flags)) + ++typedef struct VhostUserVringArea { ++ uint64_t u64; ++ uint64_t size; ++ uint64_t offset; ++} VhostUserVringArea; ++ + typedef struct { + VhostUserRequest request; + +@@ -159,6 +168,7 @@ typedef union { + struct vhost_iotlb_msg iotlb; + VhostUserConfig config; + VhostUserCryptoSession session; ++ VhostUserVringArea area; + } VhostUserPayload; + + typedef struct VhostUserMsg { +@@ -640,9 +650,37 @@ static int vhost_user_set_vring_num(struct vhost_dev *dev, + return vhost_set_vring(dev, VHOST_USER_SET_VRING_NUM, ring); + } + ++static void vhost_user_host_notifier_restore(struct vhost_dev *dev, ++ int queue_idx) ++{ ++ struct vhost_user *u = dev->opaque; ++ VhostUserHostNotifier *n = &u->user->notifier[queue_idx]; ++ VirtIODevice *vdev = dev->vdev; ++ ++ if (n->addr && !n->set) { ++ virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, true); ++ n->set = true; ++ } ++} ++ ++static void vhost_user_host_notifier_remove(struct vhost_dev *dev, ++ int queue_idx) ++{ ++ struct vhost_user *u = dev->opaque; ++ VhostUserHostNotifier *n = &u->user->notifier[queue_idx]; ++ VirtIODevice *vdev = dev->vdev; ++ ++ if (n->addr && n->set) { ++ virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, false); ++ n->set = false; ++ } ++} ++ + static int vhost_user_set_vring_base(struct vhost_dev *dev, + struct vhost_vring_state *ring) + { ++ vhost_user_host_notifier_restore(dev, ring->index); ++ + return vhost_set_vring(dev, VHOST_USER_SET_VRING_BASE, ring); + } + +@@ -676,6 +714,8 @@ static int vhost_user_get_vring_base(struct vhost_dev *dev, + .hdr.size = sizeof(msg.payload.state), + }; + ++ vhost_user_host_notifier_remove(dev, ring->index); ++ + if (vhost_user_write(dev, &msg, NULL, 0) < 0) { + return -1; + } +@@ -849,6 +889,66 @@ static int vhost_user_slave_handle_config_change(struct vhost_dev *dev) + return ret; + } + ++static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev, ++ VhostUserVringArea *area, ++ int fd) ++{ ++ int queue_idx = area->u64 & VHOST_USER_VRING_IDX_MASK; ++ size_t page_size = qemu_real_host_page_size; ++ struct vhost_user *u = dev->opaque; ++ VhostUserState *user = u->user; ++ VirtIODevice *vdev = dev->vdev; ++ VhostUserHostNotifier *n; ++ void *addr; ++ char *name; ++ ++ if (!virtio_has_feature(dev->protocol_features, ++ VHOST_USER_PROTOCOL_F_HOST_NOTIFIER) || ++ vdev == NULL || queue_idx >= virtio_get_num_queues(vdev)) { ++ return -1; ++ } ++ ++ n = &user->notifier[queue_idx]; ++ ++ if (n->addr) { ++ virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, false); ++ object_unparent(OBJECT(&n->mr)); ++ munmap(n->addr, page_size); ++ n->addr = NULL; ++ } ++ ++ if (area->u64 & VHOST_USER_VRING_NOFD_MASK) { ++ return 0; ++ } ++ ++ /* Sanity check. */ ++ if (area->size != page_size) { ++ return -1; ++ } ++ ++ addr = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED, ++ fd, area->offset); ++ if (addr == MAP_FAILED) { ++ return -1; ++ } ++ ++ name = g_strdup_printf("vhost-user/host-notifier@%p mmaps[%d]", ++ user, queue_idx); ++ memory_region_init_ram_device_ptr(&n->mr, OBJECT(vdev), name, ++ page_size, addr); ++ g_free(name); ++ ++ if (virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, true)) { ++ munmap(addr, page_size); ++ return -1; ++ } ++ ++ n->addr = addr; ++ n->set = true; ++ ++ return 0; ++} ++ + static void slave_read(void *opaque) + { + struct vhost_dev *dev = opaque; +@@ -917,6 +1017,10 @@ static void slave_read(void *opaque) + case VHOST_USER_SLAVE_CONFIG_CHANGE_MSG : + ret = vhost_user_slave_handle_config_change(dev); + break; ++ case VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG: ++ ret = vhost_user_slave_handle_vring_host_notifier(dev, &payload.area, ++ fd[0]); ++ break; + default: + error_report("Received unexpected msg type."); + ret = -EINVAL; +@@ -1648,6 +1752,15 @@ VhostUserState *vhost_user_init(void) + + void vhost_user_cleanup(VhostUserState *user) + { ++ int i; ++ ++ for (i = 0; i < VIRTIO_QUEUE_MAX; i++) { ++ if (user->notifier[i].addr) { ++ object_unparent(OBJECT(&user->notifier[i].mr)); ++ munmap(user->notifier[i].addr, qemu_real_host_page_size); ++ user->notifier[i].addr = NULL; ++ } ++ } + } + + const VhostOps user_ops = { +diff --git a/include/hw/virtio/vhost-user.h b/include/hw/virtio/vhost-user.h +index eb8bc0d..fd66039 100644 +--- a/include/hw/virtio/vhost-user.h ++++ b/include/hw/virtio/vhost-user.h +@@ -9,9 +9,17 @@ + #define HW_VIRTIO_VHOST_USER_H + + #include "chardev/char-fe.h" ++#include "hw/virtio/virtio.h" ++ ++typedef struct VhostUserHostNotifier { ++ MemoryRegion mr; ++ void *addr; ++ bool set; ++} VhostUserHostNotifier; + + typedef struct VhostUserState { + CharBackend *chr; ++ VhostUserHostNotifier notifier[VIRTIO_QUEUE_MAX]; + } VhostUserState; + + VhostUserState *vhost_user_init(void); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-virtio-Add-queue-interface-to-restore-avail-index-fr.patch b/SOURCES/kvm-virtio-Add-queue-interface-to-restore-avail-index-fr.patch deleted file mode 100644 index bef39f8..0000000 --- a/SOURCES/kvm-virtio-Add-queue-interface-to-restore-avail-index-fr.patch +++ /dev/null @@ -1,74 +0,0 @@ -From 257d8d98076717288519d312f1690c453bb74776 Mon Sep 17 00:00:00 2001 -From: Maxime Coquelin -Date: Tue, 5 Dec 2017 09:28:38 +0100 -Subject: [PATCH 16/21] virtio: Add queue interface to restore avail index from - vring used index -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Maxime Coquelin -Message-id: <20171205092839.17597-2-maxime.coquelin@redhat.com> -Patchwork-id: 78140 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 1/2] virtio: Add queue interface to restore avail index from vring used index -Bugzilla: 1491909 -RH-Acked-by: wexu@redhat.com -RH-Acked-by: Marc-André Lureau -RH-Acked-by: Michael S. Tsirkin -RH-Acked-by: Xiao Wang - -In case of backend crash, it is not possible to restore internal -avail index from the backend value as vhost_get_vring_base -callback fails. - -This patch provides a new interface to restore internal avail index -from the vring used index, as done by some vhost-user backend on -reconnection. - -Signed-off-by: Maxime Coquelin -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 2d4ba6cc741df15df6fbb4feaa706a02e103083a) -Signed-off-by: Maxime Coquelin -Signed-off-by: Miroslav Rezanina ---- - hw/virtio/virtio.c | 10 ++++++++++ - include/hw/virtio/virtio.h | 1 + - 2 files changed, 11 insertions(+) - -diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c -index e7a2bc2..58ecf75 100644 ---- a/hw/virtio/virtio.c -+++ b/hw/virtio/virtio.c -@@ -2329,6 +2329,16 @@ void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx) - vdev->vq[n].shadow_avail_idx = idx; - } - -+void virtio_queue_restore_last_avail_idx(VirtIODevice *vdev, int n) -+{ -+ rcu_read_lock(); -+ if (vdev->vq[n].vring.desc) { -+ vdev->vq[n].last_avail_idx = vring_used_idx(&vdev->vq[n]); -+ vdev->vq[n].shadow_avail_idx = vdev->vq[n].last_avail_idx; -+ } -+ rcu_read_unlock(); -+} -+ - void virtio_queue_update_used_idx(VirtIODevice *vdev, int n) - { - rcu_read_lock(); -diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h -index 5faa359..912310c 100644 ---- a/include/hw/virtio/virtio.h -+++ b/include/hw/virtio/virtio.h -@@ -273,6 +273,7 @@ hwaddr virtio_queue_get_avail_size(VirtIODevice *vdev, int n); - hwaddr virtio_queue_get_used_size(VirtIODevice *vdev, int n); - uint16_t virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n); - void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx); -+void virtio_queue_restore_last_avail_idx(VirtIODevice *vdev, int n); - void virtio_queue_invalidate_signalled_used(VirtIODevice *vdev, int n); - void virtio_queue_update_used_idx(VirtIODevice *vdev, int n); - VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n); --- -1.8.3.1 - diff --git a/SOURCES/kvm-virtio-gpu-disable-scanout-when-backing-resource-is-.patch b/SOURCES/kvm-virtio-gpu-disable-scanout-when-backing-resource-is-.patch new file mode 100644 index 0000000..660d7ac --- /dev/null +++ b/SOURCES/kvm-virtio-gpu-disable-scanout-when-backing-resource-is-.patch @@ -0,0 +1,51 @@ +From 3354ddad8488034064ae85e8414a77514a90b259 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 4 Jul 2018 09:54:09 +0200 +Subject: [PATCH 15/89] virtio-gpu: disable scanout when backing resource is + destroyed +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Gerd Hoffmann +Message-id: <20180704095409.14514-4-kraxel@redhat.com> +Patchwork-id: 81225 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 3/3] virtio-gpu: disable scanout when backing resource is destroyed +Bugzilla: 1589634 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Marc-André Lureau +RH-Acked-by: Laszlo Ersek + +Signed-off-by: Gerd Hoffmann +Reviewed-by: Marc-André Lureau +Message-id: 20180702162443.16796-4-kraxel@redhat.com +(cherry picked from commit 1fccd7c5a9a722a9cbf1bc91693f4618034f01ac) +Signed-off-by: Miroslav Rezanina +--- + hw/display/virtio-gpu.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c +index 336dc59..08cd567 100644 +--- a/hw/display/virtio-gpu.c ++++ b/hw/display/virtio-gpu.c +@@ -430,6 +430,16 @@ static void virtio_gpu_disable_scanout(VirtIOGPU *g, int scanout_id) + static void virtio_gpu_resource_destroy(VirtIOGPU *g, + struct virtio_gpu_simple_resource *res) + { ++ int i; ++ ++ if (res->scanout_bitmask) { ++ for (i = 0; i < g->conf.max_outputs; i++) { ++ if (res->scanout_bitmask & (1 << i)) { ++ virtio_gpu_disable_scanout(g, i); ++ } ++ } ++ } ++ + pixman_image_unref(res->image); + virtio_gpu_cleanup_mapping(res); + QTAILQ_REMOVE(&g->reslist, res, next); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-virtio-gpu-disallow-vIOMMU.patch b/SOURCES/kvm-virtio-gpu-disallow-vIOMMU.patch deleted file mode 100644 index f2f442c..0000000 --- a/SOURCES/kvm-virtio-gpu-disallow-vIOMMU.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 5ce65934798e5c87e465f30ad08f24b76429ee7c Mon Sep 17 00:00:00 2001 -From: Peter Xu -Date: Tue, 6 Feb 2018 08:21:19 +0100 -Subject: [PATCH 20/20] virtio-gpu: disallow vIOMMU -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Peter Xu -Message-id: <20180206082119.9246-1-peterx@redhat.com> -Patchwork-id: 78903 -O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH] virtio-gpu: disallow vIOMMU -Bugzilla: 1540182 -RH-Acked-by: Gerd Hoffmann -RH-Acked-by: Dr. David Alan Gilbert -RH-Acked-by: Marc-André Lureau - -virtio-gpu has special code path that bypassed vIOMMU protection. So -for now let's disable iommu_platform for the device until we fully -support that (if needed). - -After the patch, both virtio-vga and virtio-gpu won't allow to boot with -iommu_platform parameter set. - -CC: Gerd Hoffmann -Signed-off-by: Peter Xu -Message-id: 20180131040401.3550-1-peterx@redhat.com -Signed-off-by: Gerd Hoffmann -(cherry picked from commit 34e304e97576a9e17680c868c00ff524a981007b) -Signed-off-by: Peter Xu -Signed-off-by: Miroslav Rezanina ---- - hw/display/virtio-gpu-pci.c | 8 +++++++- - hw/display/virtio-gpu.c | 5 +++++ - 2 files changed, 12 insertions(+), 1 deletion(-) - -diff --git a/hw/display/virtio-gpu-pci.c b/hw/display/virtio-gpu-pci.c -index ef92c4a..3519dc8 100644 ---- a/hw/display/virtio-gpu-pci.c -+++ b/hw/display/virtio-gpu-pci.c -@@ -28,10 +28,16 @@ static void virtio_gpu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) - VirtIOGPU *g = &vgpu->vdev; - DeviceState *vdev = DEVICE(&vgpu->vdev); - int i; -+ Error *local_error = NULL; - - qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - virtio_pci_force_virtio_1(vpci_dev); -- object_property_set_bool(OBJECT(vdev), true, "realized", errp); -+ object_property_set_bool(OBJECT(vdev), true, "realized", &local_error); -+ -+ if (local_error) { -+ error_propagate(errp, local_error); -+ return; -+ } - - for (i = 0; i < g->conf.max_outputs; i++) { - object_property_set_link(OBJECT(g->scanout[i].con), -diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c -index 4e66535..db53e0b 100644 ---- a/hw/display/virtio-gpu.c -+++ b/hw/display/virtio-gpu.c -@@ -1109,6 +1109,11 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) - Error *local_err = NULL; - int i; - -+ if (virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM)) { -+ error_setg(errp, "virtio-gpu does not support vIOMMU yet"); -+ return; -+ } -+ - if (g->conf.max_outputs > VIRTIO_GPU_MAX_SCANOUTS) { - error_setg(errp, "invalid max_outputs > %d", VIRTIO_GPU_MAX_SCANOUTS); - return; --- -1.8.3.1 - diff --git a/SOURCES/kvm-virtio-gpu-don-t-clear-QemuUIInfo-information-on-res.patch b/SOURCES/kvm-virtio-gpu-don-t-clear-QemuUIInfo-information-on-res.patch deleted file mode 100644 index c39ecf9..0000000 --- a/SOURCES/kvm-virtio-gpu-don-t-clear-QemuUIInfo-information-on-res.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 778b752e1808475fe4c2086e5e0c523bff7b30b9 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Thu, 5 Oct 2017 08:39:50 +0200 -Subject: [PATCH 01/69] virtio-gpu: don't clear QemuUIInfo information on reset -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Gerd Hoffmann -Message-id: <20171005083950.12662-2-kraxel@redhat.com> -Patchwork-id: 76812 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 1/1] virtio-gpu: don't clear QemuUIInfo information on reset -Bugzilla: 1460595 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Thomas Huth - -Don't reset window layout information (passed via virtio_gpu_ui_info) on -device reset, so the user interface window layout will be kept intact -over reboots. The head size and position was commented out already, so -this patch just drops the dead code. Additionally the enabled head mask -must be kept so multihead setups work properly too. - -Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1460595 -Signed-off-by: Gerd Hoffmann -Reviewed-by: Marc-André Lureau -Message-id: 20170906142058.2460-1-kraxel@redhat.com -(cherry picked from commit 79d16c21a565927943486b26789caa62413ff371) -Signed-off-by: Miroslav Rezanina ---- - hw/display/virtio-gpu.c | 12 ------------ - 1 file changed, 12 deletions(-) - -diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c -index 6aae147..4e66535 100644 ---- a/hw/display/virtio-gpu.c -+++ b/hw/display/virtio-gpu.c -@@ -1195,17 +1195,6 @@ static void virtio_gpu_reset(VirtIODevice *vdev) - virtio_gpu_resource_destroy(g, res); - } - for (i = 0; i < g->conf.max_outputs; i++) { --#if 0 -- g->req_state[i].x = 0; -- g->req_state[i].y = 0; -- if (i == 0) { -- g->req_state[0].width = 1024; -- g->req_state[0].height = 768; -- } else { -- g->req_state[i].width = 0; -- g->req_state[i].height = 0; -- } --#endif - g->scanout[i].resource_id = 0; - g->scanout[i].width = 0; - g->scanout[i].height = 0; -@@ -1213,7 +1202,6 @@ static void virtio_gpu_reset(VirtIODevice *vdev) - g->scanout[i].y = 0; - g->scanout[i].ds = NULL; - } -- g->enabled_output_bitmask = 1; - - #ifdef CONFIG_VIRGL - if (g->use_virgl_renderer) { --- -1.8.3.1 - diff --git a/SOURCES/kvm-virtio-gpu-tweak-scanout-disable.patch b/SOURCES/kvm-virtio-gpu-tweak-scanout-disable.patch new file mode 100644 index 0000000..0f593a0 --- /dev/null +++ b/SOURCES/kvm-virtio-gpu-tweak-scanout-disable.patch @@ -0,0 +1,98 @@ +From 403646c800359dcc52f3bbbf348dda917667d9d1 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 4 Jul 2018 09:54:07 +0200 +Subject: [PATCH 13/89] virtio-gpu: tweak scanout disable. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Gerd Hoffmann +Message-id: <20180704095409.14514-2-kraxel@redhat.com> +Patchwork-id: 81226 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/3] virtio-gpu: tweak scanout disable. +Bugzilla: 1589634 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Marc-André Lureau +RH-Acked-by: Laszlo Ersek + +- Factor out the code to virtio_gpu_disable_scanout(). +- Allow disable scanout 0, show a message then. +- Clear scanout->resource_id. + +Signed-off-by: Gerd Hoffmann +Reviewed-by: Marc-André Lureau +Message-id: 20180702162443.16796-2-kraxel@redhat.com +(cherry picked from commit da566a18a7799e5a655cd9f87e222b672cc93e7b) +Signed-off-by: Miroslav Rezanina +--- + hw/display/virtio-gpu.c | 47 +++++++++++++++++++++++++++++------------------ + 1 file changed, 29 insertions(+), 18 deletions(-) + +diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c +index 2dd3c34..054ec73 100644 +--- a/hw/display/virtio-gpu.c ++++ b/hw/display/virtio-gpu.c +@@ -399,6 +399,34 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g, + g->hostmem += res->hostmem; + } + ++static void virtio_gpu_disable_scanout(VirtIOGPU *g, int scanout_id) ++{ ++ struct virtio_gpu_scanout *scanout = &g->scanout[scanout_id]; ++ struct virtio_gpu_simple_resource *res; ++ DisplaySurface *ds = NULL; ++ ++ if (scanout->resource_id == 0) { ++ return; ++ } ++ ++ res = virtio_gpu_find_resource(g, scanout->resource_id); ++ if (res) { ++ res->scanout_bitmask &= ~(1 << scanout_id); ++ } ++ ++ if (scanout_id == 0) { ++ /* primary head */ ++ ds = qemu_create_message_surface(scanout->width ?: 640, ++ scanout->height ?: 480, ++ "Guest disabled display."); ++ } ++ dpy_gfx_replace_surface(scanout->con, ds); ++ scanout->resource_id = 0; ++ scanout->ds = NULL; ++ scanout->width = 0; ++ scanout->height = 0; ++} ++ + static void virtio_gpu_resource_destroy(VirtIOGPU *g, + struct virtio_gpu_simple_resource *res) + { +@@ -583,24 +611,7 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g, + + g->enable = 1; + if (ss.resource_id == 0) { +- scanout = &g->scanout[ss.scanout_id]; +- if (scanout->resource_id) { +- res = virtio_gpu_find_resource(g, scanout->resource_id); +- if (res) { +- res->scanout_bitmask &= ~(1 << ss.scanout_id); +- } +- } +- if (ss.scanout_id == 0) { +- qemu_log_mask(LOG_GUEST_ERROR, +- "%s: illegal scanout id specified %d", +- __func__, ss.scanout_id); +- cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID; +- return; +- } +- dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, NULL); +- scanout->ds = NULL; +- scanout->width = 0; +- scanout->height = 0; ++ virtio_gpu_disable_scanout(g, ss.scanout_id); + return; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-virtio-gpu-update-old-resource-too.patch b/SOURCES/kvm-virtio-gpu-update-old-resource-too.patch new file mode 100644 index 0000000..73ef420 --- /dev/null +++ b/SOURCES/kvm-virtio-gpu-update-old-resource-too.patch @@ -0,0 +1,58 @@ +From 10ece778cf0de01b5fb9c853fc27ea3bb7d40a5e Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 4 Jul 2018 09:54:08 +0200 +Subject: [PATCH 14/89] virtio-gpu: update old resource too. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Gerd Hoffmann +Message-id: <20180704095409.14514-3-kraxel@redhat.com> +Patchwork-id: 81227 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 2/3] virtio-gpu: update old resource too. +Bugzilla: 1589634 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Marc-André Lureau +RH-Acked-by: Laszlo Ersek + +When switching scanout from one resource to another we must update the +scanout_bitmask field for both new (set bit) and old (clear bit) +resource. + +Signed-off-by: Gerd Hoffmann +Reviewed-by: Marc-André Lureau +Message-id: 20180702162443.16796-3-kraxel@redhat.com +(cherry picked from commit c806cfa036a7ec991170eb9899f3a676bfcc3253) +Signed-off-by: Miroslav Rezanina +--- + hw/display/virtio-gpu.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c +index 054ec73..336dc59 100644 +--- a/hw/display/virtio-gpu.c ++++ b/hw/display/virtio-gpu.c +@@ -590,7 +590,7 @@ static void virtio_unref_resource(pixman_image_t *image, void *data) + static void virtio_gpu_set_scanout(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) + { +- struct virtio_gpu_simple_resource *res; ++ struct virtio_gpu_simple_resource *res, *ores; + struct virtio_gpu_scanout *scanout; + pixman_format_code_t format; + uint32_t offset; +@@ -664,6 +664,11 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g, + dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, scanout->ds); + } + ++ ores = virtio_gpu_find_resource(g, scanout->resource_id); ++ if (ores) { ++ ores->scanout_bitmask &= ~(1 << ss.scanout_id); ++ } ++ + res->scanout_bitmask |= (1 << ss.scanout_id); + scanout->resource_id = ss.resource_id; + scanout->x = ss.r.x; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-virtio-net-don-t-touch-virtqueue-if-vm-is-stopped.patch b/SOURCES/kvm-virtio-net-don-t-touch-virtqueue-if-vm-is-stopped.patch deleted file mode 100644 index 03533e5..0000000 --- a/SOURCES/kvm-virtio-net-don-t-touch-virtqueue-if-vm-is-stopped.patch +++ /dev/null @@ -1,59 +0,0 @@ -From d7c69df61c216de014aca9d1eafc94ddb81ce5bb Mon Sep 17 00:00:00 2001 -From: Xiao Wang -Date: Wed, 29 Nov 2017 07:39:51 +0100 -Subject: [PATCH 17/21] virtio-net: don't touch virtqueue if vm is stopped - -RH-Author: Xiao Wang -Message-id: <1511941191-30204-1-git-send-email-jasowang@redhat.com> -Patchwork-id: 77949 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH] virtio-net: don't touch virtqueue if vm is stopped -Bugzilla: 1506151 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Pankaj Gupta -RH-Acked-by: wexu@redhat.com - -Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1506151 -Brew Build: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=14645237 -Test status: Tested by myself - -Guest state should not be touched if VM is stopped, unfortunately we -didn't check running state and tried to drain tx queue unconditionally -in virtio_net_set_status(). A crash was then noticed as a migration -destination when user type quit after virtqueue state is loaded but -before region cache is initialized. In this case, -virtio_net_drop_tx_queue_data() tries to access the uninitialized -region cache. - -Fix this by only dropping tx queue data when vm is running. - -Fixes: 283e2c2adcb80 ("net: virtio-net discards TX data after link down") -Cc: Yuri Benditovich -Cc: Paolo Bonzini -Cc: Stefan Hajnoczi -Cc: Michael S. Tsirkin -Cc: qemu-stable@nongnu.org -Reviewed-by: Stefan Hajnoczi -Signed-off-by: Jason Wang -(cherry picked from commit 70e53e6e4da3db4b2c31981191753a7e974936d0) -Signed-off-by: Miroslav Rezanina ---- - hw/net/virtio-net.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c -index 148071a..fbc5e1b 100644 ---- a/hw/net/virtio-net.c -+++ b/hw/net/virtio-net.c -@@ -288,7 +288,8 @@ static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status) - qemu_bh_cancel(q->tx_bh); - } - if ((n->status & VIRTIO_NET_S_LINK_UP) == 0 && -- (queue_status & VIRTIO_CONFIG_S_DRIVER_OK)) { -+ (queue_status & VIRTIO_CONFIG_S_DRIVER_OK) && -+ vdev->vm_running) { - /* if tx is waiting we are likely have some packets in tx queue - * and disabled notification */ - q->tx_waiting = 0; --- -1.8.3.1 - diff --git a/SOURCES/kvm-virtio-pci-Replace-modern_as-with-direct-access-to-m.patch b/SOURCES/kvm-virtio-pci-Replace-modern_as-with-direct-access-to-m.patch deleted file mode 100644 index 59f8f4e..0000000 --- a/SOURCES/kvm-virtio-pci-Replace-modern_as-with-direct-access-to-m.patch +++ /dev/null @@ -1,240 +0,0 @@ -From ff5e61b600d9a130faad32ceda3cd212dcb387d4 Mon Sep 17 00:00:00 2001 -From: David Gibson -Date: Thu, 16 Nov 2017 03:07:11 +0100 -Subject: [PATCH 07/30] virtio-pci: Replace modern_as with direct access to - modern_bar - -RH-Author: David Gibson -Message-id: <20171116030732.8560-2-dgibson@redhat.com> -Patchwork-id: 77689 -O-Subject: [PATCH 01/22] virtio-pci: Replace modern_as with direct access to modern_bar -Bugzilla: 1481593 -RH-Acked-by: Thomas Huth -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Eduardo Habkost -RH-Acked-by: Laurent Vivier - -From: Alexey Kardashevskiy - -The modern bar is accessed now via yet another address space created just -for that purpose and it does not really need FlatView and dispatch tree -as it has a single memory region so it is just a waste of memory. Things -get even worse when there are dozens or hundreds of virtio-pci devices - -since these address spaces are global, changing any of them triggers -rebuilding all address spaces. - -This replaces indirect accesses to the modern BAR with a simple lookup -and direct calls to memory_region_dispatch_read/write. - -This is expected to save lots of memory at boot time after applying: -[Qemu-devel] [PULL 00/32] Misc changes for 2017-09-22 - -Signed-off-by: Alexey Kardashevskiy -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit a93c8d828af186d9a6a1c915a1be8ba22fb89849) - -Signed-off-by: David Gibson -Signed-off-by: Miroslav Rezanina ---- - hw/virtio/virtio-pci.c | 75 +++++++++++++++++++++++++++++--------------------- - hw/virtio/virtio-pci.h | 17 +++++++----- - 2 files changed, 54 insertions(+), 38 deletions(-) - -diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c -index 6e497c8..4b041bb 100644 ---- a/hw/virtio/virtio-pci.c -+++ b/hw/virtio/virtio-pci.c -@@ -545,6 +545,24 @@ static const MemoryRegionOps virtio_pci_config_ops = { - .endianness = DEVICE_LITTLE_ENDIAN, - }; - -+static MemoryRegion *virtio_address_space_lookup(VirtIOPCIProxy *proxy, -+ hwaddr *off, int len) -+{ -+ int i; -+ VirtIOPCIRegion *reg; -+ -+ for (i = 0; i < ARRAY_SIZE(proxy->regs); ++i) { -+ reg = &proxy->regs[i]; -+ if (*off >= reg->offset && -+ *off + len <= reg->offset + reg->size) { -+ *off -= reg->offset; -+ return ®->mr; -+ } -+ } -+ -+ return NULL; -+} -+ - /* Below are generic functions to do memcpy from/to an address space, - * without byteswaps, with input validation. - * -@@ -558,63 +576,72 @@ static const MemoryRegionOps virtio_pci_config_ops = { - * Note: host pointer must be aligned. - */ - static --void virtio_address_space_write(AddressSpace *as, hwaddr addr, -+void virtio_address_space_write(VirtIOPCIProxy *proxy, hwaddr addr, - const uint8_t *buf, int len) - { -- uint32_t val; -+ uint64_t val; -+ MemoryRegion *mr; - - /* address_space_* APIs assume an aligned address. - * As address is under guest control, handle illegal values. - */ - addr &= ~(len - 1); - -+ mr = virtio_address_space_lookup(proxy, &addr, len); -+ if (!mr) { -+ return; -+ } -+ - /* Make sure caller aligned buf properly */ - assert(!(((uintptr_t)buf) & (len - 1))); - - switch (len) { - case 1: - val = pci_get_byte(buf); -- address_space_stb(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL); - break; - case 2: -- val = pci_get_word(buf); -- address_space_stw_le(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL); -+ val = cpu_to_le16(pci_get_word(buf)); - break; - case 4: -- val = pci_get_long(buf); -- address_space_stl_le(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL); -+ val = cpu_to_le32(pci_get_long(buf)); - break; - default: - /* As length is under guest control, handle illegal values. */ -- break; -+ return; - } -+ memory_region_dispatch_write(mr, addr, val, len, MEMTXATTRS_UNSPECIFIED); - } - - static void --virtio_address_space_read(AddressSpace *as, hwaddr addr, uint8_t *buf, int len) -+virtio_address_space_read(VirtIOPCIProxy *proxy, hwaddr addr, -+ uint8_t *buf, int len) - { -- uint32_t val; -+ uint64_t val; -+ MemoryRegion *mr; - - /* address_space_* APIs assume an aligned address. - * As address is under guest control, handle illegal values. - */ - addr &= ~(len - 1); - -+ mr = virtio_address_space_lookup(proxy, &addr, len); -+ if (!mr) { -+ return; -+ } -+ - /* Make sure caller aligned buf properly */ - assert(!(((uintptr_t)buf) & (len - 1))); - -+ memory_region_dispatch_read(mr, addr, &val, len, MEMTXATTRS_UNSPECIFIED); - switch (len) { - case 1: -- val = address_space_ldub(as, addr, MEMTXATTRS_UNSPECIFIED, NULL); - pci_set_byte(buf, val); - break; - case 2: -- val = address_space_lduw_le(as, addr, MEMTXATTRS_UNSPECIFIED, NULL); -- pci_set_word(buf, val); -+ pci_set_word(buf, le16_to_cpu(val)); - break; - case 4: -- val = address_space_ldl_le(as, addr, MEMTXATTRS_UNSPECIFIED, NULL); -- pci_set_long(buf, val); -+ pci_set_long(buf, le32_to_cpu(val)); - break; - default: - /* As length is under guest control, handle illegal values. */ -@@ -650,8 +677,7 @@ static void virtio_write_config(PCIDevice *pci_dev, uint32_t address, - - if (len == 1 || len == 2 || len == 4) { - assert(len <= sizeof cfg->pci_cfg_data); -- virtio_address_space_write(&proxy->modern_as, off, -- cfg->pci_cfg_data, len); -+ virtio_address_space_write(proxy, off, cfg->pci_cfg_data, len); - } - } - } -@@ -675,8 +701,7 @@ static uint32_t virtio_read_config(PCIDevice *pci_dev, - - if (len == 1 || len == 2 || len == 4) { - assert(len <= sizeof cfg->pci_cfg_data); -- virtio_address_space_read(&proxy->modern_as, off, -- cfg->pci_cfg_data, len); -+ virtio_address_space_read(proxy, off, cfg->pci_cfg_data, len); - } - } - -@@ -1783,15 +1808,6 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) - /* PCI BAR regions must be powers of 2 */ - pow2ceil(proxy->notify.offset + proxy->notify.size)); - -- memory_region_init_alias(&proxy->modern_cfg, -- OBJECT(proxy), -- "virtio-pci-cfg", -- &proxy->modern_bar, -- 0, -- memory_region_size(&proxy->modern_bar)); -- -- address_space_init(&proxy->modern_as, &proxy->modern_cfg, "virtio-pci-cfg-as"); -- - if (proxy->disable_legacy == ON_OFF_AUTO_AUTO) { - proxy->disable_legacy = pcie_port ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; - } -@@ -1860,10 +1876,7 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) - - static void virtio_pci_exit(PCIDevice *pci_dev) - { -- VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev); -- - msix_uninit_exclusive_bar(pci_dev); -- address_space_destroy(&proxy->modern_as); - } - - static void virtio_pci_reset(DeviceState *qdev) -diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h -index 69f5959..12d3a90 100644 ---- a/hw/virtio/virtio-pci.h -+++ b/hw/virtio/virtio-pci.h -@@ -155,15 +155,18 @@ typedef struct VirtIOPCIQueue { - struct VirtIOPCIProxy { - PCIDevice pci_dev; - MemoryRegion bar; -- VirtIOPCIRegion common; -- VirtIOPCIRegion isr; -- VirtIOPCIRegion device; -- VirtIOPCIRegion notify; -- VirtIOPCIRegion notify_pio; -+ union { -+ struct { -+ VirtIOPCIRegion common; -+ VirtIOPCIRegion isr; -+ VirtIOPCIRegion device; -+ VirtIOPCIRegion notify; -+ VirtIOPCIRegion notify_pio; -+ }; -+ VirtIOPCIRegion regs[5]; -+ }; - MemoryRegion modern_bar; - MemoryRegion io_bar; -- MemoryRegion modern_cfg; -- AddressSpace modern_as; - uint32_t legacy_io_bar_idx; - uint32_t msix_bar_idx; - uint32_t modern_io_bar_idx; --- -1.8.3.1 - diff --git a/SOURCES/kvm-virtio-rng-process-pending-requests-on-DRIVER_OK.patch b/SOURCES/kvm-virtio-rng-process-pending-requests-on-DRIVER_OK.patch new file mode 100644 index 0000000..9570f1c --- /dev/null +++ b/SOURCES/kvm-virtio-rng-process-pending-requests-on-DRIVER_OK.patch @@ -0,0 +1,70 @@ +From 01ad4c3dbed4a506e4c7988026336181aa5fd991 Mon Sep 17 00:00:00 2001 +From: Pankaj Gupta +Date: Fri, 13 Jul 2018 12:52:28 +0200 +Subject: [PATCH 42/89] virtio-rng: process pending requests on DRIVER_OK + +RH-Author: Pankaj Gupta +Message-id: <20180713125228.14458-1-pagupta@redhat.com> +Patchwork-id: 81347 +O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH] virtio-rng: process pending requests on DRIVER_OK +Bugzilla: 1576743 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Cornelia Huck +RH-Acked-by: Miroslav Rezanina + +virtio-rng device causes old guest kernels(2.6.32) to hang on latest qemu. +The driver attempts to read from the virtio-rng device too early in it's +initialization. Qemu detects guest is not ready and returns, resulting in +hang. + +To fix handle pending requests when guest is running and driver status is +set to 'VIRTIO_CONFIG_S_DRIVER_OK'. + +CC: qemu-stable@nongnu.org +Reported-by: Sergio lopez +Signed-off-by: Stefan Hajnoczi +Signed-off-by: Pankaj Gupta +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 5d9c9ea22ab4f3b3ee497523e34b6f4d3281f62d) +Signed-off-by: Pankaj Gupta +Signed-off-by: Miroslav Rezanina +--- + hw/virtio/virtio-rng.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c +index 289bbca..855f1b4 100644 +--- a/hw/virtio/virtio-rng.c ++++ b/hw/virtio/virtio-rng.c +@@ -156,6 +156,19 @@ static void check_rate_limit(void *opaque) + vrng->activate_timer = true; + } + ++static void virtio_rng_set_status(VirtIODevice *vdev, uint8_t status) ++{ ++ VirtIORNG *vrng = VIRTIO_RNG(vdev); ++ ++ if (!vdev->vm_running) { ++ return; ++ } ++ vdev->status = status; ++ ++ /* Something changed, try to process buffers */ ++ virtio_rng_process(vrng); ++} ++ + static void virtio_rng_device_realize(DeviceState *dev, Error **errp) + { + VirtIODevice *vdev = VIRTIO_DEVICE(dev); +@@ -261,6 +274,7 @@ static void virtio_rng_class_init(ObjectClass *klass, void *data) + vdc->realize = virtio_rng_device_realize; + vdc->unrealize = virtio_rng_device_unrealize; + vdc->get_features = get_features; ++ vdc->set_status = virtio_rng_set_status; + } + + static const TypeInfo virtio_rng_info = { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-virtio-scsi-fix-hotplug-reset-vs-event-race.patch b/SOURCES/kvm-virtio-scsi-fix-hotplug-reset-vs-event-race.patch new file mode 100644 index 0000000..1d0319c --- /dev/null +++ b/SOURCES/kvm-virtio-scsi-fix-hotplug-reset-vs-event-race.patch @@ -0,0 +1,77 @@ +From 68bd30cd50bff358594045cb03494132af3e09a5 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Tue, 24 Jul 2018 15:13:08 +0200 +Subject: [PATCH 09/15] virtio-scsi: fix hotplug ->reset() vs event race + +RH-Author: Stefan Hajnoczi +Message-id: <20180724151308.20500-3-stefanha@redhat.com> +Patchwork-id: 81486 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 2/2] virtio-scsi: fix hotplug ->reset() vs event race +Bugzilla: 1607891 +RH-Acked-by: Igor Mammedov +RH-Acked-by: Pankaj Gupta +RH-Acked-by: Cornelia Huck + +There is a race condition during hotplug when iothread is used. It +occurs because virtio-scsi may be processing command queues in the +iothread while the monitor performs SCSI device hotplug. + +When a SCSI device is hotplugged the HotplugHandler->plug() callback is +invoked and virtio-scsi emits a rescan event to the guest. + +If the guest submits a SCSI command at this point then it may be +cancelled before hotplug completes. This happens because ->reset() is +called by hw/core/qdev.c:device_set_realized() after +HotplugHandler->plug() has been called and +hw/scsi/scsi-disk.c:scsi_disk_reset() purges all requests. + +This patch uses the new HotplugHandler->post_plug() callback to emit the +rescan event after ->reset(). This eliminates the race conditions where +requests could be cancelled. + +Reported-by: l00284672 +Cc: Paolo Bonzini +Cc: Fam Zheng +Signed-off-by: Stefan Hajnoczi +Message-Id: <20180716083732.3347-3-stefanha@redhat.com> +Signed-off-by: Paolo Bonzini +(cherry picked from commit 8449bcf94986156a1476d6647c75ec1ce3db64d0) +Signed-off-by: Stefan Hajnoczi +Signed-off-by: Miroslav Rezanina +--- + hw/scsi/virtio-scsi.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c +index 9f754c4..52a3c1d 100644 +--- a/hw/scsi/virtio-scsi.c ++++ b/hw/scsi/virtio-scsi.c +@@ -806,8 +806,16 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev, + virtio_scsi_acquire(s); + blk_set_aio_context(sd->conf.blk, s->ctx); + virtio_scsi_release(s); +- + } ++} ++ ++/* Announce the new device after it has been plugged */ ++static void virtio_scsi_post_hotplug(HotplugHandler *hotplug_dev, ++ DeviceState *dev) ++{ ++ VirtIODevice *vdev = VIRTIO_DEVICE(hotplug_dev); ++ VirtIOSCSI *s = VIRTIO_SCSI(vdev); ++ SCSIDevice *sd = SCSI_DEVICE(dev); + + if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) { + virtio_scsi_acquire(s); +@@ -977,6 +985,7 @@ static void virtio_scsi_class_init(ObjectClass *klass, void *data) + vdc->start_ioeventfd = virtio_scsi_dataplane_start; + vdc->stop_ioeventfd = virtio_scsi_dataplane_stop; + hc->plug = virtio_scsi_hotplug; ++ hc->post_plug = virtio_scsi_post_hotplug; + hc->unplug = virtio_scsi_hotunplug; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-virtio-support-setting-memory-region-based-host-noti.patch b/SOURCES/kvm-virtio-support-setting-memory-region-based-host-noti.patch new file mode 100644 index 0000000..0a8b79c --- /dev/null +++ b/SOURCES/kvm-virtio-support-setting-memory-region-based-host-noti.patch @@ -0,0 +1,129 @@ +From c8498903f19357ce72eeb976b3054c56896a6c44 Mon Sep 17 00:00:00 2001 +From: "plai@redhat.com" +Date: Thu, 21 Jun 2018 18:54:37 +0200 +Subject: [PATCH 28/57] virtio: support setting memory region based host + notifier + +RH-Author: plai@redhat.com +Message-id: <1529607285-9942-3-git-send-email-plai@redhat.com> +Patchwork-id: 80937 +O-Subject: [RHEL7.6 PATCH BZ 1526645 02/10] virtio: support setting memory region based host notifier +Bugzilla: 1526645 +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Maxime Coquelin +RH-Acked-by: Laurent Vivier + +From: Tiwei Bie + +This patch introduces the support for setting memory region +based host notifiers for virtio device. This is helpful when +using a hardware accelerator for a virtio device, because +hardware heavily depends on the notification, this will allow +the guest driver in the VM to notify the hardware directly. + +Signed-off-by: Tiwei Bie +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 6f80e6170ede13605817e5c0ca73db0de7bdf261) +Signed-off-by: Paul Lai +Signed-off-by: Miroslav Rezanina +--- + hw/virtio/virtio-pci.c | 22 ++++++++++++++++++++++ + hw/virtio/virtio.c | 13 +++++++++++++ + include/hw/virtio/virtio-bus.h | 2 ++ + include/hw/virtio/virtio.h | 2 ++ + 4 files changed, 39 insertions(+) + +diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c +index 18f7c2c..b887fc4 100644 +--- a/hw/virtio/virtio-pci.c ++++ b/hw/virtio/virtio-pci.c +@@ -1037,6 +1037,27 @@ assign_error: + return r; + } + ++static int virtio_pci_set_host_notifier_mr(DeviceState *d, int n, ++ MemoryRegion *mr, bool assign) ++{ ++ VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); ++ int offset; ++ ++ if (n >= VIRTIO_QUEUE_MAX || !virtio_pci_modern(proxy) || ++ virtio_pci_queue_mem_mult(proxy) != memory_region_size(mr)) { ++ return -1; ++ } ++ ++ if (assign) { ++ offset = virtio_pci_queue_mem_mult(proxy) * n; ++ memory_region_add_subregion_overlap(&proxy->notify.mr, offset, mr, 1); ++ } else { ++ memory_region_del_subregion(&proxy->notify.mr, mr); ++ } ++ ++ return 0; ++} ++ + static void virtio_pci_vmstate_change(DeviceState *d, bool running) + { + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); +@@ -2652,6 +2673,7 @@ static void virtio_pci_bus_class_init(ObjectClass *klass, void *data) + k->has_extra_state = virtio_pci_has_extra_state; + k->query_guest_notifiers = virtio_pci_query_guest_notifiers; + k->set_guest_notifiers = virtio_pci_set_guest_notifiers; ++ k->set_host_notifier_mr = virtio_pci_set_host_notifier_mr; + k->vmstate_change = virtio_pci_vmstate_change; + k->pre_plugged = virtio_pci_pre_plugged; + k->device_plugged = virtio_pci_device_plugged; +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 4bcb4f4..5549bb4 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -2472,6 +2472,19 @@ EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq) + return &vq->host_notifier; + } + ++int virtio_queue_set_host_notifier_mr(VirtIODevice *vdev, int n, ++ MemoryRegion *mr, bool assign) ++{ ++ BusState *qbus = qdev_get_parent_bus(DEVICE(vdev)); ++ VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); ++ ++ if (k->set_host_notifier_mr) { ++ return k->set_host_notifier_mr(qbus->parent, n, mr, assign); ++ } ++ ++ return -1; ++} ++ + void virtio_device_set_child_bus_name(VirtIODevice *vdev, char *bus_name) + { + g_free(vdev->bus_name); +diff --git a/include/hw/virtio/virtio-bus.h b/include/hw/virtio/virtio-bus.h +index ced3d2d..7fec9dc 100644 +--- a/include/hw/virtio/virtio-bus.h ++++ b/include/hw/virtio/virtio-bus.h +@@ -52,6 +52,8 @@ typedef struct VirtioBusClass { + bool (*has_extra_state)(DeviceState *d); + bool (*query_guest_notifiers)(DeviceState *d); + int (*set_guest_notifiers)(DeviceState *d, int nvqs, bool assign); ++ int (*set_host_notifier_mr)(DeviceState *d, int n, ++ MemoryRegion *mr, bool assign); + void (*vmstate_change)(DeviceState *d, bool running); + /* + * Expose the features the transport layer supports before +diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h +index 41e13d2..96313e8 100644 +--- a/include/hw/virtio/virtio.h ++++ b/include/hw/virtio/virtio.h +@@ -240,6 +240,8 @@ void virtio_queue_set_align(VirtIODevice *vdev, int n, int align); + void virtio_queue_notify(VirtIODevice *vdev, int n); + uint16_t virtio_queue_vector(VirtIODevice *vdev, int n); + void virtio_queue_set_vector(VirtIODevice *vdev, int n, uint16_t vector); ++int virtio_queue_set_host_notifier_mr(VirtIODevice *vdev, int n, ++ MemoryRegion *mr, bool assign); + int virtio_set_status(VirtIODevice *vdev, uint8_t val); + void virtio_reset(void *opaque); + void virtio_update_irq(VirtIODevice *vdev); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vl-Clean-up-user-creatable-objects-when-exiting.patch b/SOURCES/kvm-vl-Clean-up-user-creatable-objects-when-exiting.patch deleted file mode 100644 index 527d3f7..0000000 --- a/SOURCES/kvm-vl-Clean-up-user-creatable-objects-when-exiting.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 8f6dfc8d04aa713a8a6f1856a5c2fa68100ecd77 Mon Sep 17 00:00:00 2001 -From: Eduardo Habkost -Date: Thu, 19 Oct 2017 01:34:51 +0200 -Subject: [PATCH 62/69] vl: Clean up user-creatable objects when exiting -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Eduardo Habkost -Message-id: <20171019013453.21449-3-ehabkost@redhat.com> -Patchwork-id: 77368 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 2/4] vl: Clean up user-creatable objects when exiting -Bugzilla: 1460848 -RH-Acked-by: Michael S. Tsirkin -RH-Acked-by: Igor Mammedov -RH-Acked-by: Paolo Bonzini - -Delete all user-creatable objects in /objects when exiting QEMU, so they -can perform cleanup actions. - -Signed-off-by: Eduardo Habkost -Message-Id: <20170824192315.5897-2-ehabkost@redhat.com> -Acked-by: Philippe Mathieu-Daudé -Tested-by: Zack Cornelius -Signed-off-by: Eduardo Habkost -(cherry picked from commit 9d5139e543e8579aacd324193680c64fd1463d89) -Signed-off-by: Eduardo Habkost -Signed-off-by: Miroslav Rezanina ---- - include/qom/object_interfaces.h | 8 ++++++++ - qom/object_interfaces.c | 5 +++++ - vl.c | 1 + - 3 files changed, 14 insertions(+) - -diff --git a/include/qom/object_interfaces.h b/include/qom/object_interfaces.h -index fdd7603..3f5f206 100644 ---- a/include/qom/object_interfaces.h -+++ b/include/qom/object_interfaces.h -@@ -148,4 +148,12 @@ int user_creatable_add_opts_foreach(void *opaque, - */ - void user_creatable_del(const char *id, Error **errp); - -+/** -+ * user_creatable_cleanup: -+ * -+ * Delete all user-creatable objects and the user-creatable -+ * objects container. -+ */ -+void user_creatable_cleanup(void); -+ - #endif -diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c -index ff27e06..dbf8878 100644 ---- a/qom/object_interfaces.c -+++ b/qom/object_interfaces.c -@@ -193,6 +193,11 @@ void user_creatable_del(const char *id, Error **errp) - object_unparent(obj); - } - -+void user_creatable_cleanup(void) -+{ -+ object_unparent(object_get_objects_root()); -+} -+ - static void register_types(void) - { - static const TypeInfo uc_interface_info = { -diff --git a/vl.c b/vl.c -index 18b837c..55949e6 100644 ---- a/vl.c -+++ b/vl.c -@@ -4814,6 +4814,7 @@ int main(int argc, char **argv, char **envp) - audio_cleanup(); - monitor_cleanup(); - qemu_chr_cleanup(); -+ user_creatable_cleanup(); - /* TODO: unref root container, check all devices are ok */ - - return 0; --- -1.8.3.1 - diff --git a/SOURCES/kvm-vl-exit-if-maxcpus-is-negative.patch b/SOURCES/kvm-vl-exit-if-maxcpus-is-negative.patch deleted file mode 100644 index cc4fc7b..0000000 --- a/SOURCES/kvm-vl-exit-if-maxcpus-is-negative.patch +++ /dev/null @@ -1,95 +0,0 @@ -From 72c9f52facf418294ce72056d771591debb2a2f0 Mon Sep 17 00:00:00 2001 -From: Sam Bobroff -Date: Fri, 13 Oct 2017 00:56:26 +0200 -Subject: [PATCH 33/34] vl: exit if maxcpus is negative -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Sam Bobroff -Message-id: <1507856186-31186-1-git-send-email-sbobroff@redhat.com> -Patchwork-id: 77221 -O-Subject: [RHEL7.5 qemu-kvm-rhev PATCH] vl: exit if maxcpus is negative -Bugzilla: 1491743 -RH-Acked-by: David Gibson -RH-Acked-by: Laurent Vivier -RH-Acked-by: Thomas Huth - -From: Seeteena Thoufeek - -Signed-off-by: Eduardo Habkost - ----Steps to Reproduce--- - -When passed a negative number to 'maxcpus' parameter, Qemu aborts -with a core dump. - -Run the following command with maxcpus argument as negative number - -ppc64-softmmu/qemu-system-ppc64 --nographic -vga none -machine -pseries,accel=kvm,kvm-type=HV -m size=200g -device virtio-blk-pci, -drive=rootdisk -drive file=/home/images/pegas-1.0-ppc64le.qcow2, -if=none,cache=none,id=rootdisk,format=qcow2 -monitor telnet -:127.0.0.1:1234,server,nowait -net nic,model=virtio -net -user -redir tcp:2000::22 -device nec-usb-xhci -smp 8,cores=1, -threads=1,maxcpus=-12 - -(process:12149): GLib-ERROR **: gmem.c:130: failed to allocate - 18446744073709550568 bytes - -Trace/breakpoint trap - -Reported-by: R.Nageswara Sastry -Signed-off-by: Seeteena Thoufeek -Message-Id: <1504511031-26834-1-git-send-email-s1seetee@linux.vnet.ibm.com> -Reviewed-by: Philippe Mathieu-Daudé -(cherry picked from commit c0dd10991903c552811d8cbe9231055b1b3a7ebd) - -Testing: Run qemu-kvm with "-smp maxcpus=-1". -Signed-off-by: Sam Bobroff -Signed-off-by: Miroslav Rezanina ---- - include/sysemu/sysemu.h | 2 +- - vl.c | 6 +++--- - 2 files changed, 4 insertions(+), 4 deletions(-) - -diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h -index 54fdc4f..d6a9cd7 100644 ---- a/include/sysemu/sysemu.h -+++ b/include/sysemu/sysemu.h -@@ -115,7 +115,7 @@ extern int win2k_install_hack; - extern int alt_grab; - extern int ctrl_grab; - extern int smp_cpus; --extern int max_cpus; -+extern unsigned int max_cpus; - extern int cursor_hide; - extern int graphic_rotate; - extern int no_quit; -diff --git a/vl.c b/vl.c -index 183b7f7..18b837c 100644 ---- a/vl.c -+++ b/vl.c -@@ -164,7 +164,7 @@ Chardev *sclp_hds[MAX_SCLP_CONSOLES]; - int win2k_install_hack = 0; - int singlestep = 0; - int smp_cpus = 1; --int max_cpus = 1; -+unsigned int max_cpus = 1; - int smp_cores = 1; - int smp_threads = 1; - int acpi_enabled = 1; -@@ -4244,8 +4244,8 @@ int main(int argc, char **argv, char **envp) - - machine_class->max_cpus = machine_class->max_cpus ?: 1; /* Default to UP */ - if (max_cpus > machine_class->max_cpus) { -- error_report("Number of SMP CPUs requested (%d) exceeds max CPUs " -- "supported by machine '%s' (%d)", max_cpus, -+ error_report("Invalid SMP CPUs %d. The max CPUs " -+ "supported by machine '%s' is %d", max_cpus, - machine_class->name, machine_class->max_cpus); - exit(1); - } --- -1.8.3.1 - diff --git a/SOURCES/kvm-vmcoreinfo-put-it-in-the-misc-device-category.patch b/SOURCES/kvm-vmcoreinfo-put-it-in-the-misc-device-category.patch deleted file mode 100644 index cb30535..0000000 --- a/SOURCES/kvm-vmcoreinfo-put-it-in-the-misc-device-category.patch +++ /dev/null @@ -1,43 +0,0 @@ -From a65cfbc7d09d1c55d80e6d70a45f163e89437ccf Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Mon, 27 Nov 2017 22:51:10 +0100 -Subject: [PATCH 12/21] vmcoreinfo: put it in the 'misc' device category -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Marc-André Lureau -Message-id: <20171127225111.24518-9-marcandre.lureau@redhat.com> -Patchwork-id: 77927 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 8/9] vmcoreinfo: put it in the 'misc' device category -Bugzilla: 1398633 -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Andrew Jones -RH-Acked-by: Miroslav Rezanina - -Signed-off-by: Marc-André Lureau -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin - -(cherry picked from commit b948bb55dac527ae6b0c5e6dc69d00866a3a6fee) -Signed-off-by: Marc-André Lureau -Signed-off-by: Miroslav Rezanina ---- - hw/misc/vmcoreinfo.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/hw/misc/vmcoreinfo.c b/hw/misc/vmcoreinfo.c -index a618e12..31db57a 100644 ---- a/hw/misc/vmcoreinfo.c -+++ b/hw/misc/vmcoreinfo.c -@@ -79,6 +79,7 @@ static void vmcoreinfo_device_class_init(ObjectClass *klass, void *data) - dc->vmsd = &vmstate_vmcoreinfo; - dc->realize = vmcoreinfo_realize; - dc->hotpluggable = false; -+ set_bit(DEVICE_CATEGORY_MISC, dc->categories); - } - - static const TypeInfo vmcoreinfo_device_info = { --- -1.8.3.1 - diff --git a/SOURCES/kvm-watchdog-wdt_diag288-Mark-diag288-watchdog-as-non-ho.patch b/SOURCES/kvm-watchdog-wdt_diag288-Mark-diag288-watchdog-as-non-ho.patch deleted file mode 100644 index 590c0e7..0000000 --- a/SOURCES/kvm-watchdog-wdt_diag288-Mark-diag288-watchdog-as-non-ho.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 6471fec6246b152ac4ddfb8c13d80c5054e5792f Mon Sep 17 00:00:00 2001 -From: Thomas Huth -Date: Mon, 9 Oct 2017 12:32:43 +0200 -Subject: [PATCH 24/34] watchdog/wdt_diag288: Mark diag288 watchdog as - non-hotpluggable - -RH-Author: Thomas Huth -Message-id: <1507552368-9245-8-git-send-email-thuth@redhat.com> -Patchwork-id: 77027 -O-Subject: [RHEL-7.5 qemu-kvm-ma PATCH 07/12] watchdog/wdt_diag288: Mark diag288 watchdog as non-hotpluggable -Bugzilla: 1492033 -RH-Acked-by: Cornelia Huck -RH-Acked-by: David Gibson -RH-Acked-by: Miroslav Rezanina - -QEMU currently aborts when the user tries to hot-unplug a diag288 -device: - -$ qemu-system-s390x -nographic -nodefaults -S -monitor stdio -QEMU 2.9.92 monitor - type 'help' for more information -(qemu) device_add diag288,id=x -(qemu) device_del x -** -ERROR:qemu/qdev-monitor.c:872:qdev_unplug: assertion failed: (hotplug_ctrl) -Aborted (core dumped) - -The device is not designed as hot-pluggable (it should only be used -via the "-watchdog" parameter), so let's simply remove the possibility -to hotplug it to prevent that users can run into this ugly situation. - -Signed-off-by: Thomas Huth -Message-Id: <1502892528-22618-1-git-send-email-thuth@redhat.com> -Reviewed-by: David Hildenbrand -Signed-off-by: Cornelia Huck -(cherry picked from commit 84ebd3e8c7d4fe955b359b9aac84395907b0412e) -Signed-off-by: Miroslav Rezanina ---- - hw/watchdog/wdt_diag288.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/hw/watchdog/wdt_diag288.c b/hw/watchdog/wdt_diag288.c -index a7b64e2..47f2892 100644 ---- a/hw/watchdog/wdt_diag288.c -+++ b/hw/watchdog/wdt_diag288.c -@@ -121,6 +121,7 @@ static void wdt_diag288_class_init(ObjectClass *klass, void *data) - dc->realize = wdt_diag288_realize; - dc->unrealize = wdt_diag288_unrealize; - dc->reset = wdt_diag288_reset; -+ dc->hotpluggable = false; - set_bit(DEVICE_CATEGORY_MISC, dc->categories); - dc->vmsd = &vmstate_diag288; - diag288->handle_timer = wdt_diag288_handle_timer; --- -1.8.3.1 - diff --git a/SOURCES/kvm-xen-pt-Mark-TYPE_XEN_PT_DEVICE-as-hybrid.patch b/SOURCES/kvm-xen-pt-Mark-TYPE_XEN_PT_DEVICE-as-hybrid.patch deleted file mode 100644 index 5055e74..0000000 --- a/SOURCES/kvm-xen-pt-Mark-TYPE_XEN_PT_DEVICE-as-hybrid.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 031cfd078110d2ccdde9ffa446cb34ebf5592419 Mon Sep 17 00:00:00 2001 -From: Eduardo Habkost -Date: Fri, 20 Oct 2017 18:29:16 +0200 -Subject: [PATCH 11/19] xen/pt: Mark TYPE_XEN_PT_DEVICE as hybrid - -RH-Author: Eduardo Habkost -Message-id: <20171020182917.10771-7-ehabkost@redhat.com> -Patchwork-id: 77426 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH v2 6/7] xen/pt: Mark TYPE_XEN_PT_DEVICE as hybrid -Bugzilla: 1390348 -RH-Acked-by: Marcel Apfelbaum -RH-Acked-by: Michael S. Tsirkin -RH-Acked-by: Laurent Vivier - -xen-pt doesn't set the is_express field, but is supposed to be -able to handle PCI Express devices too. Mark it as hybrid. - -Suggested-by: Jan Beulich -Signed-off-by: Eduardo Habkost -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 6d7023763ec8cc7999468769a0c6bf1335dc3bf4) -Signed-off-by: Eduardo Habkost -Signed-off-by: Miroslav Rezanina ---- - hw/xen/xen_pt.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c -index 01df341..9bba717 100644 ---- a/hw/xen/xen_pt.c -+++ b/hw/xen/xen_pt.c -@@ -966,6 +966,7 @@ static const TypeInfo xen_pci_passthrough_info = { - .class_init = xen_pci_passthrough_class_init, - .interfaces = (InterfaceInfo[]) { - { INTERFACE_CONVENTIONAL_PCI_DEVICE }, -+ { INTERFACE_PCIE_DEVICE }, - { }, - }, - }; --- -1.8.3.1 - diff --git a/SOURCES/kvm-xhci-fix-guest-triggerable-assert.patch b/SOURCES/kvm-xhci-fix-guest-triggerable-assert.patch new file mode 100644 index 0000000..bd0058c --- /dev/null +++ b/SOURCES/kvm-xhci-fix-guest-triggerable-assert.patch @@ -0,0 +1,45 @@ +From 27d574c17a28134a9e8c5cf12b2ae3635aa339c0 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 4 Jul 2018 09:00:54 +0200 +Subject: [PATCH 12/89] xhci: fix guest-triggerable assert + +RH-Author: Gerd Hoffmann +Message-id: <20180704090054.5101-2-kraxel@redhat.com> +Patchwork-id: 81224 +O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/1] xhci: fix guest-triggerable assert +Bugzilla: 1594135 +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Laurent Vivier +RH-Acked-by: Markus Armbruster + +Set xhci into error state instead of throwing a core dump. + +Signed-off-by: Gerd Hoffmann +Message-id: 20180702162752.29233-1-kraxel@redhat.com +(cherry picked from commit 8f36ec708834dfad58af6feb0b69bb0be6077f0f) +Signed-off-by: Miroslav Rezanina +--- + hw/usb/hcd-xhci.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index 181e803..45fcce3 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -1954,7 +1954,12 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid) + for (i = 0; i < length; i++) { + TRBType type; + type = xhci_ring_fetch(xhci, ring, &xfer->trbs[i], NULL); +- assert(type); ++ if (!type) { ++ xhci_die(xhci); ++ xhci_ep_free_xfer(xfer); ++ epctx->kick_active--; ++ return; ++ } + } + xfer->streamid = streamid; + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-xio3130_downstream-Report-error-if-pcie_chassis_add_.patch b/SOURCES/kvm-xio3130_downstream-Report-error-if-pcie_chassis_add_.patch deleted file mode 100644 index a1cfe0e..0000000 --- a/SOURCES/kvm-xio3130_downstream-Report-error-if-pcie_chassis_add_.patch +++ /dev/null @@ -1,53 +0,0 @@ -From f6968c5837e2201172968a49dcd7cd10e1e5a337 Mon Sep 17 00:00:00 2001 -From: Eduardo Habkost -Date: Fri, 20 Oct 2017 18:29:11 +0200 -Subject: [PATCH 06/19] xio3130_downstream: Report error if - pcie_chassis_add_slot() failed - -RH-Author: Eduardo Habkost -Message-id: <20171020182917.10771-2-ehabkost@redhat.com> -Patchwork-id: 77421 -O-Subject: [RHV7.5 qemu-kvm-rhev PATCH v2 1/7] xio3130_downstream: Report error if pcie_chassis_add_slot() failed -Bugzilla: 1390348 -RH-Acked-by: Marcel Apfelbaum -RH-Acked-by: Michael S. Tsirkin -RH-Acked-by: Laurent Vivier - -On commit f8cd1b02 ("pci: Convert to realize"), no error_set*() -call was added for the pcie_chassis_add_slot() error case. -pcie_chassis_add_slot() errors get ignored, making QEMU crash -later. e.g.: - - $ qemu-system-x86_64 -device ioh3420 -device xio3130-downstream - qemu-system-x86_64: memory.c:2166: memory_region_del_subregion: Assertion `subregion->container == mr' failed. - Aborted (core dumped) - -Fix it by reporting the error using error_setg(). - -Fixes: f8cd1b0201c41d88bb97dcafb80348a0e88d8805 -Signed-off-by: Eduardo Habkost -Reviewed-by: Marcel Apfelbaum -Reviewed-by: Michael S. Tsirkin -Signed-off-by: Michael S. Tsirkin -(cherry picked from commit 8b3d26342c4aa171e759e6392fe3b742759d4963) -Signed-off-by: Eduardo Habkost -Signed-off-by: Miroslav Rezanina ---- - hw/pci-bridge/xio3130_downstream.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/hw/pci-bridge/xio3130_downstream.c b/hw/pci-bridge/xio3130_downstream.c -index e706f36..5a882b0 100644 ---- a/hw/pci-bridge/xio3130_downstream.c -+++ b/hw/pci-bridge/xio3130_downstream.c -@@ -94,6 +94,7 @@ static void xio3130_downstream_realize(PCIDevice *d, Error **errp) - pcie_chassis_create(s->chassis); - rc = pcie_chassis_add_slot(s); - if (rc < 0) { -+ error_setg(errp, "Can't add chassis slot, error %d", rc); - goto err_pcie_cap; - } - --- -1.8.3.1 - diff --git a/SOURCES/qemu-guest-agent.service b/SOURCES/qemu-guest-agent.service index ab50e75..b33e951 100644 --- a/SOURCES/qemu-guest-agent.service +++ b/SOURCES/qemu-guest-agent.service @@ -18,4 +18,3 @@ RestartSec=0 [Install] WantedBy=dev-virtio\x2dports-org.qemu.guest_agent.0.device - diff --git a/SPECS/qemu-kvm.spec b/SPECS/qemu-kvm.spec index 6825e64..339d16a 100644 --- a/SPECS/qemu-kvm.spec +++ b/SPECS/qemu-kvm.spec @@ -5,6 +5,7 @@ %global have_usbredir 1 %global have_spice 1 +%global have_opengl 1 %global have_fdt 0 %global have_gluster 1 %global have_kvm_setup 0 @@ -35,6 +36,7 @@ %global have_vxhs 1 %else %global have_spice 0 + %global have_opengl 0 %global have_gluster 0 %endif %ifarch %{power64} @@ -105,11 +107,11 @@ Obsoletes: %1%{rhel_ma_suffix} < %{obsoletes_version2} \ Summary: QEMU is a machine emulator and virtualizer Name: %{pkgname}%{?pkgsuffix} -Version: 2.10.0 -Release: 21%{?dist}.4 +Version: 2.12.0 +Release: 18%{?dist} # Epoch because we pushed a qemu-1.0 package. AIUI this can't ever be dropped Epoch: 10 -License: GPLv2+ and LGPLv2+ and BSD +License: GPLv2 and GPLv2+ and CC-BY Group: Development/Tools URL: http://www.qemu.org/ %if %{rhev} @@ -154,7 +156,7 @@ Requires: usbredir >= 0.7.1 %define _smp_mflags %{nil} %endif -Source0: http://wiki.qemu.org/download/qemu-2.10.0.tar.xz +Source0: http://wiki.qemu.org/download/qemu-2.12.0.tar.xz # Creates /dev/kvm Source3: 80-kvm.rules @@ -189,886 +191,929 @@ Source30: kvm-s390x.conf Source31: kvm-x86.conf Source32: qemu-pr-helper.service Source33: qemu-pr-helper.socket - - - -Patch2: 0002-Initial-redhat-build.patch -Patch3: 0003-Add-RHEL-7-machine-types.patch -Patch4: 0004-Enable-disable-devices-for-RHEL-7.patch -Patch5: 0005-Use-kvm-by-default.patch -Patch6: 0006-add-qxl_screendump-monitor-command.patch -Patch7: 0007-seabios-paravirt-allow-more-than-1TB-in-x86-guest.patch -Patch8: 0008-monitor-Remove-usb_add-del-commands-for-Red-Hat-Ente.patch -Patch9: 0009-monitor-Remove-host_net_add-remove-for-Red-Hat-Enter.patch -Patch10: 0010-vfio-cap-number-of-devices-that-can-be-assigned.patch -Patch11: 0011-QMP-Forward-port-__com.redhat_drive_del-from-RHEL-6.patch -Patch12: 0012-QMP-Forward-port-__com.redhat_drive_add-from-RHEL-6.patch -Patch13: 0013-HMP-Forward-port-__com.redhat_drive_add-from-RHEL-6.patch -Patch14: 0014-Add-support-statement-to-help-output.patch -Patch15: 0015-vl-Round-memory-sizes-below-2MiB-up-to-2MiB.patch -Patch16: 0016-use-recommended-max-vcpu-count.patch -Patch17: 0017-Add-support-for-simpletrace.patch -Patch18: 0018-Use-qemu-kvm-in-documentation-instead-of-qemu-system.patch -Patch19: 0019-qmp-add-__com.redhat_reason-to-the-BLOCK_IO_ERROR-ev.patch -Patch20: 0020-Migration-compat-for-pckbd.patch -Patch21: 0021-Migration-compat-for-fdc.patch -Patch22: 0022-RHEL-Set-vcpus-hard-limit-to-240-for-Power.patch -Patch23: 0023-spapr-Reduce-advertised-max-LUNs-for-spapr_vscsi.patch -Patch24: 0024-qmp-Report-__com.redhat_drive_add-error-to-monitor.patch -Patch25: 0025-RHEL-only-hw-char-pl011-fix-SBSA-reset.patch -Patch26: 0026-blockdev-ignore-cache-options-for-empty-CDROM-drives.patch -Patch27: 0027-Revert-kvm_stat-Remove.patch -Patch28: 0028-migcompat-e1000e-Work-around-7.3-msi-intr_state-fiel.patch -Patch29: 0029-migcompat-rtl8139-Work-around-version-bump.patch -Patch30: 0030-usb-xhci-Fix-PCI-capability-order.patch -Patch31: 0031-blockdev-ignore-aio-native-for-empty-drives.patch -Patch32: 0032-scsi-Disable-deprecated-implicit-SCSI-HBA-creation-m.patch -Patch33: 0033-virtio-scsi-Reject-scsi-cd-if-data-plane-enabled-RHE.patch -Patch34: 0034-hmp-fix-dump-quest-memory-segfault-ppc.patch -Patch35: 0035-hmp-fix-dump-quest-memory-segfault-arm.patch -Patch36: 0036-dump-do-not-dump-non-existent-guest-memory.patch -Patch37: 0037-tests-hmp-test-none-machine-with-memory.patch -Patch38: 0038-vfio-spapr-Fix-levels-calculation.patch -# For bz#1489670 - Hot-unplugging a vhost network device leaks references to VFIOPCIDevice's -Patch39: kvm-vhost-Release-memory-references-on-cleanup.patch -# For bz#1491647 - [RFE] Enable seccomp (sandbox) support in QEMU for s390x -Patch40: kvm-configure-Allow-enable-seccomp-on-s390x-too.patch -# For bz#1448344 - Failed to hot unplug cpu core which hotplugged in early boot stages -Patch41: kvm-hw-ppc-spapr_drc.c-change-spapr_drc_needed-to-use-dr.patch -# For bz#1448344 - Failed to hot unplug cpu core which hotplugged in early boot stages -Patch42: kvm-hw-ppc-clear-pending_events-on-machine-reset.patch -# For bz#1448344 - Failed to hot unplug cpu core which hotplugged in early boot stages -Patch43: kvm-hw-ppc-CAS-reset-on-early-device-hotplug.patch -# For bz#1448344 - Failed to hot unplug cpu core which hotplugged in early boot stages -Patch44: kvm-spapr-fix-CAS-generated-reset.patch -# For bz#1498754 - Definition of HW_COMPAT_RHEL7_3 is not correct -Patch45: kvm-redhat-fix-HW_COMPAT_RHEL7_3.patch -# For bz#1486643 - CVE-2017-13672 qemu-kvm-rhev: Qemu: vga: OOB read access during display update [rhel-7.5] -Patch46: kvm-vga-stop-passing-pointers-to-vga_draw_line-functions.patch -# For bz#1494548 - Disable ais facility on s390x -Patch47: kvm-s390x-ais-for-2.10-stable-disable-ais-facility.patch -# For bz#1494548 - Disable ais facility on s390x -Patch48: kvm-s390x-cpumodel-remove-ais-from-z14-default-model-als.patch -# For bz#1479178 - QEMU does not yet have support for setting the virtual SMT mode on Power 9, which is required to run with KVM and more than one thread per core. -Patch49: kvm-PPC-KVM-Support-machine-option-to-set-VSMT-mode.patch -# For bz#1482478 - Fail to quit source qemu when do live migration after mirroring guest to NBD server -Patch50: kvm-nbd-client-avoid-read_reply_co-entry-if-send-failed.patch -# For bz#1482478 - Fail to quit source qemu when do live migration after mirroring guest to NBD server -Patch51: kvm-qemu-iotests-improve-nbd-fault-injector.py-startup-p.patch -# For bz#1482478 - Fail to quit source qemu when do live migration after mirroring guest to NBD server -Patch52: kvm-qemu-iotests-test-NBD-over-UNIX-domain-sockets-in-08.patch -# For bz#1482478 - Fail to quit source qemu when do live migration after mirroring guest to NBD server -Patch53: kvm-block-nbd-client-nbd_co_send_request-fix-return-code.patch -# For bz#1492033 - Disable unwanted device in QEMU for s390x -Patch54: kvm-usb-drop-HOST_USB.patch -# For bz#1492033 - Disable unwanted device in QEMU for s390x -Patch55: kvm-usb-only-build-usb-host-with-CONFIG_USB-y.patch -# For bz#1492033 - Disable unwanted device in QEMU for s390x -Patch56: kvm-usb-fix-libusb-config-variable-name.patch -# For bz#1492033 - Disable unwanted device in QEMU for s390x -Patch57: kvm-usb-fix-host-stub.c-build-race.patch -# For bz#1492033 - Disable unwanted device in QEMU for s390x -Patch58: kvm-s390x-s390-stattrib-Mark-the-storage-attribute-as-no.patch -# For bz#1492033 - Disable unwanted device in QEMU for s390x -Patch59: kvm-s390x-s390-skeys-Mark-the-storage-key-devices-with-u.patch -# For bz#1492033 - Disable unwanted device in QEMU for s390x -Patch60: kvm-watchdog-wdt_diag288-Mark-diag288-watchdog-as-non-ho.patch -# For bz#1492033 - Disable unwanted device in QEMU for s390x -Patch61: kvm-s390x-ipl-The-s390-ipl-device-is-not-hot-pluggable.patch -# For bz#1492033 - Disable unwanted device in QEMU for s390x -Patch62: kvm-hw-s390x-Mark-the-sclpquiesce-device-with-user_creat.patch -# For bz#1492033 - Disable unwanted device in QEMU for s390x -Patch63: kvm-s390x-sclp-mark-sclp-cpu-hotplug-as-non-usercreatabl.patch -# For bz#1492033 - Disable unwanted device in QEMU for s390x -Patch64: kvm-s390x-sclp-Mark-the-sclp-device-with-user_creatable-.patch -# For bz#1492033 - Disable unwanted device in QEMU for s390x -Patch65: kvm-RHEL-Disable-vfio-ccw-and-x-terminal3270-devices.patch -# For bz#1473292 - Need RHEL-specific machine types for qemu-kvm on s390x -Patch66: kvm-s390x-css-fix-css-migration-compat-handling.patch -# For bz#1473292 - Need RHEL-specific machine types for qemu-kvm on s390x -Patch67: kvm-RHEL-Add-RHEL7-machine-type-for-qemu-on-s390x.patch -# For bz#1490869 - [Pegas1.0] qemu device spapr-nvram crashes with SIGABRT (qemu-kvm) -Patch68: kvm-hw-nvram-spapr_nvram-Device-can-not-be-created-by-th.patch -# For bz#1491743 - qemu crashes with 'Abort' when a negative number is used for 'maxcpus' argument (qemu-kvm) -Patch69: kvm-vl-exit-if-maxcpus-is-negative.patch -# For bz#1460595 - [virtio-vga]Display 2 should be dropped when guest reboot -Patch70: kvm-virtio-gpu-don-t-clear-QemuUIInfo-information-on-res.patch -# For bz#1486648 - CVE-2017-13673 qemu-kvm-rhev: Qemu: vga: reachable assert failure during during display update [rhel-7.5] -Patch71: kvm-vga-fix-display-update-region-calculation-split-scre.patch -# For bz#1445834 - Add support for AMD EPYC processors -Patch72: kvm-target-i386-cpu-Add-new-EPYC-CPU-model.patch -# For bz#1498865 - There is no switch to build qemu-kvm-rhev or qemu-kvm-ma packages -Patch73: kvm-redhat-add-CONFIG_RHV-flag.patch -# For bz#1449067 - [RFE] Device passthrough support for VT-d emulation -Patch74: kvm-intel_iommu-fix-missing-BQL-in-pt-fast-path.patch -# For bz#1478478 - RHEL 7.5 machine types for Power 8 and 9 - qemu-kvm-ma -Patch75: kvm-redhat-define-HW_COMPAT_RHEL7_4.patch -# For bz#1478478 - RHEL 7.5 machine types for Power 8 and 9 - qemu-kvm-ma -Patch76: kvm-redhat-define-pseries-rhel7.5.0-machine-type.patch -# For bz#1478478 - RHEL 7.5 machine types for Power 8 and 9 - qemu-kvm-ma -Patch77: kvm-qemu-kvm-ma-define-only-pseries-rhel7.5.0-machine-ty.patch -# For bz#1499011 - 7.5: x86 machine types for 7.5 -Patch78: kvm-Create-x86-7.5.0-machine-types.patch -# For bz#1500347 - [Hyper-V][RHEL-7.4]Nested virt: Windows guest doesn't use TSC page when Hyper-V role is enabled -Patch79: kvm-i386-kvm-use-a-switch-statement-for-MSR-detection.patch -# For bz#1500347 - [Hyper-V][RHEL-7.4]Nested virt: Windows guest doesn't use TSC page when Hyper-V role is enabled -Patch80: kvm-i386-kvm-set-tsc_khz-before-configuring-Hyper-V-CPUI.patch -# For bz#1500347 - [Hyper-V][RHEL-7.4]Nested virt: Windows guest doesn't use TSC page when Hyper-V role is enabled -Patch81: kvm-i386-kvm-introduce-tsc_is_stable_and_known.patch -# For bz#1500347 - [Hyper-V][RHEL-7.4]Nested virt: Windows guest doesn't use TSC page when Hyper-V role is enabled -Patch82: kvm-i386-kvm-advertise-Hyper-V-frequency-MSRs.patch -# For bz#1489800 - q35/ovmf: Machine type compat vs OVMF vs windows -Patch83: kvm-acpi-Force-rev1-FADT-on-old-q35-machine-types.patch -# For bz#1489800 - q35/ovmf: Machine type compat vs OVMF vs windows -Patch84: kvm-pc-make-pc_rom-RO-only-on-new-machine-types.patch -# For bz#1378241 - QEMU image file locking -Patch85: kvm-osdep-Force-define-F_OFD_GETLK-RHEL-only.patch -# For bz#1498496 - Handle device tree changes in QEMU 2.10.0 -Patch86: kvm-Disable-vhost-user-scsi-and-vhost-user-scsi-pci.patch -# For bz#1498496 - Handle device tree changes in QEMU 2.10.0 -Patch87: kvm-Disable-sm501-and-sysbus-sm501-devices.patch -# For bz#1485399 - Backport selective allocation of PGSTE to avoid global vm.allocate_pgste -Patch88: kvm-configure-enable-s390-pgste-linker-option.patch -# For bz#1498662 - RHEL-7.5 machine machine type for aarch64 (qemu-kvm-ma) -Patch90: kvm-arm-virt-Add-RHEL-7.5-machine-type.patch -# For bz#1497137 - Update kvm_stat -Patch91: kvm-tools-kvm_stat-hide-cursor.patch -# For bz#1497137 - Update kvm_stat -Patch92: kvm-tools-kvm_stat-catch-curses-exceptions-only.patch -# For bz#1497137 - Update kvm_stat -Patch93: kvm-tools-kvm_stat-handle-SIGINT-in-log-and-batch-modes.patch -# For bz#1497137 - Update kvm_stat -Patch94: kvm-tools-kvm_stat-fix-misc-glitches.patch -# For bz#1497137 - Update kvm_stat -Patch95: kvm-tools-kvm_stat-fix-trace-setup-glitch-on-field-updat.patch -# For bz#1497137 - Update kvm_stat -Patch96: kvm-tools-kvm_stat-full-PEP8-compliance.patch -# For bz#1497137 - Update kvm_stat -Patch97: kvm-tools-kvm_stat-reduce-perceived-idle-time-on-filter-.patch -# For bz#1497137 - Update kvm_stat -Patch98: kvm-tools-kvm_stat-document-list-of-interactive-commands.patch -# For bz#1497137 - Update kvm_stat -Patch99: kvm-tools-kvm_stat-display-guest-name-when-using-pid-fil.patch -# For bz#1497137 - Update kvm_stat -Patch100: kvm-tools-kvm_stat-remove-pid-filter-on-empty-input.patch -# For bz#1497137 - Update kvm_stat -Patch101: kvm-tools-kvm_stat-print-error-messages-on-faulty-pid-fi.patch -# For bz#1497137 - Update kvm_stat -Patch102: kvm-tools-kvm_stat-display-regex-when-set-to-non-default.patch -# For bz#1497137 - Update kvm_stat -Patch103: kvm-tools-kvm_stat-remove-regex-filter-on-empty-input.patch -# For bz#1497137 - Update kvm_stat -Patch104: kvm-tools-kvm_stat-add-option-guest.patch -# For bz#1497137 - Update kvm_stat -Patch105: kvm-tools-kvm_stat-add-interactive-command-c.patch -# For bz#1497137 - Update kvm_stat -Patch106: kvm-tools-kvm_stat-add-interactive-command-r.patch -# For bz#1497137 - Update kvm_stat -Patch107: kvm-tools-kvm_stat-add-Total-column.patch -# For bz#1497137 - Update kvm_stat -Patch108: kvm-tools-kvm_stat-fix-typo.patch -# For bz#1497137 - Update kvm_stat -Patch109: kvm-tools-kvm_stat-fix-event-counts-display-for-interrup.patch -# For bz#1497137 - Update kvm_stat -Patch110: kvm-tools-kvm_stat-fix-undue-use-of-initial-sleeptime.patch -# For bz#1497137 - Update kvm_stat -Patch111: kvm-tools-kvm_stat-remove-unnecessary-header-redraws.patch -# For bz#1497137 - Update kvm_stat -Patch112: kvm-tools-kvm_stat-simplify-line-print-logic.patch -# For bz#1497137 - Update kvm_stat -Patch113: kvm-tools-kvm_stat-removed-unused-function.patch -# For bz#1497137 - Update kvm_stat -Patch114: kvm-tools-kvm_stat-remove-extra-statement.patch -# For bz#1497137 - Update kvm_stat -Patch115: kvm-tools-kvm_stat-simplify-initializers.patch -# For bz#1497137 - Update kvm_stat -Patch116: kvm-tools-kvm_stat-move-functions-to-corresponding-class.patch -# For bz#1497137 - Update kvm_stat -Patch117: kvm-tools-kvm_stat-show-cursor-in-selection-screens.patch -# For bz#1497137 - Update kvm_stat -Patch118: kvm-tools-kvm_stat-display-message-indicating-lack-of-ev.patch -# For bz#1497137 - Update kvm_stat -Patch119: kvm-tools-kvm_stat-make-heading-look-a-bit-more-like-top.patch -# For bz#1497137 - Update kvm_stat -Patch120: kvm-tools-kvm_stat-rename-Current-column-to-CurAvg-s.patch -# For bz#1497137 - Update kvm_stat -Patch121: kvm-tools-kvm_stat-add-new-interactive-command-h.patch -# For bz#1497137 - Update kvm_stat -Patch122: kvm-tools-kvm_stat-add-new-interactive-command-s.patch -# For bz#1497137 - Update kvm_stat -Patch123: kvm-tools-kvm_stat-add-new-interactive-command-o.patch -# For bz#1497137 - Update kvm_stat -Patch124: kvm-tools-kvm_stat-display-guest-list-in-pid-guest-selec.patch -# For bz#1497137 - Update kvm_stat -Patch125: kvm-tools-kvm_stat-display-guest-list-in-pid-guest-sele2.patch -# For bz#1497137 - Update kvm_stat -Patch126: kvm-tools-kvm_stat-add-new-command-line-switch-i.patch -# For bz#1497137 - Update kvm_stat -Patch127: kvm-tools-kvm_stat-add-new-interactive-command-b.patch -# For bz#1497137 - Update kvm_stat -Patch128: kvm-tools-kvm_stat-use-variables-instead-of-hard-paths-i.patch -# For bz#1497137 - Update kvm_stat -Patch129: kvm-tools-kvm_stat-add-f-help-to-get-the-available-event.patch -# For bz#1460848 - RFE: Enhance qemu to support freeing memory before exit when using memory-backend-file -Patch130: kvm-iothread-Make-iothread_stop-idempotent.patch -# For bz#1460848 - RFE: Enhance qemu to support freeing memory before exit when using memory-backend-file -Patch131: kvm-vl-Clean-up-user-creatable-objects-when-exiting.patch -# For bz#1460848 - RFE: Enhance qemu to support freeing memory before exit when using memory-backend-file -Patch132: kvm-osdep-Define-QEMU_MADV_REMOVE.patch -# For bz#1460848 - RFE: Enhance qemu to support freeing memory before exit when using memory-backend-file -Patch133: kvm-hostmem-file-Add-discard-data-option.patch -# For bz#1503998 - Remove redundant "user_creatable = false" flags from the downstream qemu-kvm-rhev code -Patch134: kvm-hw-dma-i8257-Remove-redundant-downstream-user_creata.patch -# For bz#1503998 - Remove redundant "user_creatable = false" flags from the downstream qemu-kvm-rhev code -Patch135: kvm-hw-pci-host-q35-Remove-redundant-downstream-user_cre.patch -# For bz#1503998 - Remove redundant "user_creatable = false" flags from the downstream qemu-kvm-rhev code -Patch136: kvm-hw-Remove-the-redundant-user_creatable-false-from-SY.patch -# For bz#1499320 - qemu-kvm-ma differentiation - cpu unplug -Patch137: kvm-spapr-disable-cpu-hot-remove.patch -# For bz#1501301 - CVE-2017-15289 qemu-kvm-rhev: Qemu: cirrus: OOB access issue in mode4and5 write functions [rhel-7.5] -Patch138: kvm-vga-drop-line_offset-variable.patch -# For bz#1501301 - CVE-2017-15289 qemu-kvm-rhev: Qemu: cirrus: OOB access issue in mode4and5 write functions [rhel-7.5] -Patch139: kvm-vga-handle-cirrus-vbe-mode-wraparounds.patch -# For bz#1501301 - CVE-2017-15289 qemu-kvm-rhev: Qemu: cirrus: OOB access issue in mode4and5 write functions [rhel-7.5] -Patch140: kvm-cirrus-fix-oob-access-in-mode4and5-write-functions.patch -# For bz#1498817 - Vhost IOMMU support regression since qemu-kvm-rhev-2.9.0-16.el7_4.5 -Patch141: kvm-exec-add-page_mask-for-address_space_do_translate.patch -# For bz#1498817 - Vhost IOMMU support regression since qemu-kvm-rhev-2.9.0-16.el7_4.5 -Patch142: kvm-exec-simplify-address_space_get_iotlb_entry.patch -# For bz#1390348 - PCI: Provide to libvirt a new query command whether a device is PCI/PCIe/hybrid -Patch143: kvm-xio3130_downstream-Report-error-if-pcie_chassis_add_.patch -# For bz#1390348 - PCI: Provide to libvirt a new query command whether a device is PCI/PCIe/hybrid -Patch144: kvm-pci-conventional-pci-device-and-pci-express-device-i.patch -# For bz#1390348 - PCI: Provide to libvirt a new query command whether a device is PCI/PCIe/hybrid -Patch145: kvm-pci-Add-interface-names-to-hybrid-PCI-devices.patch -# For bz#1390348 - PCI: Provide to libvirt a new query command whether a device is PCI/PCIe/hybrid -Patch146: kvm-pci-Add-INTERFACE_PCIE_DEVICE-to-all-PCIe-devices.patch -# For bz#1390348 - PCI: Provide to libvirt a new query command whether a device is PCI/PCIe/hybrid -Patch147: kvm-pci-Add-INTERFACE_CONVENTIONAL_PCI_DEVICE-to-Convent.patch -# For bz#1390348 - PCI: Provide to libvirt a new query command whether a device is PCI/PCIe/hybrid -Patch148: kvm-xen-pt-Mark-TYPE_XEN_PT_DEVICE-as-hybrid.patch -# For bz#1390348 - PCI: Provide to libvirt a new query command whether a device is PCI/PCIe/hybrid -Patch149: kvm-pci-Validate-interfaces-on-base_class_init.patch -# For bz#1497120 - migration+new block migration race: bdrv_co_do_pwritev: Assertion `!(bs->open_flags & 0x0800)' failed -Patch150: kvm-migration-Add-pause-before-switchover-capability.patch -# For bz#1497120 - migration+new block migration race: bdrv_co_do_pwritev: Assertion `!(bs->open_flags & 0x0800)' failed -Patch151: kvm-migration-Add-pre-switchover-and-device-statuses.patch -# For bz#1497120 - migration+new block migration race: bdrv_co_do_pwritev: Assertion `!(bs->open_flags & 0x0800)' failed -Patch152: kvm-migration-Wait-for-semaphore-before-completing-migra.patch -# For bz#1497120 - migration+new block migration race: bdrv_co_do_pwritev: Assertion `!(bs->open_flags & 0x0800)' failed -Patch153: kvm-migration-migrate-continue.patch -# For bz#1497120 - migration+new block migration race: bdrv_co_do_pwritev: Assertion `!(bs->open_flags & 0x0800)' failed -Patch154: kvm-migrate-HMP-migate_continue.patch -# For bz#1497120 - migration+new block migration race: bdrv_co_do_pwritev: Assertion `!(bs->open_flags & 0x0800)' failed -Patch155: kvm-migration-allow-cancel-to-unpause.patch -# For bz#1497120 - migration+new block migration race: bdrv_co_do_pwritev: Assertion `!(bs->open_flags & 0x0800)' failed -Patch156: kvm-migration-pause-before-switchover-for-postcopy.patch -# For bz#1478469 - RHEL 7.5 machine types for Power 8 and 9 - qemu-kvm-rhev -Patch157: kvm-qemu-kvm-rhev-only-allows-pseries-rhel7.5.0-machine-.patch -# For bz#1503128 - update reverse keymaps for qemu vnc server -Patch158: kvm-pc-bios-keymaps-keymaps-update.patch -# For bz#1508799 - qemu-kvm core dumped when doing 'savevm/loadvm/delvm' for the second time -Patch159: kvm-migration-Reset-rather-than-destroy-main_thread_load.patch -# For bz#1508799 - qemu-kvm core dumped when doing 'savevm/loadvm/delvm' for the second time -Patch160: kvm-snapshot-tests-Try-loadvm-twice.patch -# For bz#1508271 - Migration is failed from host RHEL7.4.z to host RHEL7.5 with "-machine pseries-rhel7.4.0 -device pci-bridge,id=pci_bridge,bus=pci.0,addr=03,chassis_nr=1" -Patch161: kvm-machine-compat-pci_bridge-shpc-always-enable.patch -# For bz#1460957 - Implement INTx to GSI routing on ARM virt -Patch162: kvm-hw-pci-host-gpex-Set-INTx-index-gsi-mapping.patch -# For bz#1460957 - Implement INTx to GSI routing on ARM virt -Patch163: kvm-hw-arm-virt-Set-INTx-gsi-mapping.patch -# For bz#1460957 - Implement INTx to GSI routing on ARM virt -Patch164: kvm-hw-pci-host-gpex-Implement-PCI-INTx-routing.patch -# For bz#1460957 - Implement INTx to GSI routing on ARM virt -Patch165: kvm-hw-pci-host-gpex-Improve-INTX-to-gsi-routing-error-c.patch -# For bz#1501124 - CVE-2017-14167 qemu-kvm-rhev: Qemu: i386: multiboot OOB access while loading kernel image [rhel-7.5] -Patch166: kvm-multiboot-validate-multiboot-header-address-values.patch -# For bz#1510001 - Pegas1.0 - qemu crashed during "info cpus" in monitor with change in default cpu in hotplug/unplug sequence (kvm) -Patch167: kvm-monitor-fix-dangling-CPU-pointer.patch -# For bz#1445460 - EEH freeze up when reattaching an i40evf VF to host -Patch168: kvm-qdev-store-DeviceState-s-canonical-path-to-use-when-.patch -# For bz#1445460 - EEH freeze up when reattaching an i40evf VF to host -Patch169: kvm-Revert-qdev-Free-QemuOpts-when-the-QOM-path-goes-awa.patch -# For bz#1445460 - EEH freeze up when reattaching an i40evf VF to host -Patch170: kvm-qdev-defer-DEVICE_DEL-event-until-instance_finalize.patch -# For bz#1504138 - Disable older CPU models in qemu-kvm-ma on s390x -Patch171: kvm-s390x-print-CPU-definitions-in-sorted-order.patch -# For bz#1504138 - Disable older CPU models in qemu-kvm-ma on s390x -Patch172: kvm-s390x-cpumodel-Disable-unsupported-CPU-models.patch -# For bz#1437113 - PCIe: Allow configuring Generic PCIe Root Ports MMIO Window -Patch173: kvm-hw-pci-introduce-bridge-only-vendor-specific-capabil.patch -# For bz#1437113 - PCIe: Allow configuring Generic PCIe Root Ports MMIO Window -Patch174: kvm-hw-pci-add-QEMU-specific-PCI-capability-to-the-Gener.patch -# For bz#1508886 - QEMU's AIO subsystem gets stuck inhibiting all I/O operations on virtio-blk-pci devices -Patch175: kvm-util-async-use-atomic_mb_set-in-qemu_bh_cancel.patch -# For bz#1344299 - PCIe: Add an option to PCIe ports to disable IO port space support -Patch176: kvm-hw-gen_pcie_root_port-make-IO-RO-0-on-IO-disabled.patch -# For bz#1511312 - Migrate an VM with pci-bridge or pcie-root-port failed -Patch177: kvm-pcie_root_port-Fix-x-migrate-msix-compat.patch -# For bz#1511312 - Migrate an VM with pci-bridge or pcie-root-port failed -Patch178: kvm-q35-Fix-mismerge.patch -# For bz#1481593 - Boot guest failed with "src/central_freelist.cc:333] tcmalloc: allocation failed 196608" when 465 disks are attached to 465 pci-bridges -Patch179: kvm-virtio-pci-Replace-modern_as-with-direct-access-to-m.patch -# For bz#1481593 - Boot guest failed with "src/central_freelist.cc:333] tcmalloc: allocation failed 196608" when 465 disks are attached to 465 pci-bridges -Patch180: kvm-atomic-update-documentation.patch -# For bz#1481593 - Boot guest failed with "src/central_freelist.cc:333] tcmalloc: allocation failed 196608" when 465 disks are attached to 465 pci-bridges -Patch181: kvm-memory-avoid-resurrection-of-dead-FlatViews.patch -# For bz#1481593 - Boot guest failed with "src/central_freelist.cc:333] tcmalloc: allocation failed 196608" when 465 disks are attached to 465 pci-bridges -Patch182: kvm-exec-Explicitly-export-target-AS-from-address_space_.patch -# For bz#1481593 - Boot guest failed with "src/central_freelist.cc:333] tcmalloc: allocation failed 196608" when 465 disks are attached to 465 pci-bridges -Patch183: kvm-memory-Open-code-FlatView-rendering.patch -# For bz#1481593 - Boot guest failed with "src/central_freelist.cc:333] tcmalloc: allocation failed 196608" when 465 disks are attached to 465 pci-bridges -Patch184: kvm-memory-Move-FlatView-allocation-to-a-helper.patch -# For bz#1481593 - Boot guest failed with "src/central_freelist.cc:333] tcmalloc: allocation failed 196608" when 465 disks are attached to 465 pci-bridges -Patch185: kvm-memory-Move-AddressSpaceDispatch-from-AddressSpace-t.patch -# For bz#1481593 - Boot guest failed with "src/central_freelist.cc:333] tcmalloc: allocation failed 196608" when 465 disks are attached to 465 pci-bridges -Patch186: kvm-memory-Remove-AddressSpace-pointer-from-AddressSpace.patch -# For bz#1481593 - Boot guest failed with "src/central_freelist.cc:333] tcmalloc: allocation failed 196608" when 465 disks are attached to 465 pci-bridges -Patch187: kvm-memory-Switch-memory-from-using-AddressSpace-to-Flat.patch -# For bz#1481593 - Boot guest failed with "src/central_freelist.cc:333] tcmalloc: allocation failed 196608" when 465 disks are attached to 465 pci-bridges -Patch188: kvm-memory-Cleanup-after-switching-to-FlatView.patch -# For bz#1481593 - Boot guest failed with "src/central_freelist.cc:333] tcmalloc: allocation failed 196608" when 465 disks are attached to 465 pci-bridges -Patch189: kvm-memory-Rename-mem_begin-mem_commit-mem_add-helpers.patch -# For bz#1481593 - Boot guest failed with "src/central_freelist.cc:333] tcmalloc: allocation failed 196608" when 465 disks are attached to 465 pci-bridges -Patch190: kvm-memory-Store-physical-root-MR-in-FlatView.patch -# For bz#1481593 - Boot guest failed with "src/central_freelist.cc:333] tcmalloc: allocation failed 196608" when 465 disks are attached to 465 pci-bridges -Patch191: kvm-memory-Alloc-dispatch-tree-where-topology-is-generar.patch -# For bz#1481593 - Boot guest failed with "src/central_freelist.cc:333] tcmalloc: allocation failed 196608" when 465 disks are attached to 465 pci-bridges -Patch192: kvm-memory-Move-address_space_update_ioeventfds.patch -# For bz#1481593 - Boot guest failed with "src/central_freelist.cc:333] tcmalloc: allocation failed 196608" when 465 disks are attached to 465 pci-bridges -Patch193: kvm-memory-Share-FlatView-s-and-dispatch-trees-between-a.patch -# For bz#1481593 - Boot guest failed with "src/central_freelist.cc:333] tcmalloc: allocation failed 196608" when 465 disks are attached to 465 pci-bridges -Patch194: kvm-memory-Do-not-allocate-FlatView-in-address_space_ini.patch -# For bz#1481593 - Boot guest failed with "src/central_freelist.cc:333] tcmalloc: allocation failed 196608" when 465 disks are attached to 465 pci-bridges -Patch195: kvm-memory-Rework-info-mtree-to-print-flat-views-and-dis.patch -# For bz#1481593 - Boot guest failed with "src/central_freelist.cc:333] tcmalloc: allocation failed 196608" when 465 disks are attached to 465 pci-bridges -Patch196: kvm-memory-Get-rid-of-address_space_init_shareable.patch -# For bz#1481593 - Boot guest failed with "src/central_freelist.cc:333] tcmalloc: allocation failed 196608" when 465 disks are attached to 465 pci-bridges -Patch197: kvm-memory-Create-FlatView-directly.patch -# For bz#1481593 - Boot guest failed with "src/central_freelist.cc:333] tcmalloc: allocation failed 196608" when 465 disks are attached to 465 pci-bridges -Patch198: kvm-memory-trace-FlatView-creation-and-destruction.patch -# For bz#1481593 - Boot guest failed with "src/central_freelist.cc:333] tcmalloc: allocation failed 196608" when 465 disks are attached to 465 pci-bridges -Patch199: kvm-memory-seek-FlatView-sharing-candidates-among-childr.patch -# For bz#1481593 - Boot guest failed with "src/central_freelist.cc:333] tcmalloc: allocation failed 196608" when 465 disks are attached to 465 pci-bridges -Patch200: kvm-memory-Share-special-empty-FlatView.patch -# For bz#1390346 - PCI: Reserve MMIO space over 4G for PCI hotplug -Patch201: kvm-hw-pci-host-Fix-x86-Host-Bridges-64bit-PCI-hole.patch -# For bz#1492295 - Guest hit call trace with iothrottling(iops) after the status from stop to cont during doing io testing -Patch202: kvm-block-move-ThrottleGroup-membership-to-ThrottleGroup.patch -# For bz#1492295 - Guest hit call trace with iothrottling(iops) after the status from stop to cont during doing io testing -Patch203: kvm-block-add-aio_context-field-in-ThrottleGroupMember.patch -# For bz#1492295 - Guest hit call trace with iothrottling(iops) after the status from stop to cont during doing io testing -Patch204: kvm-block-tidy-ThrottleGroupMember-initializations.patch -# For bz#1492295 - Guest hit call trace with iothrottling(iops) after the status from stop to cont during doing io testing -Patch205: kvm-block-all-I-O-should-be-completed-before-removing-th.patch -# For bz#1492295 - Guest hit call trace with iothrottling(iops) after the status from stop to cont during doing io testing -Patch206: kvm-throttle-groups-drain-before-detaching-ThrottleState.patch -# For bz#1492295 - Guest hit call trace with iothrottling(iops) after the status from stop to cont during doing io testing -Patch207: kvm-block-Check-for-inserted-BlockDriverState-in-blk_io_.patch -# For bz#1492295 - Guest hit call trace with iothrottling(iops) after the status from stop to cont during doing io testing -Patch208: kvm-block-Leave-valid-throttle-timers-when-removing-a-BD.patch -# For bz#1492295 - Guest hit call trace with iothrottling(iops) after the status from stop to cont during doing io testing -Patch209: kvm-qemu-iotests-Test-I-O-limits-with-removable-media.patch -# For bz#1492295 - Guest hit call trace with iothrottling(iops) after the status from stop to cont during doing io testing -Patch210: kvm-throttle-groups-forget-timer-and-schedule-next-TGM-o.patch -# For bz#1451959 - Windows 2016 guest blue screen with page fault in nonpaged area when using hv flags -Patch211: kvm-i386-cpu-hyperv-support-over-64-vcpus-for-windows-gu.patch -# For bz#1396120 - [IBM 7.5 FEAT] POWER9 - Virt: QEMU: POWER8/P8-Compat mode - HPT to guest -Patch212: kvm-target-ppc-correct-htab-shift-for-hash-on-radix.patch -# For bz#1396120 - [IBM 7.5 FEAT] POWER9 - Virt: QEMU: POWER8/P8-Compat mode - HPT to guest -Patch213: kvm-target-ppc-Update-setting-of-cpu-features-to-account.patch -# For bz#1514352 - [RHEL-ALT][s390x] qemu process terminated after rebooting the guest -Patch214: kvm-s390-ccw-Fix-alignment-for-CCW1.patch -# For bz#1514352 - [RHEL-ALT][s390x] qemu process terminated after rebooting the guest -Patch215: kvm-pc-bios-s390-ccw-Fix-problem-with-invalid-virtio-scs.patch -# For bz#1499647 - qemu miscalculates guest RAM size during HPT resizing -Patch216: kvm-spapr-Correct-RAM-size-calculation-for-HPT-resizing.patch -# For bz#1515173 - Cross migration from rhel6.9 to rhel7.5 failed -Patch217: kvm-migration-Reenable-incoming-live-block-migration.patch -# For bz#1506882 - Call trace showed up in dmesg after migrating guest when "stress-ng --numa 2" was running inside guest -Patch218: kvm-ppc-fix-VTB-migration.patch -# For bz#1515393 - bootindex is not taken into account for virtio-scsi devices on ppc64 if the LUN is >= 256 -Patch219: kvm-hw-ppc-spapr-Fix-virtio-scsi-bootindex-handling-for-.patch -# For bz#1495090 - Transfer a file about 10M failed from host to guest through spapr-vty device -Patch220: kvm-spapr-Implement-bug-in-spapr-vty-device-to-be-compat.patch -# For bz#1516145 - Pegas1.0 - [memory hotplug/unplug] qemu crashes with assertion failed from hw/virtio/vhost.c:649 (qemu-kvm) -Patch221: kvm-spapr-reset-DRCs-after-devices.patch -# For bz#1414049 - [RFE] Add support to qemu-img for resizing with preallocation -Patch222: kvm-qcow2-fix-return-error-code-in-qcow2_truncate.patch -# For bz#1414049 - [RFE] Add support to qemu-img for resizing with preallocation -Patch223: kvm-qcow2-Fix-unaligned-preallocated-truncation.patch -# For bz#1414049 - [RFE] Add support to qemu-img for resizing with preallocation -Patch224: kvm-qcow2-Always-execute-preallocate-in-a-coroutine.patch -# For bz#1414049 - [RFE] Add support to qemu-img for resizing with preallocation -Patch225: kvm-iotests-Add-cluster_size-64k-to-125.patch -# For bz#1398633 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm-rhev) -Patch226: kvm-fw_cfg-rename-read-callback.patch -# For bz#1398633 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm-rhev) -Patch227: kvm-fw_cfg-add-write-callback.patch -# For bz#1398633 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm-rhev) -Patch228: kvm-hw-misc-add-vmcoreinfo-device.patch -# For bz#1398633 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm-rhev) -Patch229: kvm-dump-add-guest-ELF-note.patch -# For bz#1398633 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm-rhev) -Patch230: kvm-dump-update-phys_base-header-field-based-on-VMCOREIN.patch -# For bz#1398633 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm-rhev) -Patch231: kvm-kdump-set-vmcoreinfo-location.patch -# For bz#1398633 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm-rhev) -Patch232: kvm-scripts-dump-guest-memory.py-add-vmcoreinfo.patch -# For bz#1398633 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm-rhev) -Patch233: kvm-vmcoreinfo-put-it-in-the-misc-device-category.patch -# For bz#1398633 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm-rhev) -Patch234: kvm-build-sys-restrict-vmcoreinfo-to-fw_cfg-dma-capable-.patch -# For bz#1508750 - CVE-2017-13711 qemu-kvm-rhev: Qemu: Slirp: use-after-free when sending response [rhel-7.5] -Patch235: kvm-slirp-fix-clearing-ifq_so-from-pending-packets.patch -# For bz#1516956 - Pegas1.0 - [qemu]: loadvm fails to restore VM snapshot saved using savevm in destination after postcopy migration (kvm) -Patch236: kvm-migration-ram.c-do-not-set-postcopy_running-in-POSTC.patch -# For bz#1497740 - -cdrom option is broken -Patch237: kvm-scsi-Fix-onboard-HBAs-to-pick-up-drive-if-scsi.patch -# For bz#1506151 - [data-plane] Quitting qemu in destination side encounters "core dumped" when doing live migration -Patch238: kvm-virtio-net-don-t-touch-virtqueue-if-vm-is-stopped.patch -# For bz#1498042 - RFE: option to mark virtual block device as rotational/non-rotational -Patch239: kvm-scsi-disk-support-reporting-of-rotation-rate.patch -# For bz#1498042 - RFE: option to mark virtual block device as rotational/non-rotational -Patch240: kvm-ide-support-reporting-of-rotation-rate.patch -# For bz#1498042 - RFE: option to mark virtual block device as rotational/non-rotational -Patch241: kvm-ide-avoid-referencing-NULL-dev-in-rotational-rate-se.patch -# For bz#1406803 - RFE: native integration of LUKS and qcow2 -Patch242: kvm-qcow2-don-t-permit-changing-encryption-parameters.patch -# For bz#1406803 - RFE: native integration of LUKS and qcow2 -Patch243: kvm-qcow2-fix-image-corruption-after-committing-qcow2-im.patch -# For bz#1494210 - Document image locking in the qemu-img manpage -Patch244: kvm-qemu-doc-Add-UUID-support-in-initiator-name.patch -# For bz#1494210 - Document image locking in the qemu-img manpage -Patch245: kvm-docs-add-qemu-block-drivers-7-man-page.patch -# For bz#1494210 - Document image locking in the qemu-img manpage -Patch246: kvm-docs-Add-image-locking-subsection.patch -# For bz#1494210 - Document image locking in the qemu-img manpage -Patch247: kvm-qemu-options-Mention-locking-option-of-file-driver.patch -# For bz#1505701 - -blockdev fails if a qcow2 image has backing store format and backing store is referenced via node-name -Patch248: kvm-block-don-t-add-driver-to-options-when-referring-to-.patch -# For bz#1487515 - wrong error code is reported if __com.redhat.drive_del can't find the device to delete -Patch249: kvm-blockdev-Report-proper-error-class-in-__com.redhat.d.patch -# For bz#1500334 - LUKS driver has poor performance compared to in-kernel driver -Patch250: kvm-block-use-1-MB-bounce-buffers-for-crypto-instead-of-.patch -# For bz#1464908 - [RFE] Add S3 PR support to qemu (similar to mpathpersist) -Patch251: kvm-io-add-new-qio_channel_-readv-writev-read-write-_all.patch -# For bz#1464908 - [RFE] Add S3 PR support to qemu (similar to mpathpersist) -Patch252: kvm-io-Yield-rather-than-wait-when-already-in-coroutine.patch -# For bz#1464908 - [RFE] Add S3 PR support to qemu (similar to mpathpersist) -Patch253: kvm-scsi-bus-correct-responses-for-INQUIRY-and-REQUEST-S.patch -# For bz#1464908 - [RFE] Add S3 PR support to qemu (similar to mpathpersist) -Patch254: kvm-scsi-Refactor-scsi-sense-interpreting-code.patch -# For bz#1464908 - [RFE] Add S3 PR support to qemu (similar to mpathpersist) -Patch255: kvm-scsi-Improve-scsi_sense_to_errno.patch -# For bz#1464908 - [RFE] Add S3 PR support to qemu (similar to mpathpersist) -Patch256: kvm-scsi-Introduce-scsi_sense_buf_to_errno.patch -# For bz#1464908 - [RFE] Add S3 PR support to qemu (similar to mpathpersist) -Patch257: kvm-scsi-rename-scsi_build_sense-to-scsi_convert_sense.patch -# For bz#1464908 - [RFE] Add S3 PR support to qemu (similar to mpathpersist) -Patch258: kvm-scsi-move-non-emulation-specific-code-to-scsi.patch -# For bz#1464908 - [RFE] Add S3 PR support to qemu (similar to mpathpersist) -Patch259: kvm-scsi-introduce-scsi_build_sense.patch -# For bz#1464908 - [RFE] Add S3 PR support to qemu (similar to mpathpersist) -Patch260: kvm-scsi-introduce-sg_io_sense_from_errno.patch -# For bz#1464908 - [RFE] Add S3 PR support to qemu (similar to mpathpersist) -Patch261: kvm-scsi-move-block-scsi.h-to-include-scsi-constants.h.patch -# For bz#1464908 - [RFE] Add S3 PR support to qemu (similar to mpathpersist) -Patch262: kvm-scsi-file-posix-add-support-for-persistent-reservati.patch -# For bz#1464908 - [RFE] Add S3 PR support to qemu (similar to mpathpersist) -Patch263: kvm-scsi-build-qemu-pr-helper.patch -# For bz#1464908 - [RFE] Add S3 PR support to qemu (similar to mpathpersist) -Patch264: kvm-scsi-add-multipath-support-to-qemu-pr-helper.patch -# For bz#1464908 - [RFE] Add S3 PR support to qemu (similar to mpathpersist) -Patch265: kvm-scsi-add-persistent-reservation-manager-using-qemu-p.patch -# For bz#1464908 - [RFE] Add S3 PR support to qemu (similar to mpathpersist) -Patch266: kvm-qemu-pr-helper-miscellaneous-fixes.patch -# For bz#1495456 - Update downstream qemu's max supported cpus for pseries to the RHEL supported number -Patch267: kvm-Match-POWER-max-cpus-to-x86.patch -# For bz#1492178 - Non-top-level change-backing-file causes assertion failure -Patch268: kvm-qemu-io-Drop-write-permissions-before-read-only-reop.patch -# For bz#1492178 - Non-top-level change-backing-file causes assertion failure -Patch269: kvm-block-Add-reopen_queue-to-bdrv_child_perm.patch -# For bz#1492178 - Non-top-level change-backing-file causes assertion failure -Patch270: kvm-block-Add-reopen-queue-to-bdrv_check_perm.patch -# For bz#1492178 - Non-top-level change-backing-file causes assertion failure -Patch271: kvm-block-Base-permissions-on-rw-state-after-reopen.patch -# For bz#1492178 - Non-top-level change-backing-file causes assertion failure -Patch272: kvm-block-reopen-Queue-children-after-their-parents.patch -# For bz#1492178 - Non-top-level change-backing-file causes assertion failure -Patch273: kvm-block-Fix-permissions-after-bdrv_reopen.patch -# For bz#1492178 - Non-top-level change-backing-file causes assertion failure -Patch274: kvm-qemu-iotests-Test-change-backing-file-command.patch -# For bz#1492178 - Non-top-level change-backing-file causes assertion failure -Patch275: kvm-iotests-Fix-195-if-IMGFMT-is-part-of-TEST_DIR.patch -# For bz#1506531 - [data-plane] Qemu-kvm core dumped when hot-unplugging a block device with data-plane while the drive-mirror job is running -Patch276: kvm-block-add-bdrv_co_drain_end-callback.patch -# For bz#1506531 - [data-plane] Qemu-kvm core dumped when hot-unplugging a block device with data-plane while the drive-mirror job is running -Patch277: kvm-block-rename-bdrv_co_drain-to-bdrv_co_drain_begin.patch -# For bz#1506531 - [data-plane] Qemu-kvm core dumped when hot-unplugging a block device with data-plane while the drive-mirror job is running -Patch278: kvm-blockjob-do-not-allow-coroutine-double-entry-or-entr.patch -# For bz#1506531 - [data-plane] Qemu-kvm core dumped when hot-unplugging a block device with data-plane while the drive-mirror job is running -Patch279: kvm-coroutine-abort-if-we-try-to-schedule-or-enter-a-pen.patch -# For bz#1506531 - [data-plane] Qemu-kvm core dumped when hot-unplugging a block device with data-plane while the drive-mirror job is running -Patch280: kvm-qemu-iotests-add-option-in-common.qemu-for-mismatch-.patch -# For bz#1506531 - [data-plane] Qemu-kvm core dumped when hot-unplugging a block device with data-plane while the drive-mirror job is running -Patch281: kvm-qemu-iotest-add-test-for-blockjob-coroutine-race-con.patch -# For bz#1506531 - [data-plane] Qemu-kvm core dumped when hot-unplugging a block device with data-plane while the drive-mirror job is running -Patch282: kvm-blockjob-Remove-the-job-from-the-list-earlier-in-blo.patch -# For bz#1506531 - [data-plane] Qemu-kvm core dumped when hot-unplugging a block device with data-plane while the drive-mirror job is running -Patch283: kvm-block-Expect-graph-changes-in-bdrv_parent_drained_be.patch -# For bz#1506531 - [data-plane] Qemu-kvm core dumped when hot-unplugging a block device with data-plane while the drive-mirror job is running -Patch284: kvm-blockjob-remove-clock-argument-from-block_job_sleep_.patch -# For bz#1506531 - [data-plane] Qemu-kvm core dumped when hot-unplugging a block device with data-plane while the drive-mirror job is running -Patch285: kvm-blockjob-introduce-block_job_do_yield.patch -# For bz#1506531 - [data-plane] Qemu-kvm core dumped when hot-unplugging a block device with data-plane while the drive-mirror job is running -Patch286: kvm-blockjob-reimplement-block_job_sleep_ns-to-allow-can.patch -# For bz#1506531 - [data-plane] Qemu-kvm core dumped when hot-unplugging a block device with data-plane while the drive-mirror job is running -Patch287: kvm-blockjob-Make-block_job_pause_all-keep-a-reference-t.patch -# For bz#1517051 - POWER9 - Virt: QEMU: Migration of HPT guest on Radix host fails -Patch288: kvm-target-ppc-Move-setting-of-patb_entry-on-hash-table-.patch -# For bz#1517051 - POWER9 - Virt: QEMU: Migration of HPT guest on Radix host fails -Patch289: kvm-target-ppc-Fix-setting-of-cpu-compat_pvr-on-incoming.patch -# For bz#1513294 - Guest got stuck when attached memory beforehand.[-device dimm and object memory-backend-ram] -Patch290: kvm-BZ1513294-spapr-Include-pre-plugged-DIMMS-in-ram-siz.patch -# For bz#1491909 - IP network can not recover after several vhost-user reconnect -Patch291: kvm-virtio-Add-queue-interface-to-restore-avail-index-fr.patch -# For bz#1491909 - IP network can not recover after several vhost-user reconnect -Patch292: kvm-vhost-restore-avail-index-from-vring-used-index-on-d.patch -# For bz#1398633 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm-rhev) -Patch293: kvm-dump-guest-memory.py-fix-No-symbol-vmcoreinfo_find.patch -# For bz#1396119 - [IBM 7.5 Feature] POWER9 - Virt: QEMU: POWER8/P8-Compat mode for POWER8 Guests on POWER9 platform -Patch294: kvm-ppc-fix-setting-of-compat-mode.patch -# For bz#1506856 - [abrt] qemu-kvm-rhev: object_get_class(): qemu-kvm killed by SIGSEGV -Patch295: kvm-pc-fix-crash-on-attempted-cpu-unplug.patch -# For bz#1506218 - seg at exit - due to missing fd? -Patch296: kvm-sockets-avoid-crash-when-cleaning-up-sockets-for-an-.patch -# For bz#1523235 - Pegas1.0 - qemu cpu information is not up-to-date (qemu-kvm) -Patch297: kvm-target-ppc-Add-POWER9-DD2.0-model-information.patch -# For bz#1505654 - Missing libvxhs share-able object file when try to query vxhs protocol -Patch298: kvm-block-vxhs-improve-error-message-for-missing-bad-vxh.patch -# For bz#1451269 - Clarify the relativity of backing file and created image in "qemu-img create" -Patch299: kvm-qemu-img-Clarify-about-relative-backing-file-options.patch -# For bz#1518529 - CVE-2017-15119 qemu-kvm-rhev: qemu: DoS via large option request [rhel-7.5] -# For bz#1518551 - CVE-2017-15119 qemu-kvm-ma: qemu: DoS via large option request [rhel-7.5] -Patch300: kvm-nbd-server-CVE-2017-15119-Reject-options-larger-than.patch -# For bz#1516545 - CVE-2017-15118 qemu-kvm-rhev: qemu NBD server vulnerable to stack smash from client requesting long export name [rhel-7.5] -# For bz#1518548 - CVE-2017-15118 qemu-kvm-ma: Qemu: stack buffer overflow in NBD server triggered via long export name [rhel-7.5] -Patch301: kvm-nbd-server-CVE-2017-15118-Stack-smash-on-large-expor.patch -# For bz#1520294 - Hot-unplug the second pf cause qemu promote " Failed to remove group $iommu_group_num from KVM VFIO device:" -Patch302: kvm-vfio-Fix-vfio-kvm-group-registration.patch -# For bz#1525866 - P9 to P8 guest migration fails when kernel is not started -Patch303: kvm-spapr-don-t-initialize-PATB-entry-if-max-cpu-compat-.patch -# For bz#1520824 - Migration with dataplane, qemu processor hang, vm hang and migration can't finish -Patch304: kvm-block-avoid-recursive-AioContext-acquire-in-bdrv_ina.patch -# For bz#1518649 - Client compatibility flaws in VNC websockets server -Patch305: kvm-io-send-proper-HTTP-response-for-websocket-errors.patch -# For bz#1518649 - Client compatibility flaws in VNC websockets server -Patch306: kvm-io-include-full-error-message-in-websocket-handshake.patch -# For bz#1518649 - Client compatibility flaws in VNC websockets server -Patch307: kvm-io-use-case-insensitive-check-for-Connection-Upgrade.patch -# For bz#1518649 - Client compatibility flaws in VNC websockets server -Patch308: kvm-ui-Always-remove-an-old-VNC-channel-watch-before-add.patch -# For bz#1518649 - Client compatibility flaws in VNC websockets server -Patch309: kvm-io-Small-updates-in-preparation-for-websocket-change.patch -# For bz#1518649 - Client compatibility flaws in VNC websockets server -Patch310: kvm-io-Add-support-for-fragmented-websocket-binary-frame.patch -# For bz#1518649 - Client compatibility flaws in VNC websockets server -Patch311: kvm-io-Allow-empty-websocket-payload.patch -# For bz#1518649 - Client compatibility flaws in VNC websockets server -Patch312: kvm-io-Ignore-websocket-PING-and-PONG-frames.patch -# For bz#1518649 - Client compatibility flaws in VNC websockets server -Patch313: kvm-io-Reply-to-ping-frames.patch -# For bz#1518649 - Client compatibility flaws in VNC websockets server -Patch314: kvm-io-Attempt-to-send-websocket-close-messages-to-clien.patch -# For bz#1518649 - Client compatibility flaws in VNC websockets server -Patch315: kvm-io-add-trace-events-for-websockets-frame-handling.patch -# For bz#1518650 - CVE-2017-15268 qemu-kvm-rhev: Qemu: I/O: potential memory exhaustion via websock connection to VNC [rhel-7.5] -Patch316: kvm-io-monitor-encoutput-buffer-size-from-websocket-GSou.patch -# For bz#1518649 - Client compatibility flaws in VNC websockets server -Patch317: kvm-io-simplify-websocket-ping-reply-handling.patch -# For bz#1518649 - Client compatibility flaws in VNC websockets server -Patch318: kvm-io-get-rid-of-qio_channel_websock_encode-helper-meth.patch -# For bz#1518649 - Client compatibility flaws in VNC websockets server -Patch319: kvm-io-pass-a-struct-iovec-into-qio_channel_websock_enco.patch -# For bz#1518649 - Client compatibility flaws in VNC websockets server -Patch320: kvm-io-get-rid-of-bounce-buffering-in-websock-write-path.patch -# For bz#1518649 - Client compatibility flaws in VNC websockets server -Patch321: kvm-io-cope-with-websock-Connection-header-having-multip.patch -# For bz#1518649 - Client compatibility flaws in VNC websockets server -Patch322: kvm-io-add-trace-points-for-websocket-HTTP-protocol-head.patch -# For bz#1518649 - Client compatibility flaws in VNC websockets server -Patch323: kvm-io-fix-mem-leak-in-websock-error-path.patch -# For bz#1518649 - Client compatibility flaws in VNC websockets server -Patch324: kvm-io-Add-missing-GCC_FMT_ATTR-fix-Werror-suggest-attri.patch -# For bz#1519721 - Both qemu and guest hang when performing live snapshot transaction with data-plane -Patch325: kvm-qemu.py-make-VM-a-context-manager.patch -# For bz#1519721 - Both qemu and guest hang when performing live snapshot transaction with data-plane -Patch326: kvm-iotests.py-add-FilePath-context-manager.patch -# For bz#1519721 - Both qemu and guest hang when performing live snapshot transaction with data-plane -Patch327: kvm-qemu-iothread-IOThread-supports-the-GMainContext-eve.patch -# For bz#1519721 - Both qemu and guest hang when performing live snapshot transaction with data-plane -Patch328: kvm-qom-provide-root-container-for-internal-objs.patch -# For bz#1519721 - Both qemu and guest hang when performing live snapshot transaction with data-plane -Patch329: kvm-iothread-provide-helpers-for-internal-use.patch -# For bz#1519721 - Both qemu and guest hang when performing live snapshot transaction with data-plane -Patch330: kvm-iothread-export-iothread_stop.patch -# For bz#1519721 - Both qemu and guest hang when performing live snapshot transaction with data-plane -Patch331: kvm-iothread-delay-the-context-release-to-finalize.patch -# For bz#1519721 - Both qemu and guest hang when performing live snapshot transaction with data-plane -Patch332: kvm-aio-fix-assert-when-remove-poll-during-destroy.patch -# For bz#1519721 - Both qemu and guest hang when performing live snapshot transaction with data-plane -Patch333: kvm-blockdev-hold-AioContext-for-bdrv_unref-in-external_.patch -# For bz#1519721 - Both qemu and guest hang when performing live snapshot transaction with data-plane -Patch334: kvm-block-don-t-keep-AioContext-acquired-after-external_.patch -# For bz#1519721 - Both qemu and guest hang when performing live snapshot transaction with data-plane -Patch335: kvm-block-don-t-keep-AioContext-acquired-after-drive_bac.patch -# For bz#1519721 - Both qemu and guest hang when performing live snapshot transaction with data-plane -Patch336: kvm-block-don-t-keep-AioContext-acquired-after-blockdev_.patch -# For bz#1519721 - Both qemu and guest hang when performing live snapshot transaction with data-plane -Patch337: kvm-block-don-t-keep-AioContext-acquired-after-internal_.patch -# For bz#1519721 - Both qemu and guest hang when performing live snapshot transaction with data-plane -Patch338: kvm-iothread-add-iothread_by_id-API.patch -# For bz#1519721 - Both qemu and guest hang when performing live snapshot transaction with data-plane -Patch339: kvm-blockdev-add-x-blockdev-set-iothread-testing-command.patch -# For bz#1519721 - Both qemu and guest hang when performing live snapshot transaction with data-plane -Patch340: kvm-qemu-iotests-add-202-external-snapshots-IOThread-tes.patch -# For bz#1519721 - Both qemu and guest hang when performing live snapshot transaction with data-plane -Patch341: kvm-blockdev-add-x-blockdev-set-iothread-force-boolean.patch -# For bz#1519721 - Both qemu and guest hang when performing live snapshot transaction with data-plane -Patch342: kvm-iotests-add-VM.add_object.patch -# For bz#1519721 - Both qemu and guest hang when performing live snapshot transaction with data-plane -Patch343: kvm-iothread-fix-iothread_stop-race-condition.patch -# For bz#1519721 - Both qemu and guest hang when performing live snapshot transaction with data-plane -Patch344: kvm-qemu-iotests-add-203-savevm-with-IOThreads-test.patch -# For bz#CVE-2017-5715 -Patch345: kvm-target-i386-add-support-for-SPEC_CTRL-MSR.patch -# For bz#CVE-2017-5715 -Patch346: kvm-target-i386-cpu-add-new-CPUID-bits-for-indirect-bran.patch -# For bz#CVE-2017-5715 -Patch347: kvm-target-i386-cpu-add-new-CPU-models-for-indirect-bran.patch -# For bz#1513323 - vITS reset -Patch348: kvm-gicv3-Convert-to-DEFINE_PROP_LINK.patch -# For bz#1513323 - vITS reset -Patch349: kvm-hw-intc-arm_gicv3_its-Fix-the-VM-termination-in-vm_c.patch -# For bz#1513323 - vITS reset -Patch350: kvm-hw-intc-arm_gicv3_its-Don-t-abort-on-table-save-fail.patch -# For bz#1513323 - vITS reset -Patch351: kvm-hw-intc-arm_gicv3_its-Don-t-call-post_load-on-reset.patch -# For bz#1513323 - vITS reset -Patch352: kvm-hw-intc-arm_gicv3_its-Implement-a-minimalist-reset.patch -# For bz#1513323 - vITS reset -Patch353: kvm-linux-headers-Partial-header-update-against-v4.15-rc.patch -# For bz#1513323 - vITS reset -Patch354: kvm-hw-intc-arm_gicv3_its-Implement-full-reset.patch -# For bz#1525868 - Guest hit core dump with both IO throttling and data plane -Patch355: kvm-block-throttle-groups.c-allocate-RestartData-on-the-.patch -# For bz#1529676 - kvm_stat: option '--guest' doesn't work -Patch356: kvm-tools-kvm_stat-fix-command-line-option-g.patch -# For bz#1527449 - qemu-kvm-ma: vCPU count should be limited to 240 on all arches -Patch357: kvm-redhat-globally-limit-the-maximum-number-of-CPUs.patch -# For bz#1527449 - qemu-kvm-ma: vCPU count should be limited to 240 on all arches -Patch358: kvm-redhat-remove-manual-max_cpus-limitations-for-ppc.patch -# For bz#1398633 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm-rhev) -Patch359: kvm-dump-guest-memory.py-fix-You-can-t-do-that-without-a.patch -# For bz#1528173 - Hot-unplug memory during booting early stage induced qemu-kvm coredump -Patch360: kvm-hw-ppc-spapr.c-abort-unplug_request-if-previous-unpl.patch -# For bz#1528234 - Pegas1.1 Alpha: Hotplugged vcpu does not guarantee CPU P8compat mode on POWER9 host (qemu-kvm) -Patch361: kvm-spapr-Correct-compatibility-mode-setting-for-hotplug.patch -# For bz#1510809 - qemu-kvm core dumped when booting up guest using both virtio-vga and VGA -Patch362: kvm-ui-fix-dcl-unregister.patch -# For bz#1526212 - qemu-img should not need a write lock for creating the overlay image -Patch363: kvm-block-Open-backing-image-in-force-share-mode-for-siz.patch -# For bz#1462145 - Qemu crashes when all fw_cfg slots are used -Patch364: kvm-fw_cfg-fix-memory-corruption-when-all-fw_cfg-slots-a.patch -# For bz#1515604 - qemu-img info: failed to get "consistent read" lock on a mirroring image -Patch365: kvm-block-Don-t-use-BLK_PERM_CONSISTENT_READ-for-format-.patch -# For bz#1515604 - qemu-img info: failed to get "consistent read" lock on a mirroring image -Patch366: kvm-block-Don-t-request-I-O-permission-with-BDRV_O_NO_IO.patch -# For bz#1515604 - qemu-img info: failed to get "consistent read" lock on a mirroring image -Patch367: kvm-block-Formats-don-t-need-CONSISTENT_READ-with-NO_IO.patch -# For bz#1459945 - migration fails with hungup serial console reader on -M pc-i440fx-rhel7.0.0 and pc-i440fx-rhel7.1.0 -Patch368: kvm-serial-always-transmit-send-receive-buffers-on-migra.patch -# For bz#1507693 - Unable to hot plug device to VM reporting libvirt errors. -Patch369: kvm-hw-acpi-Move-acpi_set_pci_info-to-pcihp.patch -# For bz#1518482 - "share-rw" property is unavailable on scsi passthrough devices -Patch370: kvm-scsi-block-Add-share-rw-option.patch -# For bz#1518482 - "share-rw" property is unavailable on scsi passthrough devices -Patch371: kvm-scsi-generic-Add-share-rw-option.patch -# For bz#1529461 - On amd hosts, after migration from rhel6.9.z to rhel7.5, CPU utilization of qemu-kvm is always more than 100% on destination rhel7.5 host -Patch372: kvm-target-i386-sanitize-x86-MSR_PAT-loaded-from-another.patch -# For bz#1526423 - QEMU hang with data plane enabled after some sg_write_same operations in guest -Patch373: kvm-scsi-disk-release-AioContext-in-unaligned-WRITE-SAME.patch -# For bz#1520858 - qemu-kvm core dumped when booting guest with more pcie-root-ports than available slots and io-reserve=0 -Patch374: kvm-hw-pci-bridge-fix-QEMU-crash-because-of-pcie-root-po.patch -# For bz#1523414 - [POWER guests] Verify compatible CPU & hypervisor capabilities across migration -Patch375: kvm-spapr-Capabilities-infrastructure.patch -# For bz#1523414 - [POWER guests] Verify compatible CPU & hypervisor capabilities across migration -Patch376: kvm-spapr-Treat-Hardware-Transactional-Memory-HTM-as-an-.patch -# For bz#1523414 - [POWER guests] Verify compatible CPU & hypervisor capabilities across migration -Patch377: kvm-spapr-Validate-capabilities-on-migration.patch -# For bz#1523414 - [POWER guests] Verify compatible CPU & hypervisor capabilities across migration -Patch378: kvm-spapr-Handle-VMX-VSX-presence-as-an-spapr-capability.patch -# For bz#1523414 - [POWER guests] Verify compatible CPU & hypervisor capabilities across migration -Patch379: kvm-spapr-Handle-Decimal-Floating-Point-DFP-as-an-option.patch -# For bz#1523414 - [POWER guests] Verify compatible CPU & hypervisor capabilities across migration -Patch380: kvm-hw-ppc-spapr_caps-Rework-spapr_caps-to-use-uint8-int.patch -# For bz#1523414 - [POWER guests] Verify compatible CPU & hypervisor capabilities across migration -Patch381: kvm-spapr-Remove-unnecessary-options-field-from-sPAPRCap.patch -# For bz#1529243 - Migration from P9 to P8, migration failed and qemu quit on dst end with "error while loading state for instance 0x0 of device 'ics'" -Patch382: kvm-ppc-Change-Power9-compat-table-to-support-at-most-8-.patch -# For bz#1529243 - Migration from P9 to P8, migration failed and qemu quit on dst end with "error while loading state for instance 0x0 of device 'ics'" -Patch383: kvm-target-ppc-Clarify-compat-mode-max_threads-value.patch -# For bz#1529243 - Migration from P9 to P8, migration failed and qemu quit on dst end with "error while loading state for instance 0x0 of device 'ics'" -Patch384: kvm-spapr-Allow-some-cases-where-we-can-t-set-VSMT-mode-.patch -# For bz#1529243 - Migration from P9 to P8, migration failed and qemu quit on dst end with "error while loading state for instance 0x0 of device 'ics'" -Patch385: kvm-spapr-Adjust-default-VSMT-value-for-better-migration.patch -# For bz#1535992 - Set force shared option "-U" as default option for "qemu-img info" -Patch386: kvm-qemu-img-info-Force-U-downstream.patch -# For bz#1398633 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm-rhev) -Patch387: kvm-dump-guest-memory.py-fix-python-2-support.patch -# For bz#1535752 - Device tree incorrectly advertises compatibility modes for secondary CPUs -Patch388: kvm-spapr-fix-device-tree-properties-when-using-compatib.patch -# For bz#1513870 - For VNC connection, characters '|' and '<' are both recognized as '>' in linux guests, while '<' and '>' are both recognized as '|' in windows guest -Patch389: kvm-Drop-105th-key-from-en-us-keymap.patch -# For bz#1535606 - Spectre mitigation patches for qemu-kvm-ma on z Systems -Patch390: kvm-linux-headers-update.patch -# For bz#1535606 - Spectre mitigation patches for qemu-kvm-ma on z Systems -Patch391: kvm-s390x-kvm-Handle-bpb-feature.patch -# For bz#1535606 - Spectre mitigation patches for qemu-kvm-ma on z Systems -Patch392: kvm-s390x-kvm-provide-stfle.81.patch -# For bz#1529053 - Miss the handling of EINTR in the fcntl calls made by QEMU -Patch393: kvm-osdep-Retry-SETLK-upon-EINTR.patch -# For bz#1534682 - CVE-2018-5683 qemu-kvm-rhev: Qemu: Out-of-bounds read in vga_draw_text routine [rhel-7.5] -Patch394: kvm-vga-check-the-validation-of-memory-addr-when-draw-te.patch -# For bz#1525324 - 2 VMs both with 'share-rw=on' appending on '-device usb-storage' for the same source image can not be started at the same time -Patch395: kvm-usb-storage-Fix-share-rw-option-parsing.patch -# For bz#1535952 - qemu-kvm-ma differentiation - memory hotplug -Patch396: kvm-spapr-disable-memory-hotplug.patch -# For bz#1505696 - Qemu crashed when open the second display of virtio video -Patch397: kvm-console-fix-dpy_gfx_replace_surface-assert.patch -# For bz#1527404 - CVE-2017-15124 qemu-kvm-rhev: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] -Patch398: kvm-ui-add-tracing-of-VNC-operations-related-to-QIOChann.patch -# For bz#1527404 - CVE-2017-15124 qemu-kvm-rhev: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] -Patch399: kvm-ui-add-tracing-of-VNC-authentication-process.patch -# For bz#1527404 - CVE-2017-15124 qemu-kvm-rhev: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] -Patch400: kvm-ui-remove-sync-parameter-from-vnc_update_client.patch -# For bz#1527404 - CVE-2017-15124 qemu-kvm-rhev: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] -Patch401: kvm-ui-remove-unreachable-code-in-vnc_update_client.patch -# For bz#1527404 - CVE-2017-15124 qemu-kvm-rhev: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] -Patch402: kvm-ui-remove-redundant-indentation-in-vnc_client_update.patch -# For bz#1527404 - CVE-2017-15124 qemu-kvm-rhev: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] -Patch403: kvm-ui-avoid-pointless-VNC-updates-if-framebuffer-isn-t-.patch -# For bz#1527404 - CVE-2017-15124 qemu-kvm-rhev: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] -Patch404: kvm-ui-track-how-much-decoded-data-we-consumed-when-doin.patch -# For bz#1527404 - CVE-2017-15124 qemu-kvm-rhev: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] -Patch405: kvm-ui-introduce-enum-to-track-VNC-client-framebuffer-up.patch -# For bz#1527404 - CVE-2017-15124 qemu-kvm-rhev: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] -Patch406: kvm-ui-correctly-reset-framebuffer-update-state-after-pr.patch -# For bz#1527404 - CVE-2017-15124 qemu-kvm-rhev: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] -Patch407: kvm-ui-refactor-code-for-determining-if-an-update-should.patch -# For bz#1527404 - CVE-2017-15124 qemu-kvm-rhev: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] -Patch408: kvm-ui-fix-VNC-client-throttling-when-audio-capture-is-a.patch -# For bz#1527404 - CVE-2017-15124 qemu-kvm-rhev: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] -Patch409: kvm-ui-fix-VNC-client-throttling-when-forced-update-is-r.patch -# For bz#1527404 - CVE-2017-15124 qemu-kvm-rhev: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] -Patch410: kvm-ui-place-a-hard-cap-on-VNC-server-output-buffer-size.patch -# For bz#1527404 - CVE-2017-15124 qemu-kvm-rhev: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] -Patch411: kvm-ui-add-trace-events-related-to-VNC-client-throttling.patch -# For bz#1527404 - CVE-2017-15124 qemu-kvm-rhev: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] -Patch412: kvm-ui-mix-misleading-comments-return-types-of-VNC-I-O-h.patch -# For bz#1527404 - CVE-2017-15124 qemu-kvm-rhev: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] -Patch413: kvm-ui-avoid-sign-extension-using-client-width-height.patch -# For bz#1527404 - CVE-2017-15124 qemu-kvm-rhev: Qemu: memory exhaustion through framebuffer update request message in VNC server [rhel-7.5] -Patch414: kvm-ui-correctly-advance-output-buffer-when-writing-SASL.patch -# For bz#1398633 - [RFE] Kernel address space layout randomization [KASLR] support (qemu-kvm-rhev) -Patch415: kvm-dump-guest-memory.py-skip-vmcoreinfo-section-if-not-.patch -# For bz#1540182 - QEMU: disallow virtio-gpu to boot with vIOMMU -Patch416: kvm-virtio-gpu-disallow-vIOMMU.patch -# For bz#1538494 - Guest crashed on the source host when cancel migration by virDomainMigrateBegin3Params sometimes -Patch417: kvm-migration-Recover-block-devices-if-failure-in-device.patch -# For bz#1540003 - Postcopy migration failed with "Unreasonably large packaged state" -Patch418: kvm-migration-savevm.c-set-MAX_VM_CMD_PACKAGED_SIZE-to-1.patch -# For bz#1538953 - IOTLB entry size mismatch before/after migration during DPDK PVP testing -Patch419: kvm-pci-bus-let-it-has-higher-migration-priority.patch -# For bz#1542421 - Pegas1.1 Snapshot1 [4.14.0-35.el7a.ppc64le] [qemu-kvm-ma-2.10.0-18.el7.ppc64le] qemu-kvm behaves incorrectly for guest boot with invalid threads -Patch420: kvm-spapr-set-vsmt-to-MAX-8-smp_threads.patch -# For bz#1532050 - [CVE-2017-5754] Variant3: POWER {qemu-kvm-rhev} (rhel 7.5) -Patch421: kvm-target-ppc-spapr_caps-Add-macro-to-generate-spapr_ca.patch -# For bz#1532050 - [CVE-2017-5754] Variant3: POWER {qemu-kvm-rhev} (rhel 7.5) -Patch422: kvm-target-ppc-kvm-Add-cap_ppc_safe_-cache-bounds_check-.patch -# For bz#1532050 - [CVE-2017-5754] Variant3: POWER {qemu-kvm-rhev} (rhel 7.5) -Patch423: kvm-target-ppc-spapr_caps-Add-support-for-tristate-spapr.patch -# For bz#1532050 - [CVE-2017-5754] Variant3: POWER {qemu-kvm-rhev} (rhel 7.5) -Patch424: kvm-target-ppc-spapr_caps-Add-new-tristate-cap-safe_cach.patch -# For bz#1532050 - [CVE-2017-5754] Variant3: POWER {qemu-kvm-rhev} (rhel 7.5) -Patch425: kvm-target-ppc-spapr_caps-Add-new-tristate-cap-safe_boun.patch -# For bz#1532050 - [CVE-2017-5754] Variant3: POWER {qemu-kvm-rhev} (rhel 7.5) -Patch426: kvm-target-ppc-spapr_caps-Add-new-tristate-cap-safe_indi.patch -# For bz#1532050 - [CVE-2017-5754] Variant3: POWER {qemu-kvm-rhev} (rhel 7.5) -Patch427: kvm-target-ppc-introduce-the-PPC_BIT-macro.patch -# For bz#1532050 - [CVE-2017-5754] Variant3: POWER {qemu-kvm-rhev} (rhel 7.5) -Patch428: kvm-target-ppc-spapr-Add-H-Call-H_GET_CPU_CHARACTERISTIC.patch -# For bz#1532050 - [CVE-2017-5754] Variant3: POWER {qemu-kvm-rhev} (rhel 7.5) -Patch429: kvm-spapr-add-missing-break-in-h_get_cpu_characteristics.patch -# For bz#1508330 - Interrupt latency issues with vGPU on KVM hypervisor. -Patch430: kvm-vfio-pci-Add-option-to-disable-GeForce-quirks.patch -# For bz#1508330 - Interrupt latency issues with vGPU on KVM hypervisor. -Patch431: kvm-Disable-GeForce-quirks-in-vfio-pci-for-RHEL-machines.patch -# For bz#1554930 - incorrect locking (possible use-after-free) with bug 1481593 fix [rhel-7.5.z] -Patch432: kvm-memory-inline-some-performance-sensitive-accessors.patch -# For bz#1554930 - incorrect locking (possible use-after-free) with bug 1481593 fix [rhel-7.5.z] -Patch433: kvm-address_space_write-address_space_to_flatview-needs-.patch -# For bz#1554930 - incorrect locking (possible use-after-free) with bug 1481593 fix [rhel-7.5.z] -Patch434: kvm-address_space_read-address_space_to_flatview-needs-R.patch -# For bz#1554930 - incorrect locking (possible use-after-free) with bug 1481593 fix [rhel-7.5.z] -Patch435: kvm-address_space_access_valid-address_space_to_flatview.patch -# For bz#1554930 - incorrect locking (possible use-after-free) with bug 1481593 fix [rhel-7.5.z] -Patch436: kvm-address_space_map-address_space_to_flatview-needs-RC.patch -# For bz#1554930 - incorrect locking (possible use-after-free) with bug 1481593 fix [rhel-7.5.z] -Patch437: kvm-address_space_rw-address_space_to_flatview-needs-RCU.patch -# For bz#1554957 - [CVE-2017-5754] Variant3: POWER {qemu-kvm-ma} Add machine type variants [rhel-7.5.z] -Patch438: kvm-ppc-spapr-caps-Change-migration-macro-to-take-full-s.patch -# For bz#1554957 - [CVE-2017-5754] Variant3: POWER {qemu-kvm-ma} Add machine type variants [rhel-7.5.z] -Patch439: kvm-ppc-spapr-caps-Disallow-setting-workaround-for-spapr.patch -# For bz#1554957 - [CVE-2017-5754] Variant3: POWER {qemu-kvm-ma} Add machine type variants [rhel-7.5.z] -Patch440: kvm-target-ppc-Check-mask-when-setting-cap_ppc_safe_indi.patch -# For bz#1554957 - [CVE-2017-5754] Variant3: POWER {qemu-kvm-ma} Add machine type variants [rhel-7.5.z] -Patch441: kvm-ppc-spapr-caps-Add-support-for-custom-spapr_capabili.patch -# For bz#1554957 - [CVE-2017-5754] Variant3: POWER {qemu-kvm-ma} Add machine type variants [rhel-7.5.z] -Patch442: kvm-ppc-spapr-caps-Convert-cap-cfpc-to-custom-spapr-cap.patch -# For bz#1554957 - [CVE-2017-5754] Variant3: POWER {qemu-kvm-ma} Add machine type variants [rhel-7.5.z] -Patch443: kvm-ppc-spapr-caps-Convert-cap-sbbc-to-custom-spapr-cap.patch -# For bz#1554957 - [CVE-2017-5754] Variant3: POWER {qemu-kvm-ma} Add machine type variants [rhel-7.5.z] -Patch444: kvm-ppc-spapr-caps-Convert-cap-ibs-to-custom-spapr-cap.patch -# For bz#1554957 - [CVE-2017-5754] Variant3: POWER {qemu-kvm-ma} Add machine type variants [rhel-7.5.z] -Patch445: kvm-ppc-spapr-caps-Define-the-pseries-2.12-sxxm-machine-.patch -# For bz#1554957 - [CVE-2017-5754] Variant3: POWER {qemu-kvm-ma} Add machine type variants [rhel-7.5.z] -Patch446: kvm-redhat-Define-the-pseries-rhel7.5-sxxm-machine-type.patch -# For bz#1554957 - [CVE-2017-5754] Variant3: POWER {qemu-kvm-ma} Add machine type variants [rhel-7.5.z] -Patch447: kvm-redhat-Define-the-pseries-rhel7.4-sxxm-machine-type.patch -# For bz#1554957 - [CVE-2017-5754] Variant3: POWER {qemu-kvm-ma} Add machine type variants [rhel-7.5.z] -Patch448: kvm-redhat-Define-the-pseries-rhel7.3-sxxm-machine-type.patch -# For bz#1557206 - [Regression] Cannot delete VM's snapshot [rhel-7.5.z] -Patch449: kvm-block-Fix-flags-in-reopen-queue.patch -# For bz#1557206 - [Regression] Cannot delete VM's snapshot [rhel-7.5.z] -Patch450: kvm-iotests-Add-regression-test-for-commit-base-locking.patch -# For bz#1566878 - CVE-2018-7858 qemu-kvm-ma: Qemu: cirrus: OOB access when updating vga display [rhel-7] [rhel-7.5.z] -Patch451: kvm-vga-add-ram_addr_t-cast.patch -# For bz#1566878 - CVE-2018-7858 qemu-kvm-ma: Qemu: cirrus: OOB access when updating vga display [rhel-7] [rhel-7.5.z] -Patch452: kvm-vga-fix-region-calculation.patch -# For bz#1593193 - Pegas1.1 - SCSI pass-thru of aacraid RAID1 is inaccessible (qemu-kvm-ma) [rhel-7.5.z] -Patch453: kvm-scsi-disk-allow-customizing-the-SCSI-version.patch -# For bz#1593193 - Pegas1.1 - SCSI pass-thru of aacraid RAID1 is inaccessible (qemu-kvm-ma) [rhel-7.5.z] -Patch454: kvm-hw-scsi-support-SCSI-2-passthrough-without-PI.patch -# For bz#1596553 - RHEL-Alt-7.5 - qemu has error during migration of larger guests [rhel-7.5.z] -Patch455: kvm-s390x-fix-storage-attributes-migration-for-non-small.patch -# For bz#1586247 - CVE-2018-11806 qemu-kvm-ma: QEMU: slirp: heap buffer overflow while reassembling fragmented datagrams [rhel-7.5.z] -Patch456: kvm-slirp-correct-size-computation-while-concatenating-m.patch -# For bz#1586247 - CVE-2018-11806 qemu-kvm-ma: QEMU: slirp: heap buffer overflow while reassembling fragmented datagrams [rhel-7.5.z] -Patch457: kvm-slirp-reformat-m_inc-routine.patch -# For bz#1586247 - CVE-2018-11806 qemu-kvm-ma: QEMU: slirp: heap buffer overflow while reassembling fragmented datagrams [rhel-7.5.z] -Patch458: kvm-slirp-Correct-size-check-in-m_inc.patch +Source34: kvm-setup-ppc64.sysconfig + + + +Patch0001: 0001-Revert-qemu-pr-helper-use-new-libmultipath-API.patch +Patch0003: 0003-Initial-redhat-build.patch +Patch0004: 0004-Enable-disable-devices-for-RHEL-7.patch +Patch0005: 0005-Add-RHEL-7-machine-types.patch +Patch0006: 0006-Revert-kvm_stat-Remove.patch +Patch0007: 0007-Use-kvm-by-default.patch +Patch0008: 0008-add-qxl_screendump-monitor-command.patch +Patch0009: 0009-seabios-paravirt-allow-more-than-1TB-in-x86-guest.patch +Patch0010: 0010-vfio-cap-number-of-devices-that-can-be-assigned.patch +Patch0011: 0011-QMP-Forward-port-__com.redhat_drive_del-from-RHEL-6.patch +Patch0012: 0012-QMP-Forward-port-__com.redhat_drive_add-from-RHEL-6.patch +Patch0013: 0013-HMP-Forward-port-__com.redhat_drive_add-from-RHEL-6.patch +Patch0014: 0014-Add-support-statement-to-help-output.patch +Patch0015: 0015-vl-Round-memory-sizes-below-2MiB-up-to-2MiB.patch +Patch0016: 0016-use-recommended-max-vcpu-count.patch +Patch0017: 0017-Add-support-for-simpletrace.patch +Patch0018: 0018-Use-qemu-kvm-in-documentation-instead-of-qemu-system.patch +Patch0019: 0019-qmp-add-__com.redhat_reason-to-the-BLOCK_IO_ERROR-ev.patch +Patch0020: 0020-Migration-compat-for-pckbd.patch +Patch0021: 0021-Migration-compat-for-fdc.patch +Patch0022: 0022-spapr-Reduce-advertised-max-LUNs-for-spapr_vscsi.patch +Patch0023: 0023-RHEL-only-hw-char-pl011-fix-SBSA-reset.patch +Patch0024: 0024-blockdev-ignore-cache-options-for-empty-CDROM-drives.patch +Patch0025: 0025-usb-xhci-Fix-PCI-capability-order.patch +Patch0026: 0026-blockdev-ignore-aio-native-for-empty-drives.patch +Patch0027: 0027-virtio-scsi-Reject-scsi-cd-if-data-plane-enabled-RHE.patch +Patch0028: 0028-osdep-Force-define-F_OFD_GETLK-RHEL-only.patch +Patch0029: 0029-spapr-disable-cpu-hot-remove.patch +Patch0030: 0030-migration-Reenable-incoming-live-block-migration.patch +Patch0031: 0031-block-vxhs-improve-error-message-for-missing-bad-vxh.patch +Patch0032: 0032-serial-always-transmit-send-receive-buffers-on-migra.patch +Patch0033: 0033-target-i386-sanitize-x86-MSR_PAT-loaded-from-another.patch +Patch0034: 0034-spapr-disable-memory-hotplug.patch +# For bz#1558723 - Create RHEL-7.6 QEMU machine type for AArch64 +Patch35: kvm-AArch64-Add-virt-rhel7.6-machine-type.patch +# For bz#1570525 - [POWER][QEMU-KVM] Can't hotplug memory to initially memory-less NUMA node +Patch36: kvm-spapr-Add-ibm-max-associativity-domains-property.patch +# For bz#1570525 - [POWER][QEMU-KVM] Can't hotplug memory to initially memory-less NUMA node +Patch37: kvm-Revert-spapr-Don-t-allow-memory-hotplug-to-memory-le.patch +# For bz#1574577 - qemu-kvm segfaults when run guestfsd under TCG +Patch38: kvm-tcg-workaround-branch-instruction-overflow-in-tcg_ou.patch +# For bz#1523857 - [Pegas1.2 FEAT] KVM: Interactive Bootloader - qemu part +Patch39: kvm-s390-ccw-force-diag-308-subcode-to-unsigned-long.patch +# For bz#1523857 - [Pegas1.2 FEAT] KVM: Interactive Bootloader - qemu part +Patch40: kvm-pc-bios-s390-ccw-size_t-should-be-unsigned.patch +# For bz#1523857 - [Pegas1.2 FEAT] KVM: Interactive Bootloader - qemu part +Patch41: kvm-pc-bios-s390-ccw-rename-MAX_TABLE_ENTRIES-to-MAX_BOO.patch +# For bz#1523857 - [Pegas1.2 FEAT] KVM: Interactive Bootloader - qemu part +Patch42: kvm-pc-bios-s390-ccw-fix-loadparm-initialization-and-int.patch +# For bz#1523857 - [Pegas1.2 FEAT] KVM: Interactive Bootloader - qemu part +Patch43: kvm-pc-bios-s390-ccw-fix-non-sequential-boot-entries-eck.patch +# For bz#1523857 - [Pegas1.2 FEAT] KVM: Interactive Bootloader - qemu part +Patch44: kvm-pc-bios-s390-ccw-fix-non-sequential-boot-entries-enu.patch +# For bz#1566153 - IOERROR pause code lost after resuming a VM while I/O error is still present +Patch45: kvm-cpus-Fix-event-order-on-resume-of-stopped-guest.patch +# For bz#1523065 - "qemu-img resize" should fail to decrease the size of logical partition/lvm/iSCSI image with raw format +Patch46: kvm-qemu-img-Check-post-truncation-size.patch +# For bz#1562138 - RHEL 7.6 new qemu-kvm-ma machine type (s390x) +Patch47: kvm-s390x-add-RHEL-7.6-machine-type-for-ccw.patch +# For bz#1557054 - RHEL 7.6 new pseries machine type (ppc64le) +Patch48: kvm-redhat-define-HW_COMPAT_RHEL7_5.patch +# For bz#1557054 - RHEL 7.6 new pseries machine type (ppc64le) +Patch49: kvm-redhat-define-pseries-rhel7.6.0-machine-types.patch +# For bz#1578068 - Backwards compatibility of pc-*-rhel7.5.0 and older machine-types +Patch50: kvm-pc-pc-rhel75.5.0-compat-code.patch +# For bz#1575541 - qemu core dump while installing win10 guest +Patch51: kvm-vga-catch-depth-0.patch +# For bz#1583959 - Incorrect vcpu count limit for 7.4 machine types for windows guests +Patch52: kvm-Fix-x-hv-max-vps-compat-value-for-7.4-machine-type.patch +# For bz#1584984 - Vm starts failed with 'passthrough' smartcard +Patch53: kvm-ccid-card-passthru-fix-regression-in-realize.patch +# For bz#1542080 - Qemu core dump at cirrus_invalidate_region +Patch54: kvm-remove-duplicate-HW_COMPAT_RHEL7_5.patch +# For bz#1542080 - Qemu core dump at cirrus_invalidate_region +Patch55: kvm-Use-4-MB-vram-for-cirrus.patch +# For bz#1505664 - "qemu-kvm: System page size 0x1000000 is not enabled in page_size_mask (0x11000). Performance may be slow" show up while using hugepage as guest's memory +Patch56: kvm-spapr_pci-Remove-unhelpful-pagesize-warning.patch +# For bz#1557995 - QAPI schema for RBD storage misses the 'password-secret' option +Patch57: kvm-qobject-Use-qobject_to-instead-of-type-cast.patch +# For bz#1557995 - QAPI schema for RBD storage misses the 'password-secret' option +Patch58: kvm-qobject-Ensure-base-is-at-offset-0.patch +# For bz#1557995 - QAPI schema for RBD storage misses the 'password-secret' option +Patch59: kvm-qobject-use-a-QObjectBase_-struct.patch +# For bz#1557995 - QAPI schema for RBD storage misses the 'password-secret' option +Patch60: kvm-qobject-Replace-qobject_incref-QINCREF-qobject_decre.patch +# For bz#1557995 - QAPI schema for RBD storage misses the 'password-secret' option +Patch61: kvm-qobject-Modify-qobject_ref-to-return-obj.patch +# For bz#1557995 - QAPI schema for RBD storage misses the 'password-secret' option +Patch62: kvm-rbd-Drop-deprecated-drive-parameter-filename.patch +# For bz#1557995 - QAPI schema for RBD storage misses the 'password-secret' option +Patch63: kvm-iscsi-Drop-deprecated-drive-parameter-filename.patch +# For bz#1557995 - QAPI schema for RBD storage misses the 'password-secret' option +Patch64: kvm-block-Add-block-specific-QDict-header.patch +# For bz#1557995 - QAPI schema for RBD storage misses the 'password-secret' option +Patch65: kvm-qobject-Move-block-specific-qdict-code-to-block-qdic.patch +# For bz#1557995 - QAPI schema for RBD storage misses the 'password-secret' option +Patch66: kvm-block-Fix-blockdev-for-certain-non-string-scalars.patch +# For bz#1557995 - QAPI schema for RBD storage misses the 'password-secret' option +Patch67: kvm-block-Fix-drive-for-certain-non-string-scalars.patch +# For bz#1557995 - QAPI schema for RBD storage misses the 'password-secret' option +Patch68: kvm-block-Clean-up-a-misuse-of-qobject_to-in-.bdrv_co_cr.patch +# For bz#1557995 - QAPI schema for RBD storage misses the 'password-secret' option +Patch69: kvm-block-Factor-out-qobject_input_visitor_new_flat_conf.patch +# For bz#1557995 - QAPI schema for RBD storage misses the 'password-secret' option +Patch70: kvm-block-Make-remaining-uses-of-qobject-input-visitor-m.patch +# For bz#1557995 - QAPI schema for RBD storage misses the 'password-secret' option +Patch71: kvm-block-qdict-Simplify-qdict_flatten_qdict.patch +# For bz#1557995 - QAPI schema for RBD storage misses the 'password-secret' option +Patch72: kvm-block-qdict-Tweak-qdict_flatten_qdict-qdict_flatten_.patch +# For bz#1557995 - QAPI schema for RBD storage misses the 'password-secret' option +Patch73: kvm-block-qdict-Clean-up-qdict_crumple-a-bit.patch +# For bz#1557995 - QAPI schema for RBD storage misses the 'password-secret' option +Patch74: kvm-block-qdict-Simplify-qdict_is_list-some.patch +# For bz#1557995 - QAPI schema for RBD storage misses the 'password-secret' option +Patch75: kvm-check-block-qdict-Rename-qdict_flatten-s-variables-f.patch +# For bz#1557995 - QAPI schema for RBD storage misses the 'password-secret' option +Patch76: kvm-check-block-qdict-Cover-flattening-of-empty-lists-an.patch +# For bz#1557995 - QAPI schema for RBD storage misses the 'password-secret' option +Patch77: kvm-block-Fix-blockdev-blockdev-add-for-empty-objects-an.patch +# For bz#1557995 - QAPI schema for RBD storage misses the 'password-secret' option +Patch78: kvm-rbd-New-parameter-auth-client-required.patch +# For bz#1557995 - QAPI schema for RBD storage misses the 'password-secret' option +Patch79: kvm-rbd-New-parameter-key-secret.patch +# For bz#1572856 - 'block-job-cancel' can not cancel a "drive-mirror" job +Patch80: kvm-block-mirror-honor-ratelimit-again.patch +# For bz#1572856 - 'block-job-cancel' can not cancel a "drive-mirror" job +Patch81: kvm-block-mirror-Make-cancel-always-cancel-pre-READY.patch +# For bz#1572856 - 'block-job-cancel' can not cancel a "drive-mirror" job +Patch82: kvm-iotests-Add-test-for-cancelling-a-mirror-job.patch +# For bz#1518738 - Add 'copy-on-read' filter driver for use with blockdev-add +Patch83: kvm-iotests-Split-214-off-of-122.patch +# For bz#1518738 - Add 'copy-on-read' filter driver for use with blockdev-add +Patch84: kvm-block-Add-COR-filter-driver.patch +# For bz#1518738 - Add 'copy-on-read' filter driver for use with blockdev-add +Patch85: kvm-block-BLK_PERM_WRITE-includes-._UNCHANGED.patch +# For bz#1518738 - Add 'copy-on-read' filter driver for use with blockdev-add +Patch86: kvm-block-Add-BDRV_REQ_WRITE_UNCHANGED-flag.patch +# For bz#1518738 - Add 'copy-on-read' filter driver for use with blockdev-add +Patch87: kvm-block-Set-BDRV_REQ_WRITE_UNCHANGED-for-COR-writes.patch +# For bz#1518738 - Add 'copy-on-read' filter driver for use with blockdev-add +Patch88: kvm-block-quorum-Support-BDRV_REQ_WRITE_UNCHANGED.patch +# For bz#1518738 - Add 'copy-on-read' filter driver for use with blockdev-add +Patch89: kvm-block-Support-BDRV_REQ_WRITE_UNCHANGED-in-filters.patch +# For bz#1518738 - Add 'copy-on-read' filter driver for use with blockdev-add +Patch90: kvm-iotests-Clean-up-wrap-image-in-197.patch +# For bz#1518738 - Add 'copy-on-read' filter driver for use with blockdev-add +Patch91: kvm-iotests-Copy-197-for-COR-filter-driver.patch +# For bz#1518738 - Add 'copy-on-read' filter driver for use with blockdev-add +Patch92: kvm-iotests-Add-test-for-COR-across-nodes.patch +# For bz#1576598 - Segfault in qemu-io and qemu-img with -U --image-opts force-share=off +Patch93: kvm-qemu-io-Use-purely-string-blockdev-options.patch +# For bz#1576598 - Segfault in qemu-io and qemu-img with -U --image-opts force-share=off +Patch94: kvm-qemu-img-Use-only-string-options-in-img_open_opts.patch +# For bz#1576598 - Segfault in qemu-io and qemu-img with -U --image-opts force-share=off +Patch95: kvm-iotests-Add-test-for-U-force-share-conflicts.patch +# For bz#1519617 - The exit code should be non-zero when qemu-io reports an error +Patch96: kvm-qemu-io-Drop-command-functions-return-values.patch +# For bz#1519617 - The exit code should be non-zero when qemu-io reports an error +Patch97: kvm-qemu-io-Let-command-functions-return-error-code.patch +# For bz#1519617 - The exit code should be non-zero when qemu-io reports an error +Patch98: kvm-qemu-io-Exit-with-error-when-a-command-failed.patch +# For bz#1519617 - The exit code should be non-zero when qemu-io reports an error +Patch99: kvm-iotests.py-Add-qemu_io_silent.patch +# For bz#1519617 - The exit code should be non-zero when qemu-io reports an error +Patch100: kvm-iotests-Let-216-make-use-of-qemu-io-s-exit-code.patch +# For bz#1527085 - The copied flag should be updated during '-r leaks' +Patch101: kvm-qcow2-Repair-OFLAG_COPIED-when-fixing-leaks.patch +# For bz#1527085 - The copied flag should be updated during '-r leaks' +Patch102: kvm-iotests-Repairing-error-during-snapshot-deletion.patch +# For bz#1588039 - Possible assertion failure in qemu when a corrupted image is used during an incoming migration +Patch103: kvm-block-Make-bdrv_is_writable-public.patch +# For bz#1588039 - Possible assertion failure in qemu when a corrupted image is used during an incoming migration +Patch104: kvm-qcow2-Do-not-mark-inactive-images-corrupt.patch +# For bz#1588039 - Possible assertion failure in qemu when a corrupted image is used during an incoming migration +Patch105: kvm-iotests-Add-case-for-a-corrupted-inactive-image.patch +# For bz#1592327 - [RHEL-Alt-7.6 FEAT] KVM: CPU Model z14 ZR1 (qemu-kvm-ma) +Patch106: kvm-s390x-cpumodels-add-z14-Model-ZR1.patch +# For bz#1168213 - main-loop: WARNING: I/O thread spun for 1000 iterations while doing stream block device. +Patch107: kvm-main-loop-drop-spin_counter.patch +# For bz#1560847 - [Power8][FW b0320a_1812.861][rhel7.5rc2 3.10.0-861.el7.ppc64le][qemu-kvm-{ma,rhev}-2.10.0-21.el7_5.1.ppc64le] KVM guest does not default to ori type flush even with pseries-rhel7.5.0-sxxm +Patch108: kvm-target-ppc-Factor-out-the-parsing-in-kvmppc_get_cpu_.patch +# For bz#1560847 - [Power8][FW b0320a_1812.861][rhel7.5rc2 3.10.0-861.el7.ppc64le][qemu-kvm-{ma,rhev}-2.10.0-21.el7_5.1.ppc64le] KVM guest does not default to ori type flush even with pseries-rhel7.5.0-sxxm +Patch109: kvm-target-ppc-Don-t-require-private-l1d-cache-on-POWER8.patch +# For bz#1560847 - [Power8][FW b0320a_1812.861][rhel7.5rc2 3.10.0-861.el7.ppc64le][qemu-kvm-{ma,rhev}-2.10.0-21.el7_5.1.ppc64le] KVM guest does not default to ori type flush even with pseries-rhel7.5.0-sxxm +Patch110: kvm-ppc-spapr_caps-Don-t-disable-cap_cfpc-on-POWER8-by-d.patch +Patch111: kvm-Fix-permissions-for-iotest-218.patch +# For bz#1567733 - qemu abort when migrate during guest reboot +Patch112: kvm-qxl-fix-local-renderer-crash.patch +# For bz#1537956 - RFE: qemu-img amend should list the true supported options +Patch113: kvm-qemu-img-Amendment-support-implies-create_opts.patch +# For bz#1537956 - RFE: qemu-img amend should list the true supported options +Patch114: kvm-block-Add-Error-parameter-to-bdrv_amend_options.patch +# For bz#1537956 - RFE: qemu-img amend should list the true supported options +Patch115: kvm-qemu-option-Pull-out-Supported-options-print.patch +# For bz#1537956 - RFE: qemu-img amend should list the true supported options +Patch116: kvm-qemu-img-Add-print_amend_option_help.patch +# For bz#1537956 - RFE: qemu-img amend should list the true supported options +Patch117: kvm-qemu-img-Recognize-no-creation-support-in-o-help.patch +# For bz#1537956 - RFE: qemu-img amend should list the true supported options +Patch118: kvm-iotests-Test-help-option-for-unsupporting-formats.patch +# For bz#1537956 - RFE: qemu-img amend should list the true supported options +Patch119: kvm-iotests-Rework-113.patch +# For bz#1569835 - qemu-img get wrong backing file path after rebasing image with relative path +Patch120: kvm-qemu-img-Resolve-relative-backing-paths-in-rebase.patch +# For bz#1569835 - qemu-img get wrong backing file path after rebasing image with relative path +Patch121: kvm-iotests-Add-test-for-rebasing-with-relative-paths.patch +# For bz#1527898 - [RFE] qemu-img should leave cluster unallocated if it's read as zero throughout the backing chain +Patch122: kvm-qemu-img-Special-post-backing-convert-handling.patch +# For bz#1527898 - [RFE] qemu-img should leave cluster unallocated if it's read as zero throughout the backing chain +Patch123: kvm-iotests-Test-post-backing-convert-target-behavior.patch +# For bz#1564576 - Pegas 1.1 - Require to backport qemu-kvm patch that fixes expected_downtime calculation during migration +Patch124: kvm-migration-calculate-expected_downtime-with-ram_bytes.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch125: kvm-sheepdog-Fix-sd_co_create_opts-memory-leaks.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch126: kvm-qemu-iotests-reduce-chance-of-races-in-185.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch127: kvm-blockjob-do-not-cancel-timer-in-resume.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch128: kvm-nfs-Fix-error-path-in-nfs_options_qdict_to_qapi.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch129: kvm-nfs-Remove-processed-options-from-QDict.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch130: kvm-blockjob-drop-block_job_pause-resume_all.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch131: kvm-blockjob-expose-error-string-via-query.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch132: kvm-blockjob-Fix-assertion-in-block_job_finalize.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch133: kvm-blockjob-Wrappers-for-progress-counter-access.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch134: kvm-blockjob-Move-RateLimit-to-BlockJob.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch135: kvm-blockjob-Implement-block_job_set_speed-centrally.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch136: kvm-blockjob-Introduce-block_job_ratelimit_get_delay.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch137: kvm-blockjob-Add-block_job_driver.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch138: kvm-blockjob-Update-block-job-pause-resume-documentation.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch139: kvm-blockjob-Improve-BlockJobInfo.offset-len-documentati.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch140: kvm-job-Create-Job-JobDriver-and-job_create.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch141: kvm-job-Rename-BlockJobType-into-JobType.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch142: kvm-job-Add-JobDriver.job_type.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch143: kvm-job-Add-job_delete.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch144: kvm-job-Maintain-a-list-of-all-jobs.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch145: kvm-job-Move-state-transitions-to-Job.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch146: kvm-job-Add-reference-counting.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch147: kvm-job-Move-cancelled-to-Job.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch148: kvm-job-Add-Job.aio_context.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch149: kvm-job-Move-defer_to_main_loop-to-Job.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch150: kvm-job-Move-coroutine-and-related-code-to-Job.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch151: kvm-job-Add-job_sleep_ns.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch152: kvm-job-Move-pause-resume-functions-to-Job.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch153: kvm-job-Replace-BlockJob.completed-with-job_is_completed.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch154: kvm-job-Move-BlockJobCreateFlags-to-Job.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch155: kvm-blockjob-Split-block_job_event_pending.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch156: kvm-job-Add-job_event_.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch157: kvm-job-Move-single-job-finalisation-to-Job.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch158: kvm-job-Convert-block_job_cancel_async-to-Job.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch159: kvm-job-Add-job_drain.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch160: kvm-job-Move-.complete-callback-to-Job.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch161: kvm-job-Move-job_finish_sync-to-Job.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch162: kvm-job-Switch-transactions-to-JobTxn.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch163: kvm-job-Move-transactions-to-Job.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch164: kvm-job-Move-completion-and-cancellation-to-Job.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch165: kvm-block-Cancel-job-in-bdrv_close_all-callers.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch166: kvm-job-Add-job_yield.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch167: kvm-job-Add-job_dismiss.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch168: kvm-job-Add-job_is_ready.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch169: kvm-job-Add-job_transition_to_ready.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch170: kvm-job-Move-progress-fields-to-Job.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch171: kvm-job-Introduce-qapi-job.json.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch172: kvm-job-Add-JOB_STATUS_CHANGE-QMP-event.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch173: kvm-job-Add-lifecycle-QMP-commands.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch174: kvm-job-Add-query-jobs-QMP-command.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch175: kvm-blockjob-Remove-BlockJob.driver.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch176: kvm-iotests-Move-qmp_to_opts-to-VM.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch177: kvm-qemu-iotests-Test-job-with-block-jobs.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch178: kvm-vdi-Fix-vdi_co_do_create-return-value.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch179: kvm-vhdx-Fix-vhdx_co_create-return-value.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch180: kvm-job-Add-error-message-for-failing-jobs.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch181: kvm-block-create-Make-x-blockdev-create-a-job.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch182: kvm-qemu-iotests-Add-VM.get_qmp_events_filtered.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch183: kvm-qemu-iotests-Add-VM.qmp_log.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch184: kvm-qemu-iotests-Add-iotests.img_info_log.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch185: kvm-qemu-iotests-Add-VM.run_job.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch186: kvm-qemu-iotests-iotests.py-helper-for-non-file-protocol.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch187: kvm-qemu-iotests-Rewrite-206-for-blockdev-create-job.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch188: kvm-qemu-iotests-Rewrite-207-for-blockdev-create-job.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch189: kvm-qemu-iotests-Rewrite-210-for-blockdev-create-job.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch190: kvm-qemu-iotests-Rewrite-211-for-blockdev-create-job.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch191: kvm-qemu-iotests-Rewrite-212-for-blockdev-create-job.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch192: kvm-qemu-iotests-Rewrite-213-for-blockdev-create-job.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch193: kvm-block-create-Mark-blockdev-create-stable.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch194: kvm-jobs-fix-stale-wording.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch195: kvm-jobs-fix-verb-references-in-docs.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch196: kvm-iotests-Fix-219-s-timing.patch +# For bz#1513543 - [RFE] Add block job to create format on a storage device +Patch197: kvm-iotests-improve-pause_job.patch +# For bz#1583050 - Fails to start guest with Intel vGPU device +Patch198: kvm-vfio-pci-Default-display-option-to-off.patch +# For bz#1572851 - Core dumped after migration when with usb-host +Patch199: kvm-usb-host-skip-open-on-pending-postload-bh.patch +# For bz#1574216 - CVE-2018-3639 qemu-kvm-rhev: hw: cpu: speculative store bypass [rhel-7.6] +Patch200: kvm-i386-Define-the-Virt-SSBD-MSR-and-handling-of-it-CVE.patch +# For bz#1574216 - CVE-2018-3639 qemu-kvm-rhev: hw: cpu: speculative store bypass [rhel-7.6] +Patch201: kvm-i386-define-the-AMD-virt-ssbd-CPUID-feature-bit-CVE-.patch +# For bz#1519144 - qemu-img: image locking doesn't cover image creation +Patch202: kvm-block-file-posix-Pass-FD-to-locking-helpers.patch +# For bz#1519144 - qemu-img: image locking doesn't cover image creation +Patch203: kvm-block-file-posix-File-locking-during-creation.patch +# For bz#1519144 - qemu-img: image locking doesn't cover image creation +Patch204: kvm-iotests-Add-creation-test-to-153.patch +# For bz#1584139 - 2.12 migration fixes +Patch205: kvm-migration-stop-compressing-page-in-migration-thread.patch +# For bz#1584139 - 2.12 migration fixes +Patch206: kvm-migration-stop-compression-to-allocate-and-free-memo.patch +# For bz#1584139 - 2.12 migration fixes +Patch207: kvm-migration-stop-decompression-to-allocate-and-free-me.patch +# For bz#1584139 - 2.12 migration fixes +Patch208: kvm-migration-detect-compression-and-decompression-error.patch +# For bz#1584139 - 2.12 migration fixes +Patch209: kvm-migration-introduce-control_save_page.patch +# For bz#1584139 - 2.12 migration fixes +Patch210: kvm-migration-move-some-code-to-ram_save_host_page.patch +# For bz#1584139 - 2.12 migration fixes +Patch211: kvm-migration-move-calling-control_save_page-to-the-comm.patch +# For bz#1584139 - 2.12 migration fixes +Patch212: kvm-migration-move-calling-save_zero_page-to-the-common-.patch +# For bz#1584139 - 2.12 migration fixes +Patch213: kvm-migration-introduce-save_normal_page.patch +# For bz#1584139 - 2.12 migration fixes +Patch214: kvm-migration-remove-ram_save_compressed_page.patch +# For bz#1584139 - 2.12 migration fixes +Patch215: kvm-migration-block-dirty-bitmap-fix-memory-leak-in-dirt.patch +# For bz#1584139 - 2.12 migration fixes +Patch216: kvm-migration-fix-saving-normal-page-even-if-it-s-been-c.patch +# For bz#1584139 - 2.12 migration fixes +Patch217: kvm-migration-update-index-field-when-delete-or-qsort-RD.patch +# For bz#1584139 - 2.12 migration fixes +Patch218: kvm-Migration-TLS-Fix-crash-due-to-double-cleanup.patch +# For bz#1584139 - 2.12 migration fixes +Patch219: kvm-migration-introduce-decompress-error-check.patch +# For bz#1560854 - Guest is left paused on source host sometimes if kill source libvirtd during live migration due to QEMU image locking +Patch220: kvm-migration-Don-t-activate-block-devices-if-using-S.patch +# For bz#1584139 - 2.12 migration fixes +Patch221: kvm-migration-not-wait-RDMA_CM_EVENT_DISCONNECTED-event-.patch +# For bz#1584139 - 2.12 migration fixes +Patch222: kvm-migration-block-dirty-bitmap-fix-dirty_bitmap_load.patch +# For bz#1526645 - [Intel 7.6 FEAT] vHost Data Plane Acceleration (vDPA) - vhost user client - qemu-kvm-rhev +Patch223: kvm-vhost-user-add-Net-prefix-to-internal-state-structur.patch +# For bz#1526645 - [Intel 7.6 FEAT] vHost Data Plane Acceleration (vDPA) - vhost user client - qemu-kvm-rhev +Patch224: kvm-virtio-support-setting-memory-region-based-host-noti.patch +# For bz#1526645 - [Intel 7.6 FEAT] vHost Data Plane Acceleration (vDPA) - vhost user client - qemu-kvm-rhev +Patch225: kvm-vhost-user-support-receiving-file-descriptors-in-sla.patch +# For bz#1526645 - [Intel 7.6 FEAT] vHost Data Plane Acceleration (vDPA) - vhost user client - qemu-kvm-rhev +Patch226: kvm-osdep-add-wait.h-compat-macros.patch +# For bz#1526645 - [Intel 7.6 FEAT] vHost Data Plane Acceleration (vDPA) - vhost user client - qemu-kvm-rhev +Patch227: kvm-vhost-user-bridge-support-host-notifier.patch +# For bz#1526645 - [Intel 7.6 FEAT] vHost Data Plane Acceleration (vDPA) - vhost user client - qemu-kvm-rhev +Patch228: kvm-vhost-allow-backends-to-filter-memory-sections.patch +# For bz#1526645 - [Intel 7.6 FEAT] vHost Data Plane Acceleration (vDPA) - vhost user client - qemu-kvm-rhev +Patch229: kvm-vhost-user-allow-slave-to-send-fds-via-slave-channel.patch +# For bz#1526645 - [Intel 7.6 FEAT] vHost Data Plane Acceleration (vDPA) - vhost user client - qemu-kvm-rhev +Patch230: kvm-vhost-user-introduce-shared-vhost-user-state.patch +# For bz#1526645 - [Intel 7.6 FEAT] vHost Data Plane Acceleration (vDPA) - vhost user client - qemu-kvm-rhev +Patch231: kvm-vhost-user-support-registering-external-host-notifie.patch +# For bz#1526645 - [Intel 7.6 FEAT] vHost Data Plane Acceleration (vDPA) - vhost user client - qemu-kvm-rhev +Patch232: kvm-libvhost-user-support-host-notifier.patch +# For bz#1482537 - [RFE] qemu-img copy-offloading (convert command) +Patch233: kvm-block-Introduce-API-for-copy-offloading.patch +# For bz#1482537 - [RFE] qemu-img copy-offloading (convert command) +Patch234: kvm-raw-Check-byte-range-uniformly.patch +# For bz#1482537 - [RFE] qemu-img copy-offloading (convert command) +Patch235: kvm-raw-Implement-copy-offloading.patch +# For bz#1482537 - [RFE] qemu-img copy-offloading (convert command) +Patch236: kvm-qcow2-Implement-copy-offloading.patch +# For bz#1482537 - [RFE] qemu-img copy-offloading (convert command) +Patch237: kvm-file-posix-Implement-bdrv_co_copy_range.patch +# For bz#1482537 - [RFE] qemu-img copy-offloading (convert command) +Patch238: kvm-iscsi-Query-and-save-device-designator-when-opening.patch +# For bz#1482537 - [RFE] qemu-img copy-offloading (convert command) +Patch239: kvm-iscsi-Create-and-use-iscsi_co_wait_for_task.patch +# For bz#1482537 - [RFE] qemu-img copy-offloading (convert command) +Patch240: kvm-iscsi-Implement-copy-offloading.patch +# For bz#1482537 - [RFE] qemu-img copy-offloading (convert command) +Patch241: kvm-block-backend-Add-blk_co_copy_range.patch +# For bz#1482537 - [RFE] qemu-img copy-offloading (convert command) +Patch242: kvm-qemu-img-Convert-with-copy-offloading.patch +# For bz#1482537 - [RFE] qemu-img copy-offloading (convert command) +Patch243: kvm-qcow2-Fix-src_offset-in-copy-offloading.patch +# For bz#1482537 - [RFE] qemu-img copy-offloading (convert command) +Patch244: kvm-iscsi-Don-t-blindly-use-designator-length-in-respons.patch +# For bz#1482537 - [RFE] qemu-img copy-offloading (convert command) +Patch245: kvm-file-posix-Fix-EINTR-handling.patch +# For bz#1557051 - pc-i440fx-rhel7.6.0 and pc-q35-rhel7.6.0 machine types (x86) +Patch246: kvm-pc-Add-rhel7.6.0-machine-types.patch +# For bz#1595180 - Can't set rerror/werror with usb-storage +Patch247: kvm-usb-storage-Add-rerror-werror-properties.patch +# For bz#1578381 - Error message need update when specify numa distance with node index >=128 +Patch248: kvm-numa-clarify-error-message-when-node-index-is-out-of.patch +# For bz#1528541 - qemu-img check reports tons of leaked clusters after re-start nfs service to resume writing data in guest +Patch249: kvm-qemu-iotests-Update-026.out.nocache-reference-output.patch +# For bz#1528541 - qemu-img check reports tons of leaked clusters after re-start nfs service to resume writing data in guest +Patch250: kvm-qcow2-Free-allocated-clusters-on-write-error.patch +# For bz#1528541 - qemu-img check reports tons of leaked clusters after re-start nfs service to resume writing data in guest +Patch251: kvm-qemu-iotests-Test-qcow2-not-leaking-clusters-on-writ.patch +# For bz#1595715 - Add ppa15/bpb to the default cpu model for z196 and higher in the 7.6 s390-ccw-virtio machine +Patch252: kvm-s390x-cpumodel-default-enable-bpb-and-ppa15-for-z196.patch +# For bz#1586313 - -smp option is not easily found in the output of qemu help +Patch253: kvm-qemu-options-Add-missing-newline-to-accel-help-text.patch +# For bz#1592648 - Create pseries-rhel7.6.0-sxxm machine type +Patch254: kvm-RHEL-7.6-Add-pseries-rhel7.6.0-sxxm-machine-type.patch +# For bz#1481253 - AMD EPYC/Zen SMT support for KVM / QEMU guest (qemu-kvm-rhev) +Patch255: kvm-i386-Helpers-to-encode-cache-information-consistentl.patch +# For bz#1481253 - AMD EPYC/Zen SMT support for KVM / QEMU guest (qemu-kvm-rhev) +Patch256: kvm-i386-Add-cache-information-in-X86CPUDefinition.patch +# For bz#1481253 - AMD EPYC/Zen SMT support for KVM / QEMU guest (qemu-kvm-rhev) +Patch257: kvm-i386-Initialize-cache-information-for-EPYC-family-pr.patch +# For bz#1481253 - AMD EPYC/Zen SMT support for KVM / QEMU guest (qemu-kvm-rhev) +Patch258: kvm-i386-Add-new-property-to-control-cache-info.patch +# For bz#1481253 - AMD EPYC/Zen SMT support for KVM / QEMU guest (qemu-kvm-rhev) +Patch259: kvm-i386-Clean-up-cache-CPUID-code.patch +# For bz#1481253 - AMD EPYC/Zen SMT support for KVM / QEMU guest (qemu-kvm-rhev) +Patch260: kvm-i386-Populate-AMD-Processor-Cache-Information-for-cp.patch +# For bz#1481253 - AMD EPYC/Zen SMT support for KVM / QEMU guest (qemu-kvm-rhev) +Patch261: kvm-i386-Add-support-for-CPUID_8000_001E-for-AMD.patch +# For bz#1481253 - AMD EPYC/Zen SMT support for KVM / QEMU guest (qemu-kvm-rhev) +Patch262: kvm-i386-Fix-up-the-Node-id-for-CPUID_8000_001E.patch +# For bz#1481253 - AMD EPYC/Zen SMT support for KVM / QEMU guest (qemu-kvm-rhev) +Patch263: kvm-i386-Enable-TOPOEXT-feature-on-AMD-EPYC-CPU.patch +# For bz#1481253 - AMD EPYC/Zen SMT support for KVM / QEMU guest (qemu-kvm-rhev) +Patch264: kvm-i386-Remove-generic-SMT-thread-check.patch +# For bz#1594135 - system_reset many times linux guests cause qemu process Aborted +Patch265: kvm-xhci-fix-guest-triggerable-assert.patch +# For bz#1589634 - Migration failed when rebooting guest with multiple virtio videos +Patch266: kvm-virtio-gpu-tweak-scanout-disable.patch +# For bz#1589634 - Migration failed when rebooting guest with multiple virtio videos +Patch267: kvm-virtio-gpu-update-old-resource-too.patch +# For bz#1589634 - Migration failed when rebooting guest with multiple virtio videos +Patch268: kvm-virtio-gpu-disable-scanout-when-backing-resource-is-.patch +# For bz#1549654 - Reject node-names which would be truncated by the block layer commands +Patch269: kvm-block-Don-t-silently-truncate-node-names.patch +# For bz#1533158 - QEMU support for libvirtd restarting qemu-pr-helper +Patch270: kvm-pr-helper-fix-socket-path-default-in-help.patch +# For bz#1533158 - QEMU support for libvirtd restarting qemu-pr-helper +Patch271: kvm-pr-helper-fix-assertion-failure-on-failed-multipath-.patch +# For bz#1533158 - QEMU support for libvirtd restarting qemu-pr-helper +Patch272: kvm-pr-manager-helper-avoid-SIGSEGV-when-writing-to-the-.patch +# For bz#1533158 - QEMU support for libvirtd restarting qemu-pr-helper +Patch273: kvm-pr-manager-put-stubs-in-.c-file.patch +# For bz#1533158 - QEMU support for libvirtd restarting qemu-pr-helper +Patch274: kvm-pr-manager-add-query-pr-managers-QMP-command.patch +# For bz#1533158 - QEMU support for libvirtd restarting qemu-pr-helper +Patch275: kvm-pr-manager-helper-report-event-on-connection-disconn.patch +# For bz#1533158 - QEMU support for libvirtd restarting qemu-pr-helper +Patch276: kvm-pr-helper-avoid-error-on-PR-IN-command-with-zero-req.patch +# For bz#1533158 - QEMU support for libvirtd restarting qemu-pr-helper +Patch277: kvm-pr-helper-Rework-socket-path-handling.patch +# For bz#1533158 - QEMU support for libvirtd restarting qemu-pr-helper +Patch278: kvm-pr-manager-helper-fix-memory-leak-on-event.patch +# For bz#1556678 - Hot plug usb-ccid for the 2nd time with the same ID as the 1st time failed +Patch279: kvm-object-fix-OBJ_PROP_LINK_UNREF_ON_RELEASE-ambivalenc.patch +# For bz#1556678 - Hot plug usb-ccid for the 2nd time with the same ID as the 1st time failed +Patch280: kvm-usb-hcd-xhci-test-add-a-test-for-ccid-hotplug.patch +# For bz#1556678 - Hot plug usb-ccid for the 2nd time with the same ID as the 1st time failed +Patch281: kvm-Revert-usb-release-the-created-buses.patch +# For bz#1599335 - Image creation locking is too tight and is not properly released +Patch282: kvm-file-posix-Fix-creation-locking.patch +# For bz#1599335 - Image creation locking is too tight and is not properly released +Patch283: kvm-file-posix-Unlock-FD-after-creation.patch +# For bz#1584914 - SATA emulator lags and hangs +Patch284: kvm-ahci-trim-signatures-on-raise-lower.patch +# For bz#1584914 - SATA emulator lags and hangs +Patch285: kvm-ahci-fix-PxCI-register-race.patch +# For bz#1584914 - SATA emulator lags and hangs +Patch286: kvm-ahci-don-t-schedule-unnecessary-BH.patch +# For bz#1595173 - blockdev-create is blocking +Patch287: kvm-qcow2-Fix-qcow2_truncate-error-return-value.patch +# For bz#1595173 - blockdev-create is blocking +Patch288: kvm-block-Convert-.bdrv_truncate-callback-to-coroutine_f.patch +# For bz#1595173 - blockdev-create is blocking +Patch289: kvm-qcow2-Remove-coroutine-trampoline-for-preallocate_co.patch +# For bz#1595173 - blockdev-create is blocking +Patch290: kvm-block-Move-bdrv_truncate-implementation-to-io.c.patch +# For bz#1595173 - blockdev-create is blocking +Patch291: kvm-block-Use-tracked-request-for-truncate.patch +# For bz#1595173 - blockdev-create is blocking +Patch292: kvm-file-posix-Make-.bdrv_co_truncate-asynchronous.patch +# For bz#1590640 - qemu-kvm: block/io.c:1098: bdrv_co_do_copy_on_readv: Assertion `skip_bytes < pnum' failed. +Patch293: kvm-block-Fix-copy-on-read-crash-with-partial-final-clus.patch +# For bz#1599515 - qemu core-dump with aio_read via hmp (util/qemu-thread-posix.c:64: qemu_mutex_lock_impl: Assertion `mutex->initialized' failed) +Patch294: kvm-block-fix-QEMU-crash-with-scsi-hd-and-drive_del.patch +# For bz#1576743 - virtio-rng hangs when running on recent (2.x) QEMU versions +Patch295: kvm-virtio-rng-process-pending-requests-on-DRIVER_OK.patch +# For bz#1525829 - can not boot up a scsi-block passthrough disk via -blockdev with error "cannot get SG_IO version number: Operation not supported. Is this a SCSI device?" +Patch296: kvm-file-posix-specify-expected-filetypes.patch +# For bz#1525829 - can not boot up a scsi-block passthrough disk via -blockdev with error "cannot get SG_IO version number: Operation not supported. Is this a SCSI device?" +Patch297: kvm-iotests-add-test-226-for-file-driver-types.patch +# For bz#1600797 - RHEL7.5/RHV4.2 - qemu patch to align memory to allow 2MB THP +Patch298: kvm-osdep-powerpc64-align-memory-to-allow-2MB-radix-THP-.patch +# For bz#1598287 - After rebooting guest,all the hot plug memory will be assigned to the 1st numa node. +Patch299: kvm-spapr-Correct-inverted-test-in-spapr_pc_dimm_node.patch +Patch300: kvm-Add-functional-acceptance-tests-infrastructure.patch +Patch301: kvm-scripts-qemu.py-allow-adding-to-the-list-of-extra-ar.patch +Patch302: kvm-Acceptance-tests-add-quick-VNC-tests.patch +Patch303: kvm-scripts-qemu.py-introduce-set_console-method.patch +Patch304: kvm-Acceptance-tests-add-Linux-kernel-boot-and-console-c.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch305: kvm-block-dirty-bitmap-add-lock-to-bdrv_enable-disable_d.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch306: kvm-qapi-add-x-block-dirty-bitmap-enable-disable.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch307: kvm-qmp-transaction-support-for-x-block-dirty-bitmap-ena.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch308: kvm-qapi-add-x-block-dirty-bitmap-merge.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch309: kvm-qapi-add-disabled-parameter-to-block-dirty-bitmap-ad.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch310: kvm-block-dirty-bitmap-add-bdrv_enable_dirty_bitmap_lock.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch311: kvm-dirty-bitmap-fix-double-lock-on-bitmap-enabling.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch312: kvm-block-qcow2-bitmap-fix-free_bitmap_clusters.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch313: kvm-qcow2-add-overlap-check-for-bitmap-directory.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch314: kvm-blockdev-enable-non-root-nodes-for-backup-source.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch315: kvm-iotests-add-222-to-test-basic-fleecing.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch316: kvm-qcow2-Remove-dead-check-on-ret.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch317: kvm-block-Move-request-tracking-to-children-in-copy-offl.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch318: kvm-block-Fix-parameter-checking-in-bdrv_co_copy_range_i.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch319: kvm-block-Honour-BDRV_REQ_NO_SERIALISING-in-copy-range.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch320: kvm-backup-Use-copy-offloading.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch321: kvm-block-backup-disable-copy-offloading-for-backup.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch322: kvm-iotests-222-Don-t-run-with-luks.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch323: kvm-block-io-fix-copy_range.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch324: kvm-block-split-flags-in-copy_range.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch325: kvm-block-add-BDRV_REQ_SERIALISING-flag.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch326: kvm-block-backup-fix-fleecing-scheme-use-serialized-writ.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch327: kvm-nbd-server-Reject-0-length-block-status-request.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch328: kvm-nbd-server-fix-trace.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch329: kvm-nbd-server-refactor-NBDExportMetaContexts.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch330: kvm-nbd-server-add-nbd_meta_empty_or_pattern-helper.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch331: kvm-nbd-server-implement-dirty-bitmap-export.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch332: kvm-qapi-new-qmp-command-nbd-server-add-bitmap.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch333: kvm-docs-interop-add-nbd.txt.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch334: kvm-nbd-server-introduce-NBD_CMD_CACHE.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch335: kvm-nbd-server-Silence-gcc-false-positive.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch336: kvm-nbd-server-Fix-dirty-bitmap-logic-regression.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch337: kvm-nbd-server-fix-nbd_co_send_block_status.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch338: kvm-nbd-client-Add-x-dirty-bitmap-to-query-bitmap-from-s.patch +# For bz#1207657 - RFE: QEMU Incremental live backup - push and pull modes +Patch339: kvm-iotests-New-test-223-for-exporting-dirty-bitmap-over.patch +# For bz#1592817 - Retrying on serial_xmit if the pipe is broken may compromise the Guest +Patch340: kvm-hw-char-serial-Only-retry-if-qemu_chr_fe_write-retur.patch +# For bz#1592817 - Retrying on serial_xmit if the pipe is broken may compromise the Guest +Patch341: kvm-hw-char-serial-retry-write-if-EAGAIN.patch +# For bz#1535914 - Disable io throttling for one member disk of a group during io will induce the other one hang with io +Patch342: kvm-throttle-groups-fix-hang-when-group-member-leaves.patch +# For bz#1586357 - Disable new devices in 2.12 +Patch343: kvm-Disable-aarch64-devices-reappeared-after-2.12-rebase.patch +# For bz#1586357 - Disable new devices in 2.12 +Patch344: kvm-Disable-split-irq-device.patch +# For bz#1586357 - Disable new devices in 2.12 +Patch345: kvm-Disable-AT24Cx-i2c-eeprom.patch +# For bz#1586357 - Disable new devices in 2.12 +Patch346: kvm-Disable-CAN-bus-devices.patch +# For bz#1586357 - Disable new devices in 2.12 +Patch347: kvm-Disable-new-superio-devices.patch +# For bz#1586357 - Disable new devices in 2.12 +Patch348: kvm-Disable-new-pvrdma-device.patch +# For bz#1586357 - Disable new devices in 2.12 +Patch349: kvm-Disable-PCIe-to-PCI-bridge-device.patch +# For bz#1607891 - Hotplug events are sometimes lost with virtio-scsi + iothread +Patch350: kvm-qdev-add-HotplugHandler-post_plug-callback.patch +# For bz#1607891 - Hotplug events are sometimes lost with virtio-scsi + iothread +Patch351: kvm-virtio-scsi-fix-hotplug-reset-vs-event-race.patch +# For bz#1608698 - topoext support should not require kernel support +Patch352: kvm-i386-Allow-TOPOEXT-to-be-enabled-on-older-kernels.patch +# For bz#1608778 - qemu/migration: migrate failed from RHEL.7.6 to RHEL.7.5 with e1000-82540em +Patch353: kvm-e1000-Fix-tso_props-compat-for-82540em.patch +# For bz#1586255 - CVE-2018-11806 qemu-kvm-rhev: QEMU: slirp: heap buffer overflow while reassembling fragmented datagrams [rhel-7.6] +Patch354: kvm-slirp-correct-size-computation-while-concatenating-m.patch +# For bz#1595740 - RHEL-Alt-7.6 - qemu has error during migration of larger guests +Patch355: kvm-s390x-sclp-fix-maxram-calculation.patch +# For bz#1607774 - Target files for 'qemu-img convert' do not support thin_provisoning with iscsi/nfs backend +Patch356: kvm-qemu-img-Add-C-option-for-convert-with-copy-offloadi.patch +# For bz#1607774 - Target files for 'qemu-img convert' do not support thin_provisoning with iscsi/nfs backend +Patch357: kvm-iotests-Add-test-for-qemu-img-convert-C-compatibilit.patch +# For bz#1601310 - qemu-img map 'Aborted (core dumped)' when specifying a plain file +Patch358: kvm-qemu-img-Fix-assert-when-mapping-unaligned-raw-file.patch +# For bz#1601310 - qemu-img map 'Aborted (core dumped)' when specifying a plain file +Patch359: kvm-iotests-Add-test-221-to-catch-qemu-img-map-regressio.patch +# For bz#1609234 - Win2016 guest can't recognize pc-dimm hotplugged to node 0 +Patch360: kvm-pc-acpi-fix-memory-hotplug-regression-by-reducing-st.patch +# For bz#1612114 - Anonymous BlockBackends are missing in query-blockstats +Patch361: kvm-block-qapi-Add-qdev-field-to-query-blockstats-result.patch +# For bz#1612114 - Anonymous BlockBackends are missing in query-blockstats +Patch362: kvm-block-qapi-Include-anonymous-BBs-in-query-blockstats.patch +# For bz#1612114 - Anonymous BlockBackends are missing in query-blockstats +Patch363: kvm-qemu-iotests-Test-query-blockstats-with-drive-and-bl.patch +# For bz#1586255 - CVE-2018-11806 qemu-kvm-rhev: QEMU: slirp: heap buffer overflow while reassembling fragmented datagrams [rhel-7.6] +Patch364: kvm-slirp-reformat-m_inc-routine.patch +# For bz#1586255 - CVE-2018-11806 qemu-kvm-rhev: QEMU: slirp: heap buffer overflow while reassembling fragmented datagrams [rhel-7.6] +Patch365: kvm-slirp-Correct-size-check-in-m_inc.patch +# For bz#1390329 - PCIe: Add Generic PCIe-PCI bridge +Patch366: kvm-Revert-Disable-PCIe-to-PCI-bridge-device.patch +# For bz#1562750 - VM doesn't boot from HD +Patch367: kvm-aio-posix-Don-t-count-ctx-notifier-as-progress-when-.patch +# For bz#1562750 - VM doesn't boot from HD +Patch368: kvm-aio-Do-aio_notify_accept-only-during-blocking-aio_po.patch +# For bz#1596010 - The network link can't be detected on guest when the guest uses e1000e model type +Patch369: kvm-e1000e-Do-not-auto-clear-ICR-bits-which-aren-t-set-i.patch +# For bz#1596010 - The network link can't be detected on guest when the guest uses e1000e model type +Patch370: kvm-e1000e-Prevent-MSI-MSI-X-storms.patch +# For bz#1589147 - Handle 64 B USB packets for Smart Card redirection +Patch371: kvm-hw-usb-dev-smartcard-reader-Handle-64-B-USB-packets.patch +# For bz#1613277 - kernel panic in init_amd_cacheinfo +Patch372: kvm-i386-Disable-TOPOEXT-by-default-on-cpu-host.patch +# For bz#1622962 - Add etoken support to qemu-kvm for s390x KVM guests +Patch373: kvm-linux-headers-asm-s390-kvm.h-header-sync.patch +# For bz#1622962 - Add etoken support to qemu-kvm for s390x KVM guests +Patch374: kvm-s390x-kvm-add-etoken-facility.patch +# For bz#1605026 - Quitting VM causes qemu core dump once the block mirror job paused for no enough target space +Patch375: kvm-block-for-jobs-do-not-clear-user_paused-until-after-.patch +# For bz#1605026 - Quitting VM causes qemu core dump once the block mirror job paused for no enough target space +Patch376: kvm-iotests-Add-failure-matching-to-common.qemu.patch +# For bz#1605026 - Quitting VM causes qemu core dump once the block mirror job paused for no enough target space +Patch377: kvm-block-iotest-to-catch-abort-on-forced-blockjob-cance.patch +# For bz#1574216 - CVE-2018-3639 qemu-kvm-rhev: hw: cpu: speculative store bypass [rhel-7.6] +Patch378: kvm-i386-define-the-ssbd-CPUID-feature-bit-CVE-2018-3639.patch +# For bz#1624390 - Memory leaks +Patch379: kvm-target-i386-sev-fix-memory-leaks.patch +# For bz#1624390 - Memory leaks +Patch380: kvm-i386-Fix-arch_query_cpu_model_expansion-leak.patch +# For bz#1539280 - [Intel 7.6 Bug] [KVM][Crystal Ridge] Lack of data persistence guarantee of QEMU writes to host PMEM +Patch381: kvm-migration-discard-non-migratable-RAMBlocks.patch +# For bz#1539280 - [Intel 7.6 Bug] [KVM][Crystal Ridge] Lack of data persistence guarantee of QEMU writes to host PMEM +Patch382: kvm-vfio-pci-do-not-set-the-PCIDevice-has_rom-attribute.patch +# For bz#1539280 - [Intel 7.6 Bug] [KVM][Crystal Ridge] Lack of data persistence guarantee of QEMU writes to host PMEM +Patch383: kvm-memory-exec-Expose-all-memory-block-related-flags.patch +# For bz#1539280 - [Intel 7.6 Bug] [KVM][Crystal Ridge] Lack of data persistence guarantee of QEMU writes to host PMEM +Patch384: kvm-memory-exec-switch-file-ram-allocation-functions-to-.patch +# For bz#1539280 - [Intel 7.6 Bug] [KVM][Crystal Ridge] Lack of data persistence guarantee of QEMU writes to host PMEM +Patch385: kvm-configure-add-libpmem-support.patch +# For bz#1539280 - [Intel 7.6 Bug] [KVM][Crystal Ridge] Lack of data persistence guarantee of QEMU writes to host PMEM +Patch386: kvm-hostmem-file-add-the-pmem-option.patch +# For bz#1539280 - [Intel 7.6 Bug] [KVM][Crystal Ridge] Lack of data persistence guarantee of QEMU writes to host PMEM +Patch387: kvm-mem-nvdimm-ensure-write-persistence-to-PMEM-in-label.patch +# For bz#1539280 - [Intel 7.6 Bug] [KVM][Crystal Ridge] Lack of data persistence guarantee of QEMU writes to host PMEM +Patch388: kvm-migration-ram-Add-check-and-info-message-to-nvdimm-p.patch +# For bz#1539280 - [Intel 7.6 Bug] [KVM][Crystal Ridge] Lack of data persistence guarantee of QEMU writes to host PMEM +Patch389: kvm-migration-ram-ensure-write-persistence-on-loading-al.patch +# For bz#1623859 - Guest "Detected Tx unit Hang" and host "DMAR: fault addr" when booting guest with ixgbe device assignment, +Patch390: kvm-intel-iommu-send-PSI-always-even-if-across-PDEs.patch +# For bz#1623859 - Guest "Detected Tx unit Hang" and host "DMAR: fault addr" when booting guest with ixgbe device assignment, +Patch391: kvm-intel-iommu-remove-IntelIOMMUNotifierNode.patch +# For bz#1623859 - Guest "Detected Tx unit Hang" and host "DMAR: fault addr" when booting guest with ixgbe device assignment, +Patch392: kvm-intel-iommu-add-iommu-lock.patch +# For bz#1623859 - Guest "Detected Tx unit Hang" and host "DMAR: fault addr" when booting guest with ixgbe device assignment, +Patch393: kvm-intel-iommu-only-do-page-walk-for-MAP-notifiers.patch +# For bz#1623859 - Guest "Detected Tx unit Hang" and host "DMAR: fault addr" when booting guest with ixgbe device assignment, +Patch394: kvm-intel-iommu-introduce-vtd_page_walk_info.patch +# For bz#1623859 - Guest "Detected Tx unit Hang" and host "DMAR: fault addr" when booting guest with ixgbe device assignment, +Patch395: kvm-intel-iommu-pass-in-address-space-when-page-walk.patch +# For bz#1623859 - Guest "Detected Tx unit Hang" and host "DMAR: fault addr" when booting guest with ixgbe device assignment, +Patch396: kvm-intel-iommu-trace-domain-id-during-page-walk.patch +# For bz#1623859 - Guest "Detected Tx unit Hang" and host "DMAR: fault addr" when booting guest with ixgbe device assignment, +Patch397: kvm-util-implement-simple-iova-tree.patch +# For bz#1623859 - Guest "Detected Tx unit Hang" and host "DMAR: fault addr" when booting guest with ixgbe device assignment, +Patch398: kvm-intel-iommu-rework-the-page-walk-logic.patch +# For bz#1575578 - Failed to convert a source image to the qcow2 image encrypted by luks +Patch399: kvm-qemu-img-fix-regression-copying-secrets-during-conve.patch +# For bz#1582042 - Segfault on 'blockdev-mirror' with same node as source and target +Patch400: kvm-mirror-Fail-gracefully-for-source-target.patch +# For bz#1626061 - qemu blockjobs other than backup do not support job-finalize or job-dismiss +Patch401: kvm-jobs-change-start-callback-to-run-callback.patch +# For bz#1626061 - qemu blockjobs other than backup do not support job-finalize or job-dismiss +Patch402: kvm-jobs-canonize-Error-object.patch +# For bz#1626061 - qemu blockjobs other than backup do not support job-finalize or job-dismiss +Patch403: kvm-jobs-add-exit-shim.patch +# For bz#1626061 - qemu blockjobs other than backup do not support job-finalize or job-dismiss +Patch404: kvm-block-commit-utilize-job_exit-shim.patch +# For bz#1626061 - qemu blockjobs other than backup do not support job-finalize or job-dismiss +Patch405: kvm-block-mirror-utilize-job_exit-shim.patch +# For bz#1626061 - qemu blockjobs other than backup do not support job-finalize or job-dismiss +Patch406: kvm-jobs-utilize-job_exit-shim.patch +# For bz#1626061 - qemu blockjobs other than backup do not support job-finalize or job-dismiss +Patch407: kvm-block-backup-make-function-variables-consistently-na.patch +# For bz#1626061 - qemu blockjobs other than backup do not support job-finalize or job-dismiss +Patch408: kvm-jobs-remove-ret-argument-to-job_completed-privatize-.patch +# For bz#1626061 - qemu blockjobs other than backup do not support job-finalize or job-dismiss +Patch409: kvm-jobs-remove-job_defer_to_main_loop.patch +# For bz#1626061 - qemu blockjobs other than backup do not support job-finalize or job-dismiss +Patch410: kvm-block-commit-add-block-job-creation-flags.patch +# For bz#1626061 - qemu blockjobs other than backup do not support job-finalize or job-dismiss +Patch411: kvm-block-mirror-add-block-job-creation-flags.patch +# For bz#1626061 - qemu blockjobs other than backup do not support job-finalize or job-dismiss +Patch412: kvm-block-stream-add-block-job-creation-flags.patch +# For bz#1626061 - qemu blockjobs other than backup do not support job-finalize or job-dismiss +Patch413: kvm-block-commit-refactor-commit-to-use-job-callbacks.patch +# For bz#1626061 - qemu blockjobs other than backup do not support job-finalize or job-dismiss +Patch414: kvm-block-mirror-don-t-install-backing-chain-on-abort.patch +# For bz#1626061 - qemu blockjobs other than backup do not support job-finalize or job-dismiss +Patch415: kvm-block-mirror-conservative-mirror_exit-refactor.patch +# For bz#1626061 - qemu blockjobs other than backup do not support job-finalize or job-dismiss +Patch416: kvm-block-stream-refactor-stream-to-use-job-callbacks.patch +# For bz#1626061 - qemu blockjobs other than backup do not support job-finalize or job-dismiss +Patch417: kvm-tests-blockjob-replace-Blockjob-with-Job.patch +# For bz#1626061 - qemu blockjobs other than backup do not support job-finalize or job-dismiss +Patch418: kvm-tests-test-blockjob-remove-exit-callback.patch +# For bz#1626061 - qemu blockjobs other than backup do not support job-finalize or job-dismiss +Patch419: kvm-tests-test-blockjob-txn-move-.exit-to-.clean.patch +# For bz#1626061 - qemu blockjobs other than backup do not support job-finalize or job-dismiss +Patch420: kvm-jobs-remove-.exit-callback.patch +# For bz#1626061 - qemu blockjobs other than backup do not support job-finalize or job-dismiss +Patch421: kvm-qapi-block-commit-expose-new-job-properties.patch +# For bz#1626061 - qemu blockjobs other than backup do not support job-finalize or job-dismiss +Patch422: kvm-qapi-block-mirror-expose-new-job-properties.patch +# For bz#1626061 - qemu blockjobs other than backup do not support job-finalize or job-dismiss +Patch423: kvm-qapi-block-stream-expose-new-job-properties.patch +# For bz#1626061 - qemu blockjobs other than backup do not support job-finalize or job-dismiss +Patch424: kvm-block-backup-qapi-documentation-fixup.patch +# For bz#1626061 - qemu blockjobs other than backup do not support job-finalize or job-dismiss +Patch425: kvm-blockdev-document-transactional-shortcomings.patch +# For bz#1624012 - allow using node-names with block-commit +Patch426: kvm-commit-Add-top-node-base-node-options.patch +# For bz#1624012 - allow using node-names with block-commit +Patch427: kvm-qemu-iotests-Test-commit-with-top-node-base-node.patch +# For bz#1610605 - rbd json format of 7.6 is incompatible with 7.5 +Patch428: kvm-block-rbd-pull-out-qemu_rbd_convert_options.patch +# For bz#1610605 - rbd json format of 7.6 is incompatible with 7.5 +Patch429: kvm-block-rbd-Attempt-to-parse-legacy-filenames.patch +# For bz#1610605 - rbd json format of 7.6 is incompatible with 7.5 +Patch430: kvm-block-rbd-add-iotest-for-rbd-legacy-keyvalue-filenam.patch +# For bz#1626059 - RHEL6 guest panics on boot if hotpluggable memory (pc-dimm) is present at boot time +Patch431: kvm-pc-acpi-revert-back-to-1-SRAT-entry-for-hotpluggable.patch +# For bz#1628373 - blockdev-backup does not accept bitmap parameter +Patch432: kvm-blockdev-backup-add-bitmap-argument.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch433: kvm-test-bdrv-drain-bdrv_drain-works-with-cross-AioConte.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch434: kvm-block-Use-bdrv_do_drain_begin-end-in-bdrv_drain_all.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch435: kvm-block-Remove-recursive-parameter-from-bdrv_drain_inv.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch436: kvm-block-Don-t-manually-poll-in-bdrv_drain_all.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch437: kvm-tests-test-bdrv-drain-bdrv_drain_all-works-in-corout.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch438: kvm-block-Avoid-unnecessary-aio_poll-in-AIO_WAIT_WHILE.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch439: kvm-block-Really-pause-block-jobs-on-drain.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch440: kvm-block-Remove-bdrv_drain_recurse.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch441: kvm-test-bdrv-drain-Add-test-for-node-deletion.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch442: kvm-block-Drain-recursively-with-a-single-BDRV_POLL_WHIL.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch443: kvm-test-bdrv-drain-Test-node-deletion-in-subtree-recurs.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch444: kvm-block-Don-t-poll-in-parent-drain-callbacks.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch445: kvm-test-bdrv-drain-Graph-change-through-parent-callback.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch446: kvm-block-Defer-.bdrv_drain_begin-callback-to-polling-ph.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch447: kvm-test-bdrv-drain-Test-that-bdrv_drain_invoke-doesn-t-.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch448: kvm-block-Allow-AIO_WAIT_WHILE-with-NULL-ctx.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch449: kvm-block-Move-bdrv_drain_all_begin-out-of-coroutine-con.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch450: kvm-block-ignore_bds_parents-parameter-for-drain-functio.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch451: kvm-block-Allow-graph-changes-in-bdrv_drain_all_begin-en.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch452: kvm-test-bdrv-drain-Test-graph-changes-in-drain_all-sect.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch453: kvm-block-Poll-after-drain-on-attaching-a-node.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch454: kvm-test-bdrv-drain-Test-bdrv_append-to-drained-node.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch455: kvm-block-linux-aio-acquire-AioContext-before-qemu_laio_.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch456: kvm-util-async-use-qemu_aio_coroutine_enter-in-co_schedu.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch457: kvm-job-Fix-nested-aio_poll-hanging-in-job_txn_apply.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch458: kvm-job-Fix-missing-locking-due-to-mismerge.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch459: kvm-blockjob-Wake-up-BDS-when-job-becomes-idle.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch460: kvm-aio-wait-Increase-num_waiters-even-in-home-thread.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch461: kvm-test-bdrv-drain-Drain-with-block-jobs-in-an-I-O-thre.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch462: kvm-test-blockjob-Acquire-AioContext-around-job_cancel_s.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch463: kvm-job-Use-AIO_WAIT_WHILE-in-job_finish_sync.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch464: kvm-test-bdrv-drain-Test-AIO_WAIT_WHILE-in-completion-ca.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch465: kvm-block-Add-missing-locking-in-bdrv_co_drain_bh_cb.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch466: kvm-block-backend-Add-.drained_poll-callback.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch467: kvm-block-backend-Fix-potential-double-blk_delete.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch468: kvm-block-backend-Decrease-in_flight-only-after-callback.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch469: kvm-mirror-Fix-potential-use-after-free-in-active-commit.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch470: kvm-blockjob-Lie-better-in-child_job_drained_poll.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch471: kvm-block-Remove-aio_poll-in-bdrv_drain_poll-variants.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch472: kvm-test-bdrv-drain-Test-nested-poll-in-bdrv_drain_poll_.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch473: kvm-job-Avoid-deadlocks-in-job_completed_txn_abort.patch +# For bz#1601212 - qemu coredumps on block-commit +Patch474: kvm-test-bdrv-drain-AIO_WAIT_WHILE-in-job-.commit-.abort.patch +# For bz#1628191 - ~40% virtio_blk disk performance drop for win2012r2 guest when comparing qemu-kvm-rhev-2.12.0-9 with qemu-kvm-rhev-2.12.0-12 +Patch475: kvm-aio-posix-fix-concurrent-access-to-poll_disable_cnt.patch +# For bz#1628191 - ~40% virtio_blk disk performance drop for win2012r2 guest when comparing qemu-kvm-rhev-2.12.0-9 with qemu-kvm-rhev-2.12.0-12 +Patch476: kvm-aio-posix-compute-timeout-before-polling.patch +# For bz#1628191 - ~40% virtio_blk disk performance drop for win2012r2 guest when comparing qemu-kvm-rhev-2.12.0-9 with qemu-kvm-rhev-2.12.0-12 +Patch477: kvm-aio-posix-do-skip-system-call-if-ctx-notifier-pollin.patch +# For bz#1618584 - block commit aborts with "Co-routine was already scheduled" +Patch478: kvm-test-bdrv-drain-Fix-outdated-comments.patch +# For bz#1618584 - block commit aborts with "Co-routine was already scheduled" +Patch479: kvm-block-Use-a-single-global-AioWait.patch +# For bz#1618584 - block commit aborts with "Co-routine was already scheduled" +Patch480: kvm-test-bdrv-drain-Test-draining-job-source-child-and-p.patch BuildRequires: zlib-devel BuildRequires: glib2-devel @@ -1101,10 +1146,8 @@ BuildRequires: libseccomp-devel >= 2.3.0 # For network block driver BuildRequires: libcurl-devel BuildRequires: libssh2-devel -%ifarch x86_64 BuildRequires: librados2-devel BuildRequires: librbd1-devel -%endif %if %{have_gluster} # For gluster block driver BuildRequires: glusterfs-api-devel >= 3.6.0 @@ -1175,6 +1218,15 @@ BuildRequires: diffutils BuildRequires: binutils >= 2.27-16 %endif +# qemu-keymap +BuildRequires: pkgconfig(xkbcommon) + +%if %{have_opengl} +BuildRequires: pkgconfig(epoxy) +BuildRequires: pkgconfig(libdrm) +BuildRequires: pkgconfig(gbm) +%endif + Requires: qemu-img%{?pkgsuffix} = %{epoch}:%{version}-%{release} # RHEV-specific changes: @@ -1248,39 +1300,68 @@ cp %{SOURCE29} pc-bios patch_command='patch -p1 -F1 -s' %endif -%patch2 -p1 -%patch3 -p1 -%patch4 -p1 -%patch5 -p1 -%patch6 -p1 -%patch7 -p1 -%patch8 -p1 -%patch9 -p1 -%patch10 -p1 -%patch11 -p1 -%patch12 -p1 -%patch13 -p1 -%patch14 -p1 -%patch15 -p1 -%patch16 -p1 -%patch17 -p1 -%patch18 -p1 -%patch19 -p1 -%patch20 -p1 -%patch21 -p1 -%patch22 -p1 -%patch23 -p1 -%patch24 -p1 -%patch25 -p1 -%patch26 -p1 -%patch27 -p1 -%patch28 -p1 -%patch29 -p1 -%patch30 -p1 -%patch31 -p1 -%patch32 -p1 -%patch33 -p1 -%patch34 -p1 +ApplyPatch() +{ + local patch=$1 + shift + if [ ! -f $RPM_SOURCE_DIR/$patch ]; then + exit 1 + fi + case "$patch" in + *.bz2) bunzip2 < "$RPM_SOURCE_DIR/$patch" | $patch_command ${1+"$@"} ;; + *.gz) gunzip < "$RPM_SOURCE_DIR/$patch" | $patch_command ${1+"$@"} ;; + *) $patch_command ${1+"$@"} < "$RPM_SOURCE_DIR/$patch" ;; + esac +} + +# don't apply patch if it's empty or does not exist +ApplyOptionalPatch() +{ + local patch=$1 + shift + if [ ! -f $RPM_SOURCE_DIR/$patch ]; then + return 0 + fi + local C=$(wc -l $RPM_SOURCE_DIR/$patch | awk '{print $1}') + if [ "$C" -gt 9 ]; then + ApplyPatch $patch ${1+"$@"} + fi +} + + +%patch0001 -p1 +%patch0003 -p1 +%patch0004 -p1 +%patch0005 -p1 +%patch0006 -p1 +%patch0007 -p1 +%patch0008 -p1 +%patch0009 -p1 +%patch0010 -p1 +%patch0011 -p1 +%patch0012 -p1 +%patch0013 -p1 +%patch0014 -p1 +%patch0015 -p1 +%patch0016 -p1 +%patch0017 -p1 +%patch0018 -p1 +%patch0019 -p1 +%patch0020 -p1 +%patch0021 -p1 +%patch0022 -p1 +%patch0023 -p1 +%patch0024 -p1 +%patch0025 -p1 +%patch0026 -p1 +%patch0027 -p1 +%patch0028 -p1 +%patch0029 -p1 +%patch0030 -p1 +%patch0031 -p1 +%patch0032 -p1 +%patch0033 -p1 +%patch0034 -p1 %patch35 -p1 %patch36 -p1 %patch37 -p1 @@ -1335,6 +1416,7 @@ cp %{SOURCE29} pc-bios %patch86 -p1 %patch87 -p1 %patch88 -p1 +%patch89 -p1 %patch90 -p1 %patch91 -p1 %patch92 -p1 @@ -1704,6 +1786,33 @@ cp %{SOURCE29} pc-bios %patch456 -p1 %patch457 -p1 %patch458 -p1 +%patch459 -p1 +%patch460 -p1 +%patch461 -p1 +%patch462 -p1 +%patch463 -p1 +%patch464 -p1 +%patch465 -p1 +%patch466 -p1 +%patch467 -p1 +%patch468 -p1 +%patch469 -p1 +%patch470 -p1 +%patch471 -p1 +%patch472 -p1 +%patch473 -p1 +%patch474 -p1 +%patch475 -p1 +%patch476 -p1 +%patch477 -p1 +%patch478 -p1 +%patch479 -p1 +%patch480 -p1 + +# Fix executable permission for iotests +chmod 755 $(ls tests/qemu-iotests/???) + +ApplyOptionalPatch qemu-kvm-test.patch # for tscdeadline_latency.flat %ifarch x86_64 @@ -1718,11 +1827,11 @@ extraldflags="-Wl,--build-id"; buildldflags="VL_LDFLAGS=-Wl,--build-id" # QEMU already knows how to set _FORTIFY_SOURCE -%global optflags %(echo %{optflags} | sed 's/-Wp,-D_FORTIFY_SOURCE=2//') +%global qemuoptflags %(echo %{optflags} | sed 's/-Wp,-D_FORTIFY_SOURCE=2//') %ifarch s390 # drop -g flag to prevent memory exhaustion by linker - %global optflags %(echo %{optflags} | sed 's/-g//') + %global qemuoptflags %(echo %{qemuoptflags} | sed 's/-g//') sed -i.debug 's/"-g $CFLAGS"/"$CFLAGS"/g' configure %endif @@ -1738,7 +1847,7 @@ cp %{SOURCE24} build_configure.sh "%{pkgname}" \ "%{kvm_target}" \ "%{name}-%{version}-%{release}" \ - "%{optflags}" \ + "%{qemuoptflags}" \ %if 0%{have_fdt} enable \ %else @@ -1755,11 +1864,7 @@ cp %{SOURCE24} build_configure.sh %else disable \ %endif -%ifarch x86_64 enable \ -%else - disable \ -%endif %if 0%{have_librdma} enable \ %else @@ -1775,6 +1880,11 @@ cp %{SOURCE24} build_configure.sh %else disable \ %endif +%if 0%{have_opengl} + enable \ +%else + disable \ +%endif %if 0%{have_usbredir} enable \ %else @@ -1810,6 +1920,11 @@ cp %{SOURCE24} build_configure.sh %else disable \ %endif +%if 0%{have_tcmalloc} + disable \ +%else + enable \ +%endif --target-list="$buildarch" echo "config-host.mak contents:" @@ -1832,7 +1947,7 @@ make V=1 %{?_smp_mflags} $buildldflags cp -a %{kvm_target}-softmmu/qemu-system-%{kvm_target} qemu-kvm -gcc %{SOURCE6} -O2 -g -o ksmctl +gcc %{SOURCE6} $RPM_OPT_FLAGS $RPM_LD_FLAGS -o ksmctl # build tscdeadline_latency.flat %ifarch x86_64 @@ -1909,7 +2024,7 @@ mkdir -p $RPM_BUILD_ROOT%{_datadir}/%{pkgname}/tracetool/format install -m 0644 -t $RPM_BUILD_ROOT%{_datadir}/%{pkgname}/tracetool/format scripts/tracetool/format/*.py mkdir -p $RPM_BUILD_ROOT%{qemudocdir} -install -p -m 0644 -t ${RPM_BUILD_ROOT}%{qemudocdir} Changelog README README.systemtap COPYING COPYING.LIB LICENSE %{SOURCE19} docs/interop/qmp-spec.txt +install -p -m 0644 -t ${RPM_BUILD_ROOT}%{qemudocdir} Changelog README README.systemtap COPYING COPYING.LIB LICENSE %{SOURCE19} docs/interop/qmp-spec.txt chmod -x ${RPM_BUILD_ROOT}%{_mandir}/man1/* chmod -x ${RPM_BUILD_ROOT}%{_mandir}/man8/* @@ -1931,8 +2046,11 @@ rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{pkgname}/s390-zipl.rom rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{pkgname}/u-boot.e500 rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{pkgname}/qemu_vga.ndrv rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{pkgname}/skiboot.lid - rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{pkgname}/s390-ccw.img +rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{pkgname}/hppa-firmware.img +rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{pkgname}/canyonlands.dtb +rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{pkgname}/u-boot-sam460-20100605.bin + %ifarch s390x # Use the s390-ccw.img that we've just built, not the pre-built one install -m 0644 pc-bios/s390-ccw/s390-ccw.img $RPM_BUILD_ROOT%{_datadir}/%{pkgname}/ @@ -1945,7 +2063,6 @@ rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{pkgname}/s390-ccw.img %endif %ifnarch x86_64 - rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{pkgname}/acpi-dsdt.aml rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{pkgname}/kvmvapic.bin rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{pkgname}/linuxboot.bin rm -rf ${RPM_BUILD_ROOT}%{_datadir}/%{pkgname}/multiboot.bin @@ -2009,6 +2126,9 @@ rom_link() { install -D -p -m 755 %{SOURCE21} $RPM_BUILD_ROOT%{_prefix}/lib/systemd/kvm-setup install -D -p -m 644 %{SOURCE22} $RPM_BUILD_ROOT%{_unitdir}/kvm-setup.service install -D -p -m 644 %{SOURCE23} $RPM_BUILD_ROOT%{_presetdir}/85-kvm.preset + %ifarch %{power64} + install -D -p -m 0644 %{SOURCE34} $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/kvm + %endif %endif %if 0%{have_memlock_limits} @@ -2030,6 +2150,9 @@ find $RPM_BUILD_ROOT -name "libcacard.so*" -exec chmod +x \{\} \; find $RPM_BUILD_ROOT -name '*.la' -or -name '*.a' | xargs rm -f +# Hack to prevent coloring tools package +chmod 0644 $RPM_BUILD_ROOT%{_bindir}/qemu-keymap + %check export DIFF=diff; make check V=1 @@ -2120,7 +2243,6 @@ useradd -r -u 107 -g qemu -G kvm -d / -s /sbin/nologin \ %files %defattr(-,root,root) %ifarch x86_64 - %{_datadir}/%{pkgname}/acpi-dsdt.aml %{_datadir}/%{pkgname}/bios.bin %{_datadir}/%{pkgname}/bios-256k.bin %{_datadir}/%{pkgname}/linuxboot.bin @@ -2164,6 +2286,9 @@ useradd -r -u 107 -g qemu -G kvm -d / -s /sbin/nologin \ %{_prefix}/lib/systemd/kvm-setup %{_unitdir}/kvm-setup.service %{_presetdir}/85-kvm.preset + %ifarch %{power64} + %config(noreplace) %{_sysconfdir}/sysconfig/kvm + %endif %endif %if 0%{have_memlock_limits} %{_sysconfdir}/security/limits.d/95-kvm-memlock.conf @@ -2172,6 +2297,7 @@ useradd -r -u 107 -g qemu -G kvm -d / -s /sbin/nologin \ %files -n qemu-kvm-tools%{?pkgsuffix} %defattr(-,root,root,-) %{_bindir}/kvm_stat +%attr(0755, -, -) %{_bindir}/qemu-keymap %{_mandir}/man1/kvm_stat.1* %ifarch x86_64 %{_datadir}/%{pkgname}/tscdeadline_latency.flat @@ -2202,54 +2328,725 @@ useradd -r -u 107 -g qemu -G kvm -d / -s /sbin/nologin \ %endif %changelog -* Tue Aug 21 2018 Miroslav Rezanina - ma-2.10.0-21.el7_5.4 -- kvm-slirp-correct-size-computation-while-concatenating-m.patch [bz#1586247] -- kvm-slirp-reformat-m_inc-routine.patch [bz#1586247] -- kvm-slirp-Correct-size-check-in-m_inc.patch [bz#1586247] -- Resolves: bz#1586247 - (CVE-2018-11806 qemu-kvm-ma: QEMU: slirp: heap buffer overflow while reassembling fragmented datagrams [rhel-7.5.z]) - -* Mon Jul 02 2018 Miroslav Rezanina - ma-2.10.0-21.el7_5.3 -- kvm-scsi-disk-allow-customizing-the-SCSI-version.patch [bz#1593193] -- kvm-hw-scsi-support-SCSI-2-passthrough-without-PI.patch [bz#1593193] -- kvm-s390x-fix-storage-attributes-migration-for-non-small.patch [bz#1596553] -- Resolves: bz#1593193 - (Pegas1.1 - SCSI pass-thru of aacraid RAID1 is inaccessible (qemu-kvm-ma) [rhel-7.5.z]) -- Resolves: bz#1596553 - (RHEL-Alt-7.5 - qemu has error during migration of larger guests [rhel-7.5.z]) - -* Fri Apr 13 2018 Miroslav Rezanina - ma-2.10.0-21.el7_5.2 -- kvm-block-Fix-flags-in-reopen-queue.patch [bz#1557206] -- kvm-iotests-Add-regression-test-for-commit-base-locking.patch [bz#1557206] -- kvm-vga-add-ram_addr_t-cast.patch [bz#1566878] -- kvm-vga-fix-region-calculation.patch [bz#1566878] -- Resolves: bz#1557206 - ([Regression] Cannot delete VM's snapshot [rhel-7.5.z]) -- Resolves: bz#1566878 - (CVE-2018-7858 qemu-kvm-ma: Qemu: cirrus: OOB access when updating vga display [rhel-7] [rhel-7.5.z]) - -* Wed Mar 14 2018 Miroslav Rezanina - ma-2.10.0-21.el7_5.1 -- kvm-memory-inline-some-performance-sensitive-accessors.patch [bz#1554930] -- kvm-address_space_write-address_space_to_flatview-needs-.patch [bz#1554930] -- kvm-address_space_read-address_space_to_flatview-needs-R.patch [bz#1554930] -- kvm-address_space_access_valid-address_space_to_flatview.patch [bz#1554930] -- kvm-address_space_map-address_space_to_flatview-needs-RC.patch [bz#1554930] -- kvm-address_space_rw-address_space_to_flatview-needs-RCU.patch [bz#1554930] -- kvm-ppc-spapr-caps-Change-migration-macro-to-take-full-s.patch [bz#1554957] -- kvm-ppc-spapr-caps-Disallow-setting-workaround-for-spapr.patch [bz#1554957] -- kvm-target-ppc-Check-mask-when-setting-cap_ppc_safe_indi.patch [bz#1554957] -- kvm-ppc-spapr-caps-Add-support-for-custom-spapr_capabili.patch [bz#1554957] -- kvm-ppc-spapr-caps-Convert-cap-cfpc-to-custom-spapr-cap.patch [bz#1554957] -- kvm-ppc-spapr-caps-Convert-cap-sbbc-to-custom-spapr-cap.patch [bz#1554957] -- kvm-ppc-spapr-caps-Convert-cap-ibs-to-custom-spapr-cap.patch [bz#1554957] -- kvm-ppc-spapr-caps-Define-the-pseries-2.12-sxxm-machine-.patch [bz#1554957] -- kvm-redhat-Define-the-pseries-rhel7.5-sxxm-machine-type.patch [bz#1554957] -- kvm-redhat-Define-the-pseries-rhel7.4-sxxm-machine-type.patch [bz#1554957] -- kvm-redhat-Define-the-pseries-rhel7.3-sxxm-machine-type.patch [bz#1554957] -- Resolves: bz#1554930 - (incorrect locking (possible use-after-free) with bug 1481593 fix [rhel-7.5.z]) -- Resolves: bz#1554957 - ([CVE-2017-5754] Variant3: POWER {qemu-kvm-ma} Add machine type variants [rhel-7.5.z]) +* Fri Sep 21 2018 Miroslav Rezanina - 2.12.0-18.el7 +- kvm-test-bdrv-drain-Fix-outdated-comments.patch [bz#1618584] +- kvm-block-Use-a-single-global-AioWait.patch [bz#1618584] +- kvm-test-bdrv-drain-Test-draining-job-source-child-and-p.patch [bz#1618584] +- Resolves: bz#1618584 + (block commit aborts with "Co-routine was already scheduled") + +* Wed Sep 19 2018 Miroslav Rezanina - 2.12.0-17.el7 +- kvm-aio-posix-fix-concurrent-access-to-poll_disable_cnt.patch [bz#1628191] +- kvm-aio-posix-compute-timeout-before-polling.patch [bz#1628191] +- kvm-aio-posix-do-skip-system-call-if-ctx-notifier-pollin.patch [bz#1628191] +- Resolves: bz#1628191 + (~40% virtio_blk disk performance drop for win2012r2 guest when comparing qemu-kvm-rhev-2.12.0-9 with qemu-kvm-rhev-2.12.0-12) + +* Mon Sep 17 2018 Miroslav Rezanina - 2.12.0-16.el7 +- kvm-commit-Add-top-node-base-node-options.patch [bz#1624012] +- kvm-qemu-iotests-Test-commit-with-top-node-base-node.patch [bz#1624012] +- kvm-block-rbd-pull-out-qemu_rbd_convert_options.patch [bz#1610605] +- kvm-block-rbd-Attempt-to-parse-legacy-filenames.patch [bz#1610605] +- kvm-block-rbd-add-iotest-for-rbd-legacy-keyvalue-filenam.patch [bz#1610605] +- kvm-pc-acpi-revert-back-to-1-SRAT-entry-for-hotpluggable.patch [bz#1626059] +- kvm-blockdev-backup-add-bitmap-argument.patch [bz#1628373] +- kvm-test-bdrv-drain-bdrv_drain-works-with-cross-AioConte.patch [bz#1601212] +- kvm-block-Use-bdrv_do_drain_begin-end-in-bdrv_drain_all.patch [bz#1601212] +- kvm-block-Remove-recursive-parameter-from-bdrv_drain_inv.patch [bz#1601212] +- kvm-block-Don-t-manually-poll-in-bdrv_drain_all.patch [bz#1601212] +- kvm-tests-test-bdrv-drain-bdrv_drain_all-works-in-corout.patch [bz#1601212] +- kvm-block-Avoid-unnecessary-aio_poll-in-AIO_WAIT_WHILE.patch [bz#1601212] +- kvm-block-Really-pause-block-jobs-on-drain.patch [bz#1601212] +- kvm-block-Remove-bdrv_drain_recurse.patch [bz#1601212] +- kvm-test-bdrv-drain-Add-test-for-node-deletion.patch [bz#1601212] +- kvm-block-Drain-recursively-with-a-single-BDRV_POLL_WHIL.patch [bz#1601212] +- kvm-test-bdrv-drain-Test-node-deletion-in-subtree-recurs.patch [bz#1601212] +- kvm-block-Don-t-poll-in-parent-drain-callbacks.patch [bz#1601212] +- kvm-test-bdrv-drain-Graph-change-through-parent-callback.patch [bz#1601212] +- kvm-block-Defer-.bdrv_drain_begin-callback-to-polling-ph.patch [bz#1601212] +- kvm-test-bdrv-drain-Test-that-bdrv_drain_invoke-doesn-t-.patch [bz#1601212] +- kvm-block-Allow-AIO_WAIT_WHILE-with-NULL-ctx.patch [bz#1601212] +- kvm-block-Move-bdrv_drain_all_begin-out-of-coroutine-con.patch [bz#1601212] +- kvm-block-ignore_bds_parents-parameter-for-drain-functio.patch [bz#1601212] +- kvm-block-Allow-graph-changes-in-bdrv_drain_all_begin-en.patch [bz#1601212] +- kvm-test-bdrv-drain-Test-graph-changes-in-drain_all-sect.patch [bz#1601212] +- kvm-block-Poll-after-drain-on-attaching-a-node.patch [bz#1601212] +- kvm-test-bdrv-drain-Test-bdrv_append-to-drained-node.patch [bz#1601212] +- kvm-block-linux-aio-acquire-AioContext-before-qemu_laio_.patch [bz#1601212] +- kvm-util-async-use-qemu_aio_coroutine_enter-in-co_schedu.patch [bz#1601212] +- kvm-job-Fix-nested-aio_poll-hanging-in-job_txn_apply.patch [bz#1601212] +- kvm-job-Fix-missing-locking-due-to-mismerge.patch [bz#1601212] +- kvm-blockjob-Wake-up-BDS-when-job-becomes-idle.patch [bz#1601212] +- kvm-aio-wait-Increase-num_waiters-even-in-home-thread.patch [bz#1601212] +- kvm-test-bdrv-drain-Drain-with-block-jobs-in-an-I-O-thre.patch [bz#1601212] +- kvm-test-blockjob-Acquire-AioContext-around-job_cancel_s.patch [bz#1601212] +- kvm-job-Use-AIO_WAIT_WHILE-in-job_finish_sync.patch [bz#1601212] +- kvm-test-bdrv-drain-Test-AIO_WAIT_WHILE-in-completion-ca.patch [bz#1601212] +- kvm-block-Add-missing-locking-in-bdrv_co_drain_bh_cb.patch [bz#1601212] +- kvm-block-backend-Add-.drained_poll-callback.patch [bz#1601212] +- kvm-block-backend-Fix-potential-double-blk_delete.patch [bz#1601212] +- kvm-block-backend-Decrease-in_flight-only-after-callback.patch [bz#1601212] +- kvm-mirror-Fix-potential-use-after-free-in-active-commit.patch [bz#1601212] +- kvm-blockjob-Lie-better-in-child_job_drained_poll.patch [bz#1601212] +- kvm-block-Remove-aio_poll-in-bdrv_drain_poll-variants.patch [bz#1601212] +- kvm-test-bdrv-drain-Test-nested-poll-in-bdrv_drain_poll_.patch [bz#1601212] +- kvm-job-Avoid-deadlocks-in-job_completed_txn_abort.patch [bz#1601212] +- kvm-test-bdrv-drain-AIO_WAIT_WHILE-in-job-.commit-.abort.patch [bz#1601212] +- Resolves: bz#1601212 + (qemu coredumps on block-commit) +- Resolves: bz#1610605 + (rbd json format of 7.6 is incompatible with 7.5) +- Resolves: bz#1624012 + (allow using node-names with block-commit) +- Resolves: bz#1626059 + (RHEL6 guest panics on boot if hotpluggable memory (pc-dimm) is present at boot time) +- Resolves: bz#1628373 + (blockdev-backup does not accept bitmap parameter) + +* Wed Sep 12 2018 Miroslav Rezanina - 2.12.0-15.el7 +- kvm-jobs-change-start-callback-to-run-callback.patch [bz#1626061] +- kvm-jobs-canonize-Error-object.patch [bz#1626061] +- kvm-jobs-add-exit-shim.patch [bz#1626061] +- kvm-block-commit-utilize-job_exit-shim.patch [bz#1626061] +- kvm-block-mirror-utilize-job_exit-shim.patch [bz#1626061] +- kvm-jobs-utilize-job_exit-shim.patch [bz#1626061] +- kvm-block-backup-make-function-variables-consistently-na.patch [bz#1626061] +- kvm-jobs-remove-ret-argument-to-job_completed-privatize-.patch [bz#1626061] +- kvm-jobs-remove-job_defer_to_main_loop.patch [bz#1626061] +- kvm-block-commit-add-block-job-creation-flags.patch [bz#1626061] +- kvm-block-mirror-add-block-job-creation-flags.patch [bz#1626061] +- kvm-block-stream-add-block-job-creation-flags.patch [bz#1626061] +- kvm-block-commit-refactor-commit-to-use-job-callbacks.patch [bz#1626061] +- kvm-block-mirror-don-t-install-backing-chain-on-abort.patch [bz#1626061] +- kvm-block-mirror-conservative-mirror_exit-refactor.patch [bz#1626061] +- kvm-block-stream-refactor-stream-to-use-job-callbacks.patch [bz#1626061] +- kvm-tests-blockjob-replace-Blockjob-with-Job.patch [bz#1626061] +- kvm-tests-test-blockjob-remove-exit-callback.patch [bz#1626061] +- kvm-tests-test-blockjob-txn-move-.exit-to-.clean.patch [bz#1626061] +- kvm-jobs-remove-.exit-callback.patch [bz#1626061] +- kvm-qapi-block-commit-expose-new-job-properties.patch [bz#1626061] +- kvm-qapi-block-mirror-expose-new-job-properties.patch [bz#1626061] +- kvm-qapi-block-stream-expose-new-job-properties.patch [bz#1626061] +- kvm-block-backup-qapi-documentation-fixup.patch [bz#1626061] +- kvm-blockdev-document-transactional-shortcomings.patch [bz#1626061] +- Resolves: bz#1626061 + (qemu blockjobs other than backup do not support job-finalize or job-dismiss) + +* Tue Sep 11 2018 Miroslav Rezanina - 2.12.0-14.el7 +- kvm-mirror-Fail-gracefully-for-source-target.patch [bz#1582042] +- Resolves: bz#1582042 + (Segfault on 'blockdev-mirror' with same node as source and target) + +* Tue Sep 04 2018 Miroslav Rezanina - 2.12.0-13.el7 +- kvm-linux-headers-asm-s390-kvm.h-header-sync.patch [bz#1622962] +- kvm-s390x-kvm-add-etoken-facility.patch [bz#1622962] +- kvm-block-for-jobs-do-not-clear-user_paused-until-after-.patch [bz#1605026] +- kvm-iotests-Add-failure-matching-to-common.qemu.patch [bz#1605026] +- kvm-block-iotest-to-catch-abort-on-forced-blockjob-cance.patch [bz#1605026] +- kvm-i386-define-the-ssbd-CPUID-feature-bit-CVE-2018-3639.patch [bz#1574216] +- kvm-target-i386-sev-fix-memory-leaks.patch [bz#1624390] +- kvm-i386-Fix-arch_query_cpu_model_expansion-leak.patch [bz#1624390] +- kvm-migration-discard-non-migratable-RAMBlocks.patch [bz#1539280] +- kvm-vfio-pci-do-not-set-the-PCIDevice-has_rom-attribute.patch [bz#1539280] +- kvm-memory-exec-Expose-all-memory-block-related-flags.patch [bz#1539280] +- kvm-memory-exec-switch-file-ram-allocation-functions-to-.patch [bz#1539280] +- kvm-configure-add-libpmem-support.patch [bz#1539280] +- kvm-hostmem-file-add-the-pmem-option.patch [bz#1539280] +- kvm-mem-nvdimm-ensure-write-persistence-to-PMEM-in-label.patch [bz#1539280] +- kvm-migration-ram-Add-check-and-info-message-to-nvdimm-p.patch [bz#1539280] +- kvm-migration-ram-ensure-write-persistence-on-loading-al.patch [bz#1539280] +- kvm-intel-iommu-send-PSI-always-even-if-across-PDEs.patch [bz#1623859] +- kvm-intel-iommu-remove-IntelIOMMUNotifierNode.patch [bz#1623859] +- kvm-intel-iommu-add-iommu-lock.patch [bz#1623859] +- kvm-intel-iommu-only-do-page-walk-for-MAP-notifiers.patch [bz#1623859] +- kvm-intel-iommu-introduce-vtd_page_walk_info.patch [bz#1623859] +- kvm-intel-iommu-pass-in-address-space-when-page-walk.patch [bz#1623859] +- kvm-intel-iommu-trace-domain-id-during-page-walk.patch [bz#1623859] +- kvm-util-implement-simple-iova-tree.patch [bz#1623859] +- kvm-intel-iommu-rework-the-page-walk-logic.patch [bz#1623859] +- kvm-qemu-img-fix-regression-copying-secrets-during-conve.patch [bz#1575578] +- kvm-redhat-rewrap-build_configure.sh-cmdline-for-the-rh-.patch [bz#1500753] +- kvm-redhat-enable-opengl-for-x86_64.patch [bz#1500753] +- Resolves: bz#1500753 + ([RFE] Support console on Intel vGPU - qemu) +- Resolves: bz#1539280 + ([Intel 7.6 Bug] [KVM][Crystal Ridge] Lack of data persistence guarantee of QEMU writes to host PMEM) +- Resolves: bz#1574216 + (CVE-2018-3639 qemu-kvm-rhev: hw: cpu: speculative store bypass [rhel-7.6]) +- Resolves: bz#1575578 + (Failed to convert a source image to the qcow2 image encrypted by luks) +- Resolves: bz#1605026 + (Quitting VM causes qemu core dump once the block mirror job paused for no enough target space) +- Resolves: bz#1622962 + (Add etoken support to qemu-kvm for s390x KVM guests) +- Resolves: bz#1623859 + (Guest "Detected Tx unit Hang" and host "DMAR: fault addr" when booting guest with ixgbe device assignment,) +- Resolves: bz#1624390 + (Memory leaks) + +* Tue Aug 28 2018 Miroslav Rezanina - 2.12.0-12.el7 +- kvm-e1000e-Do-not-auto-clear-ICR-bits-which-aren-t-set-i.patch [bz#1596010] +- kvm-e1000e-Prevent-MSI-MSI-X-storms.patch [bz#1596010] +- kvm-hw-usb-dev-smartcard-reader-Handle-64-B-USB-packets.patch [bz#1589147] +- kvm-i386-Disable-TOPOEXT-by-default-on-cpu-host.patch [bz#1613277] +- kvm-RHEL-Disable-transparent-hugepages-on-POWER8-KVM-hos.patch [bz#1620378] +- Resolves: bz#1589147 + (Handle 64 B USB packets for Smart Card redirection) +- Resolves: bz#1596010 + (The network link can't be detected on guest when the guest uses e1000e model type) +- Resolves: bz#1613277 + (kernel panic in init_amd_cacheinfo) +- Resolves: bz#1620378 + (qemu-kvm-rhev: Failed to allocate KVM HPT with vfio device enabled - disable THP for POWER8 guests) + +* Mon Aug 20 2018 Miroslav Rezanina - 2.12.0-11.el7 +- kvm-slirp-reformat-m_inc-routine.patch [bz#1586255] +- kvm-slirp-Correct-size-check-in-m_inc.patch [bz#1586255] +- kvm-Revert-Disable-PCIe-to-PCI-bridge-device.patch [bz#1390329] +- kvm-aio-posix-Don-t-count-ctx-notifier-as-progress-when-.patch [bz#1562750] +- kvm-aio-Do-aio_notify_accept-only-during-blocking-aio_po.patch [bz#1562750] +- Resolves: bz#1390329 + (PCIe: Add Generic PCIe-PCI bridge) +- Resolves: bz#1562750 + (VM doesn't boot from HD) +- Resolves: bz#1586255 + (CVE-2018-11806 qemu-kvm-rhev: QEMU: slirp: heap buffer overflow while reassembling fragmented datagrams [rhel-7.6]) + +* Fri Aug 10 2018 Miroslav Rezanina - 2.12.0-10.el7 +- kvm-qemu-img-Add-C-option-for-convert-with-copy-offloadi.patch [bz#1607774] +- kvm-iotests-Add-test-for-qemu-img-convert-C-compatibilit.patch [bz#1607774] +- kvm-qemu-img-Fix-assert-when-mapping-unaligned-raw-file.patch [bz#1601310] +- kvm-iotests-Add-test-221-to-catch-qemu-img-map-regressio.patch [bz#1601310] +- kvm-pc-acpi-fix-memory-hotplug-regression-by-reducing-st.patch [bz#1609234] +- kvm-block-qapi-Add-qdev-field-to-query-blockstats-result.patch [bz#1612114] +- kvm-block-qapi-Include-anonymous-BBs-in-query-blockstats.patch [bz#1612114] +- kvm-qemu-iotests-Test-query-blockstats-with-drive-and-bl.patch [bz#1612114] +- kvm-Add-local-build-configure-for-s390x.patch [bz#1573135] +- kvm-Update-build-configuration.patch [bz#1573135] +- kvm-Update-local-build-to-work-with-2.12.0-configuration.patch [bz#1573135] +- kvm-Ensure-all-iotests-are-executable-on-build-from-srpm.patch [bz#1608229] +- Resolves: bz#1573135 + (Update build configure for QEMU 2.12.0) +- Resolves: bz#1601310 + (qemu-img map 'Aborted (core dumped)' when specifying a plain file) +- Resolves: bz#1607774 + (Target files for 'qemu-img convert' do not support thin_provisoning with iscsi/nfs backend) +- Resolves: bz#1608229 + (Parts of iotest cases in SRPM don't have execute permission) +- Resolves: bz#1609234 + (Win2016 guest can't recognize pc-dimm hotplugged to node 0) +- Resolves: bz#1612114 + (Anonymous BlockBackends are missing in query-blockstats) + +* Wed Aug 01 2018 Miroslav Rezanina - 2.12.0-9.el7 +- kvm-Disable-aarch64-devices-reappeared-after-2.12-rebase.patch [bz#1586357] +- kvm-Disable-split-irq-device.patch [bz#1586357] +- kvm-Disable-AT24Cx-i2c-eeprom.patch [bz#1586357] +- kvm-Disable-CAN-bus-devices.patch [bz#1586357] +- kvm-Disable-new-superio-devices.patch [bz#1586357] +- kvm-Disable-new-pvrdma-device.patch [bz#1586357] +- kvm-Disable-PCIe-to-PCI-bridge-device.patch [bz#1586357] +- kvm-qdev-add-HotplugHandler-post_plug-callback.patch [bz#1607891] +- kvm-virtio-scsi-fix-hotplug-reset-vs-event-race.patch [bz#1607891] +- kvm-i386-Allow-TOPOEXT-to-be-enabled-on-older-kernels.patch [bz#1608698] +- kvm-e1000-Fix-tso_props-compat-for-82540em.patch [bz#1608778] +- kvm-Revert-redhat-support-POWER8-on-POWER9-settings-in-k.patch [bz#1607443] +- kvm-slirp-correct-size-computation-while-concatenating-m.patch [bz#1586255] +- kvm-s390x-sclp-fix-maxram-calculation.patch [bz#1595740] +- kvm-Fix-update-of-qemu-kvm-tools.patch [bz#1598104] +- Resolves: bz#1586255 + (CVE-2018-11806 qemu-kvm-rhev: QEMU: slirp: heap buffer overflow while reassembling fragmented datagrams [rhel-7.6]) +- Resolves: bz#1586357 + (Disable new devices in 2.12) +- Resolves: bz#1595740 + (RHEL-Alt-7.6 - qemu has error during migration of larger guests) +- Resolves: bz#1598104 + (Upgrade failed from qemu-kvm-tools-rhev-2.12.0-6.el7 to qemu-kvm-tools-rhev-2.12.0-7.el7) +- Resolves: bz#1607443 + (qemu-kvm-rhev: Remove POWER8-on-POWER9 settings from kvm-setup) +- Resolves: bz#1607891 + (Hotplug events are sometimes lost with virtio-scsi + iothread) +- Resolves: bz#1608698 + (topoext support should not require kernel support) +- Resolves: bz#1608778 + (qemu/migration: migrate failed from RHEL.7.6 to RHEL.7.5 with e1000-82540em) + +* Tue Jul 24 2018 Miroslav Rezanina - 2.12.0-8.el7 +- kvm-RHEL-7.6-Add-pseries-rhel7.6.0-sxxm-machine-type.patch [bz#1592648] +- kvm-i386-Helpers-to-encode-cache-information-consistentl.patch [bz#1481253] +- kvm-i386-Add-cache-information-in-X86CPUDefinition.patch [bz#1481253] +- kvm-i386-Initialize-cache-information-for-EPYC-family-pr.patch [bz#1481253] +- kvm-i386-Add-new-property-to-control-cache-info.patch [bz#1481253] +- kvm-i386-Clean-up-cache-CPUID-code.patch [bz#1481253] +- kvm-i386-Populate-AMD-Processor-Cache-Information-for-cp.patch [bz#1481253] +- kvm-i386-Add-support-for-CPUID_8000_001E-for-AMD.patch [bz#1481253] +- kvm-i386-Fix-up-the-Node-id-for-CPUID_8000_001E.patch [bz#1481253] +- kvm-i386-Enable-TOPOEXT-feature-on-AMD-EPYC-CPU.patch [bz#1481253] +- kvm-i386-Remove-generic-SMT-thread-check.patch [bz#1481253] +- kvm-xhci-fix-guest-triggerable-assert.patch [bz#1594135] +- kvm-virtio-gpu-tweak-scanout-disable.patch [bz#1589634] +- kvm-virtio-gpu-update-old-resource-too.patch [bz#1589634] +- kvm-virtio-gpu-disable-scanout-when-backing-resource-is-.patch [bz#1589634] +- kvm-block-Don-t-silently-truncate-node-names.patch [bz#1549654] +- kvm-pr-helper-fix-socket-path-default-in-help.patch [bz#1533158] +- kvm-pr-helper-fix-assertion-failure-on-failed-multipath-.patch [bz#1533158] +- kvm-pr-manager-helper-avoid-SIGSEGV-when-writing-to-the-.patch [bz#1533158] +- kvm-pr-manager-put-stubs-in-.c-file.patch [bz#1533158] +- kvm-pr-manager-add-query-pr-managers-QMP-command.patch [bz#1533158] +- kvm-pr-manager-helper-report-event-on-connection-disconn.patch [bz#1533158] +- kvm-pr-helper-avoid-error-on-PR-IN-command-with-zero-req.patch [bz#1533158] +- kvm-pr-helper-Rework-socket-path-handling.patch [bz#1533158] +- kvm-pr-manager-helper-fix-memory-leak-on-event.patch [bz#1533158] +- kvm-object-fix-OBJ_PROP_LINK_UNREF_ON_RELEASE-ambivalenc.patch [bz#1556678] +- kvm-usb-hcd-xhci-test-add-a-test-for-ccid-hotplug.patch [bz#1556678] +- kvm-Revert-usb-release-the-created-buses.patch [bz#1556678] +- kvm-file-posix-Fix-creation-locking.patch [bz#1599335] +- kvm-file-posix-Unlock-FD-after-creation.patch [bz#1599335] +- kvm-ahci-trim-signatures-on-raise-lower.patch [bz#1584914] +- kvm-ahci-fix-PxCI-register-race.patch [bz#1584914] +- kvm-ahci-don-t-schedule-unnecessary-BH.patch [bz#1584914] +- kvm-qcow2-Fix-qcow2_truncate-error-return-value.patch [bz#1595173] +- kvm-block-Convert-.bdrv_truncate-callback-to-coroutine_f.patch [bz#1595173] +- kvm-qcow2-Remove-coroutine-trampoline-for-preallocate_co.patch [bz#1595173] +- kvm-block-Move-bdrv_truncate-implementation-to-io.c.patch [bz#1595173] +- kvm-block-Use-tracked-request-for-truncate.patch [bz#1595173] +- kvm-file-posix-Make-.bdrv_co_truncate-asynchronous.patch [bz#1595173] +- kvm-block-Fix-copy-on-read-crash-with-partial-final-clus.patch [bz#1590640] +- kvm-block-fix-QEMU-crash-with-scsi-hd-and-drive_del.patch [bz#1599515] +- kvm-virtio-rng-process-pending-requests-on-DRIVER_OK.patch [bz#1576743] +- kvm-file-posix-specify-expected-filetypes.patch [bz#1525829] +- kvm-iotests-add-test-226-for-file-driver-types.patch [bz#1525829] +- kvm-osdep-powerpc64-align-memory-to-allow-2MB-radix-THP-.patch [bz#1600797] +- kvm-spapr-Correct-inverted-test-in-spapr_pc_dimm_node.patch [bz#1598287] +- kvm-block-dirty-bitmap-add-lock-to-bdrv_enable-disable_d.patch [bz#1207657] +- kvm-qapi-add-x-block-dirty-bitmap-enable-disable.patch [bz#1207657] +- kvm-qmp-transaction-support-for-x-block-dirty-bitmap-ena.patch [bz#1207657] +- kvm-qapi-add-x-block-dirty-bitmap-merge.patch [bz#1207657] +- kvm-qapi-add-disabled-parameter-to-block-dirty-bitmap-ad.patch [bz#1207657] +- kvm-block-dirty-bitmap-add-bdrv_enable_dirty_bitmap_lock.patch [bz#1207657] +- kvm-dirty-bitmap-fix-double-lock-on-bitmap-enabling.patch [bz#1207657] +- kvm-block-qcow2-bitmap-fix-free_bitmap_clusters.patch [bz#1207657] +- kvm-qcow2-add-overlap-check-for-bitmap-directory.patch [bz#1207657] +- kvm-blockdev-enable-non-root-nodes-for-backup-source.patch [bz#1207657] +- kvm-iotests-add-222-to-test-basic-fleecing.patch [bz#1207657] +- kvm-qcow2-Remove-dead-check-on-ret.patch [bz#1207657] +- kvm-block-Move-request-tracking-to-children-in-copy-offl.patch [bz#1207657] +- kvm-block-Fix-parameter-checking-in-bdrv_co_copy_range_i.patch [bz#1207657] +- kvm-block-Honour-BDRV_REQ_NO_SERIALISING-in-copy-range.patch [bz#1207657] +- kvm-backup-Use-copy-offloading.patch [bz#1207657] +- kvm-block-backup-disable-copy-offloading-for-backup.patch [bz#1207657] +- kvm-iotests-222-Don-t-run-with-luks.patch [bz#1207657] +- kvm-block-io-fix-copy_range.patch [bz#1207657] +- kvm-block-split-flags-in-copy_range.patch [bz#1207657] +- kvm-block-add-BDRV_REQ_SERIALISING-flag.patch [bz#1207657] +- kvm-block-backup-fix-fleecing-scheme-use-serialized-writ.patch [bz#1207657] +- kvm-nbd-server-Reject-0-length-block-status-request.patch [bz#1207657] +- kvm-nbd-server-fix-trace.patch [bz#1207657] +- kvm-nbd-server-refactor-NBDExportMetaContexts.patch [bz#1207657] +- kvm-nbd-server-add-nbd_meta_empty_or_pattern-helper.patch [bz#1207657] +- kvm-nbd-server-implement-dirty-bitmap-export.patch [bz#1207657] +- kvm-qapi-new-qmp-command-nbd-server-add-bitmap.patch [bz#1207657] +- kvm-docs-interop-add-nbd.txt.patch [bz#1207657] +- kvm-nbd-server-introduce-NBD_CMD_CACHE.patch [bz#1207657] +- kvm-nbd-server-Silence-gcc-false-positive.patch [bz#1207657] +- kvm-nbd-server-Fix-dirty-bitmap-logic-regression.patch [bz#1207657] +- kvm-nbd-server-fix-nbd_co_send_block_status.patch [bz#1207657] +- kvm-nbd-client-Add-x-dirty-bitmap-to-query-bitmap-from-s.patch [bz#1207657] +- kvm-iotests-New-test-223-for-exporting-dirty-bitmap-over.patch [bz#1207657] +- kvm-hw-char-serial-Only-retry-if-qemu_chr_fe_write-retur.patch [bz#1592817] +- kvm-hw-char-serial-retry-write-if-EAGAIN.patch [bz#1592817] +- kvm-throttle-groups-fix-hang-when-group-member-leaves.patch [bz#1535914] +- Resolves: bz#1207657 + (RFE: QEMU Incremental live backup - push and pull modes) +- Resolves: bz#1481253 + (AMD EPYC/Zen SMT support for KVM / QEMU guest (qemu-kvm-rhev)) +- Resolves: bz#1525829 + (can not boot up a scsi-block passthrough disk via -blockdev with error "cannot get SG_IO version number: Operation not supported. Is this a SCSI device?") +- Resolves: bz#1533158 + (QEMU support for libvirtd restarting qemu-pr-helper) +- Resolves: bz#1535914 + (Disable io throttling for one member disk of a group during io will induce the other one hang with io) +- Resolves: bz#1549654 + (Reject node-names which would be truncated by the block layer commands) +- Resolves: bz#1556678 + (Hot plug usb-ccid for the 2nd time with the same ID as the 1st time failed) +- Resolves: bz#1576743 + (virtio-rng hangs when running on recent (2.x) QEMU versions) +- Resolves: bz#1584914 + (SATA emulator lags and hangs) +- Resolves: bz#1589634 + (Migration failed when rebooting guest with multiple virtio videos) +- Resolves: bz#1590640 + (qemu-kvm: block/io.c:1098: bdrv_co_do_copy_on_readv: Assertion `skip_bytes < pnum' failed.) +- Resolves: bz#1592648 + (Create pseries-rhel7.6.0-sxxm machine type) +- Resolves: bz#1592817 + (Retrying on serial_xmit if the pipe is broken may compromise the Guest) +- Resolves: bz#1594135 + (system_reset many times linux guests cause qemu process Aborted) +- Resolves: bz#1595173 + (blockdev-create is blocking) +- Resolves: bz#1598287 + (After rebooting guest,all the hot plug memory will be assigned to the 1st numa node.) +- Resolves: bz#1599335 + (Image creation locking is too tight and is not properly released) +- Resolves: bz#1599515 + (qemu core-dump with aio_read via hmp (util/qemu-thread-posix.c:64: qemu_mutex_lock_impl: Assertion `mutex->initialized' failed)) +- Resolves: bz#1600797 + (RHEL7.5/RHV4.2 - qemu patch to align memory to allow 2MB THP) + +* Wed Jul 04 2018 Miroslav Rezanina - 2.12.0-7.el7 +- kvm-vfio-pci-Default-display-option-to-off.patch [bz#1583050] +- kvm-Add-qemu-keymap-to-qemu-kvm-tools.patch [bz#1590756] +- kvm-usb-host-skip-open-on-pending-postload-bh.patch [bz#1572851] +- kvm-i386-Define-the-Virt-SSBD-MSR-and-handling-of-it-CVE.patch [bz#1574216] +- kvm-i386-define-the-AMD-virt-ssbd-CPUID-feature-bit-CVE-.patch [bz#1574216] +- kvm-block-file-posix-Pass-FD-to-locking-helpers.patch [bz#1519144] +- kvm-block-file-posix-File-locking-during-creation.patch [bz#1519144] +- kvm-iotests-Add-creation-test-to-153.patch [bz#1519144] +- kvm-migration-stop-compressing-page-in-migration-thread.patch [bz#1584139] +- kvm-migration-stop-compression-to-allocate-and-free-memo.patch [bz#1584139] +- kvm-migration-stop-decompression-to-allocate-and-free-me.patch [bz#1584139] +- kvm-migration-detect-compression-and-decompression-error.patch [bz#1584139] +- kvm-migration-introduce-control_save_page.patch [bz#1584139] +- kvm-migration-move-some-code-to-ram_save_host_page.patch [bz#1584139] +- kvm-migration-move-calling-control_save_page-to-the-comm.patch [bz#1584139] +- kvm-migration-move-calling-save_zero_page-to-the-common-.patch [bz#1584139] +- kvm-migration-introduce-save_normal_page.patch [bz#1584139] +- kvm-migration-remove-ram_save_compressed_page.patch [bz#1584139] +- kvm-migration-block-dirty-bitmap-fix-memory-leak-in-dirt.patch [bz#1584139] +- kvm-migration-fix-saving-normal-page-even-if-it-s-been-c.patch [bz#1584139] +- kvm-migration-update-index-field-when-delete-or-qsort-RD.patch [bz#1584139] +- kvm-Migration-TLS-Fix-crash-due-to-double-cleanup.patch [bz#1584139] +- kvm-migration-introduce-decompress-error-check.patch [bz#1584139] +- kvm-migration-Don-t-activate-block-devices-if-using-S.patch [bz#1560854] +- kvm-migration-not-wait-RDMA_CM_EVENT_DISCONNECTED-event-.patch [bz#1584139] +- kvm-migration-block-dirty-bitmap-fix-dirty_bitmap_load.patch [bz#1584139] +- kvm-vhost-user-add-Net-prefix-to-internal-state-structur.patch [bz#1526645] +- kvm-virtio-support-setting-memory-region-based-host-noti.patch [bz#1526645] +- kvm-vhost-user-support-receiving-file-descriptors-in-sla.patch [bz#1526645] +- kvm-osdep-add-wait.h-compat-macros.patch [bz#1526645] +- kvm-vhost-user-bridge-support-host-notifier.patch [bz#1526645] +- kvm-vhost-allow-backends-to-filter-memory-sections.patch [bz#1526645] +- kvm-vhost-user-allow-slave-to-send-fds-via-slave-channel.patch [bz#1526645] +- kvm-vhost-user-introduce-shared-vhost-user-state.patch [bz#1526645] +- kvm-vhost-user-support-registering-external-host-notifie.patch [bz#1526645] +- kvm-libvhost-user-support-host-notifier.patch [bz#1526645] +- kvm-block-Introduce-API-for-copy-offloading.patch [bz#1482537] +- kvm-raw-Check-byte-range-uniformly.patch [bz#1482537] +- kvm-raw-Implement-copy-offloading.patch [bz#1482537] +- kvm-qcow2-Implement-copy-offloading.patch [bz#1482537] +- kvm-file-posix-Implement-bdrv_co_copy_range.patch [bz#1482537] +- kvm-iscsi-Query-and-save-device-designator-when-opening.patch [bz#1482537] +- kvm-iscsi-Create-and-use-iscsi_co_wait_for_task.patch [bz#1482537] +- kvm-iscsi-Implement-copy-offloading.patch [bz#1482537] +- kvm-block-backend-Add-blk_co_copy_range.patch [bz#1482537] +- kvm-qemu-img-Convert-with-copy-offloading.patch [bz#1482537] +- kvm-qcow2-Fix-src_offset-in-copy-offloading.patch [bz#1482537] +- kvm-iscsi-Don-t-blindly-use-designator-length-in-respons.patch [bz#1482537] +- kvm-file-posix-Fix-EINTR-handling.patch [bz#1482537] +- kvm-pc-Add-rhel7.6.0-machine-types.patch [bz#1557051] +- kvm-usb-storage-Add-rerror-werror-properties.patch [bz#1595180] +- kvm-numa-clarify-error-message-when-node-index-is-out-of.patch [bz#1578381] +- kvm-qemu-iotests-Update-026.out.nocache-reference-output.patch [bz#1528541] +- kvm-qcow2-Free-allocated-clusters-on-write-error.patch [bz#1528541] +- kvm-qemu-iotests-Test-qcow2-not-leaking-clusters-on-writ.patch [bz#1528541] +- kvm-s390x-cpumodel-default-enable-bpb-and-ppa15-for-z196.patch [bz#1595715] +- kvm-qemu-options-Add-missing-newline-to-accel-help-text.patch [bz#1586313] +- Resolves: bz#1482537 + ([RFE] qemu-img copy-offloading (convert command)) +- Resolves: bz#1519144 + (qemu-img: image locking doesn't cover image creation) +- Resolves: bz#1526645 + ([Intel 7.6 FEAT] vHost Data Plane Acceleration (vDPA) - vhost user client - qemu-kvm-rhev) +- Resolves: bz#1528541 + (qemu-img check reports tons of leaked clusters after re-start nfs service to resume writing data in guest) +- Resolves: bz#1557051 + (pc-i440fx-rhel7.6.0 and pc-q35-rhel7.6.0 machine types (x86)) +- Resolves: bz#1560854 + (Guest is left paused on source host sometimes if kill source libvirtd during live migration due to QEMU image locking) +- Resolves: bz#1572851 + (Core dumped after migration when with usb-host) +- Resolves: bz#1574216 + (CVE-2018-3639 qemu-kvm-rhev: hw: cpu: speculative store bypass [rhel-7.6]) +- Resolves: bz#1578381 + (Error message need update when specify numa distance with node index >=128) +- Resolves: bz#1583050 + (Fails to start guest with Intel vGPU device) +- Resolves: bz#1584139 + (2.12 migration fixes) +- Resolves: bz#1586313 + (-smp option is not easily found in the output of qemu help) +- Resolves: bz#1590756 + (add qemu-keymap utility) +- Resolves: bz#1595180 + (Can't set rerror/werror with usb-storage) +- Resolves: bz#1595715 + (Add ppa15/bpb to the default cpu model for z196 and higher in the 7.6 s390-ccw-virtio machine) + +* Sat Jun 30 2018 Miroslav Rezanina - 2.12.0-6.el7 +- kvm-Fix-permissions-for-iotest-218.patch [] +- kvm-qxl-fix-local-renderer-crash.patch [bz#1567733] +- kvm-qemu-img-Amendment-support-implies-create_opts.patch [bz#1537956] +- kvm-block-Add-Error-parameter-to-bdrv_amend_options.patch [bz#1537956] +- kvm-qemu-option-Pull-out-Supported-options-print.patch [bz#1537956] +- kvm-qemu-img-Add-print_amend_option_help.patch [bz#1537956] +- kvm-qemu-img-Recognize-no-creation-support-in-o-help.patch [bz#1537956] +- kvm-iotests-Test-help-option-for-unsupporting-formats.patch [bz#1537956] +- kvm-iotests-Rework-113.patch [bz#1537956] +- kvm-qemu-img-Resolve-relative-backing-paths-in-rebase.patch [bz#1569835] +- kvm-iotests-Add-test-for-rebasing-with-relative-paths.patch [bz#1569835] +- kvm-qemu-img-Special-post-backing-convert-handling.patch [bz#1527898] +- kvm-iotests-Test-post-backing-convert-target-behavior.patch [bz#1527898] +- kvm-migration-calculate-expected_downtime-with-ram_bytes.patch [bz#1564576] +- kvm-sheepdog-Fix-sd_co_create_opts-memory-leaks.patch [bz#1513543] +- kvm-qemu-iotests-reduce-chance-of-races-in-185.patch [bz#1513543] +- kvm-blockjob-do-not-cancel-timer-in-resume.patch [bz#1513543] +- kvm-nfs-Fix-error-path-in-nfs_options_qdict_to_qapi.patch [bz#1513543] +- kvm-nfs-Remove-processed-options-from-QDict.patch [bz#1513543] +- kvm-blockjob-drop-block_job_pause-resume_all.patch [bz#1513543] +- kvm-blockjob-expose-error-string-via-query.patch [bz#1513543] +- kvm-blockjob-Fix-assertion-in-block_job_finalize.patch [bz#1513543] +- kvm-blockjob-Wrappers-for-progress-counter-access.patch [bz#1513543] +- kvm-blockjob-Move-RateLimit-to-BlockJob.patch [bz#1513543] +- kvm-blockjob-Implement-block_job_set_speed-centrally.patch [bz#1513543] +- kvm-blockjob-Introduce-block_job_ratelimit_get_delay.patch [bz#1513543] +- kvm-blockjob-Add-block_job_driver.patch [bz#1513543] +- kvm-blockjob-Update-block-job-pause-resume-documentation.patch [bz#1513543] +- kvm-blockjob-Improve-BlockJobInfo.offset-len-documentati.patch [bz#1513543] +- kvm-job-Create-Job-JobDriver-and-job_create.patch [bz#1513543] +- kvm-job-Rename-BlockJobType-into-JobType.patch [bz#1513543] +- kvm-job-Add-JobDriver.job_type.patch [bz#1513543] +- kvm-job-Add-job_delete.patch [bz#1513543] +- kvm-job-Maintain-a-list-of-all-jobs.patch [bz#1513543] +- kvm-job-Move-state-transitions-to-Job.patch [bz#1513543] +- kvm-job-Add-reference-counting.patch [bz#1513543] +- kvm-job-Move-cancelled-to-Job.patch [bz#1513543] +- kvm-job-Add-Job.aio_context.patch [bz#1513543] +- kvm-job-Move-defer_to_main_loop-to-Job.patch [bz#1513543] +- kvm-job-Move-coroutine-and-related-code-to-Job.patch [bz#1513543] +- kvm-job-Add-job_sleep_ns.patch [bz#1513543] +- kvm-job-Move-pause-resume-functions-to-Job.patch [bz#1513543] +- kvm-job-Replace-BlockJob.completed-with-job_is_completed.patch [bz#1513543] +- kvm-job-Move-BlockJobCreateFlags-to-Job.patch [bz#1513543] +- kvm-blockjob-Split-block_job_event_pending.patch [bz#1513543] +- kvm-job-Add-job_event_.patch [bz#1513543] +- kvm-job-Move-single-job-finalisation-to-Job.patch [bz#1513543] +- kvm-job-Convert-block_job_cancel_async-to-Job.patch [bz#1513543] +- kvm-job-Add-job_drain.patch [bz#1513543] +- kvm-job-Move-.complete-callback-to-Job.patch [bz#1513543] +- kvm-job-Move-job_finish_sync-to-Job.patch [bz#1513543] +- kvm-job-Switch-transactions-to-JobTxn.patch [bz#1513543] +- kvm-job-Move-transactions-to-Job.patch [bz#1513543] +- kvm-job-Move-completion-and-cancellation-to-Job.patch [bz#1513543] +- kvm-block-Cancel-job-in-bdrv_close_all-callers.patch [bz#1513543] +- kvm-job-Add-job_yield.patch [bz#1513543] +- kvm-job-Add-job_dismiss.patch [bz#1513543] +- kvm-job-Add-job_is_ready.patch [bz#1513543] +- kvm-job-Add-job_transition_to_ready.patch [bz#1513543] +- kvm-job-Move-progress-fields-to-Job.patch [bz#1513543] +- kvm-job-Introduce-qapi-job.json.patch [bz#1513543] +- kvm-job-Add-JOB_STATUS_CHANGE-QMP-event.patch [bz#1513543] +- kvm-job-Add-lifecycle-QMP-commands.patch [bz#1513543] +- kvm-job-Add-query-jobs-QMP-command.patch [bz#1513543] +- kvm-blockjob-Remove-BlockJob.driver.patch [bz#1513543] +- kvm-iotests-Move-qmp_to_opts-to-VM.patch [bz#1513543] +- kvm-qemu-iotests-Test-job-with-block-jobs.patch [bz#1513543] +- kvm-vdi-Fix-vdi_co_do_create-return-value.patch [bz#1513543] +- kvm-vhdx-Fix-vhdx_co_create-return-value.patch [bz#1513543] +- kvm-job-Add-error-message-for-failing-jobs.patch [bz#1513543] +- kvm-block-create-Make-x-blockdev-create-a-job.patch [bz#1513543] +- kvm-qemu-iotests-Add-VM.get_qmp_events_filtered.patch [bz#1513543] +- kvm-qemu-iotests-Add-VM.qmp_log.patch [bz#1513543] +- kvm-qemu-iotests-Add-iotests.img_info_log.patch [bz#1513543] +- kvm-qemu-iotests-Add-VM.run_job.patch [bz#1513543] +- kvm-qemu-iotests-iotests.py-helper-for-non-file-protocol.patch [bz#1513543] +- kvm-qemu-iotests-Rewrite-206-for-blockdev-create-job.patch [bz#1513543] +- kvm-qemu-iotests-Rewrite-207-for-blockdev-create-job.patch [bz#1513543] +- kvm-qemu-iotests-Rewrite-210-for-blockdev-create-job.patch [bz#1513543] +- kvm-qemu-iotests-Rewrite-211-for-blockdev-create-job.patch [bz#1513543] +- kvm-qemu-iotests-Rewrite-212-for-blockdev-create-job.patch [bz#1513543] +- kvm-qemu-iotests-Rewrite-213-for-blockdev-create-job.patch [bz#1513543] +- kvm-block-create-Mark-blockdev-create-stable.patch [bz#1513543] +- kvm-jobs-fix-stale-wording.patch [bz#1513543] +- kvm-jobs-fix-verb-references-in-docs.patch [bz#1513543] +- kvm-iotests-Fix-219-s-timing.patch [bz#1513543] +- kvm-iotests-improve-pause_job.patch [bz#1513543] +- kvm-rpm-Whitelist-copy-on-read-block-driver.patch [bz#1518738] +- kvm-rpm-add-throttle-driver-to-rw-whitelist.patch [bz#1591076] +- Resolves: bz#1513543 + ([RFE] Add block job to create format on a storage device) +- Resolves: bz#1518738 + (Add 'copy-on-read' filter driver for use with blockdev-add) +- Resolves: bz#1527898 + ([RFE] qemu-img should leave cluster unallocated if it's read as zero throughout the backing chain) +- Resolves: bz#1537956 + (RFE: qemu-img amend should list the true supported options) +- Resolves: bz#1564576 + (Pegas 1.1 - Require to backport qemu-kvm patch that fixes expected_downtime calculation during migration) +- Resolves: bz#1567733 + (qemu abort when migrate during guest reboot) +- Resolves: bz#1569835 + (qemu-img get wrong backing file path after rebasing image with relative path) +- Resolves: bz#1591076 + (The driver of 'throttle' is not whitelisted) + +* Mon Jun 25 2018 Miroslav Rezanina - 2.12.0-5.el7 +- kvm-qobject-Use-qobject_to-instead-of-type-cast.patch [bz#1557995] +- kvm-qobject-Ensure-base-is-at-offset-0.patch [bz#1557995] +- kvm-qobject-use-a-QObjectBase_-struct.patch [bz#1557995] +- kvm-qobject-Replace-qobject_incref-QINCREF-qobject_decre.patch [bz#1557995] +- kvm-qobject-Modify-qobject_ref-to-return-obj.patch [bz#1557995] +- kvm-rbd-Drop-deprecated-drive-parameter-filename.patch [bz#1557995] +- kvm-iscsi-Drop-deprecated-drive-parameter-filename.patch [bz#1557995] +- kvm-block-Add-block-specific-QDict-header.patch [bz#1557995] +- kvm-qobject-Move-block-specific-qdict-code-to-block-qdic.patch [bz#1557995] +- kvm-block-Fix-blockdev-for-certain-non-string-scalars.patch [bz#1557995] +- kvm-block-Fix-drive-for-certain-non-string-scalars.patch [bz#1557995] +- kvm-block-Clean-up-a-misuse-of-qobject_to-in-.bdrv_co_cr.patch [bz#1557995] +- kvm-block-Factor-out-qobject_input_visitor_new_flat_conf.patch [bz#1557995] +- kvm-block-Make-remaining-uses-of-qobject-input-visitor-m.patch [bz#1557995] +- kvm-block-qdict-Simplify-qdict_flatten_qdict.patch [bz#1557995] +- kvm-block-qdict-Tweak-qdict_flatten_qdict-qdict_flatten_.patch [bz#1557995] +- kvm-block-qdict-Clean-up-qdict_crumple-a-bit.patch [bz#1557995] +- kvm-block-qdict-Simplify-qdict_is_list-some.patch [bz#1557995] +- kvm-check-block-qdict-Rename-qdict_flatten-s-variables-f.patch [bz#1557995] +- kvm-check-block-qdict-Cover-flattening-of-empty-lists-an.patch [bz#1557995] +- kvm-block-Fix-blockdev-blockdev-add-for-empty-objects-an.patch [bz#1557995] +- kvm-rbd-New-parameter-auth-client-required.patch [bz#1557995] +- kvm-rbd-New-parameter-key-secret.patch [bz#1557995] +- kvm-block-mirror-honor-ratelimit-again.patch [bz#1572856] +- kvm-block-mirror-Make-cancel-always-cancel-pre-READY.patch [bz#1572856] +- kvm-iotests-Add-test-for-cancelling-a-mirror-job.patch [bz#1572856] +- kvm-iotests-Split-214-off-of-122.patch [bz#1518738] +- kvm-block-Add-COR-filter-driver.patch [bz#1518738] +- kvm-block-BLK_PERM_WRITE-includes-._UNCHANGED.patch [bz#1518738] +- kvm-block-Add-BDRV_REQ_WRITE_UNCHANGED-flag.patch [bz#1518738] +- kvm-block-Set-BDRV_REQ_WRITE_UNCHANGED-for-COR-writes.patch [bz#1518738] +- kvm-block-quorum-Support-BDRV_REQ_WRITE_UNCHANGED.patch [bz#1518738] +- kvm-block-Support-BDRV_REQ_WRITE_UNCHANGED-in-filters.patch [bz#1518738] +- kvm-iotests-Clean-up-wrap-image-in-197.patch [bz#1518738] +- kvm-iotests-Copy-197-for-COR-filter-driver.patch [bz#1518738] +- kvm-iotests-Add-test-for-COR-across-nodes.patch [bz#1518738] +- kvm-qemu-io-Use-purely-string-blockdev-options.patch [bz#1576598] +- kvm-qemu-img-Use-only-string-options-in-img_open_opts.patch [bz#1576598] +- kvm-iotests-Add-test-for-U-force-share-conflicts.patch [bz#1576598] +- kvm-qemu-io-Drop-command-functions-return-values.patch [bz#1519617] +- kvm-qemu-io-Let-command-functions-return-error-code.patch [bz#1519617] +- kvm-qemu-io-Exit-with-error-when-a-command-failed.patch [bz#1519617] +- kvm-iotests.py-Add-qemu_io_silent.patch [bz#1519617] +- kvm-iotests-Let-216-make-use-of-qemu-io-s-exit-code.patch [bz#1519617] +- kvm-qcow2-Repair-OFLAG_COPIED-when-fixing-leaks.patch [bz#1527085] +- kvm-iotests-Repairing-error-during-snapshot-deletion.patch [bz#1527085] +- kvm-block-Make-bdrv_is_writable-public.patch [bz#1588039] +- kvm-qcow2-Do-not-mark-inactive-images-corrupt.patch [bz#1588039] +- kvm-iotests-Add-case-for-a-corrupted-inactive-image.patch [bz#1588039] +- kvm-s390x-cpumodels-add-z14-Model-ZR1.patch [bz#1592327] +- kvm-main-loop-drop-spin_counter.patch [bz#1168213] +- kvm-target-ppc-Factor-out-the-parsing-in-kvmppc_get_cpu_.patch [bz#1560847] +- kvm-target-ppc-Don-t-require-private-l1d-cache-on-POWER8.patch [bz#1560847] +- kvm-ppc-spapr_caps-Don-t-disable-cap_cfpc-on-POWER8-by-d.patch [bz#1560847] +- Resolves: bz#1168213 + (main-loop: WARNING: I/O thread spun for 1000 iterations while doing stream block device.) +- Resolves: bz#1518738 + (Add 'copy-on-read' filter driver for use with blockdev-add) +- Resolves: bz#1519617 + (The exit code should be non-zero when qemu-io reports an error) +- Resolves: bz#1527085 + (The copied flag should be updated during '-r leaks') +- Resolves: bz#1557995 + (QAPI schema for RBD storage misses the 'password-secret' option) +- Resolves: bz#1560847 + ([Power8][FW b0320a_1812.861][rhel7.5rc2 3.10.0-861.el7.ppc64le][qemu-kvm-{ma,rhev}-2.10.0-21.el7_5.1.ppc64le] KVM guest does not default to ori type flush even with pseries-rhel7.5.0-sxxm) +- Resolves: bz#1572856 + ('block-job-cancel' can not cancel a "drive-mirror" job) +- Resolves: bz#1576598 + (Segfault in qemu-io and qemu-img with -U --image-opts force-share=off) +- Resolves: bz#1588039 + (Possible assertion failure in qemu when a corrupted image is used during an incoming migration) +- Resolves: bz#1592327 + ([RHEL-Alt-7.6 FEAT] KVM: CPU Model z14 ZR1 (qemu-kvm-ma)) + +* Tue Jun 19 2018 Miroslav Rezanina - 2.12.0-4.el7 +- kvm-Fix-x-hv-max-vps-compat-value-for-7.4-machine-type.patch [bz#1583959] +- kvm-ccid-card-passthru-fix-regression-in-realize.patch [bz#1584984] +- kvm-remove-duplicate-HW_COMPAT_RHEL7_5.patch [bz#1542080] +- kvm-Use-4-MB-vram-for-cirrus.patch [bz#1542080] +- kvm-spapr_pci-Remove-unhelpful-pagesize-warning.patch [bz#1505664] +- kvm-redhat-cleanup-redhat-kvm-setup.patch [bz#1580297] +- kvm-redhat-add-a-configuration-file-for-kvm-setup.patch [bz#1580297] +- kvm-redhat-support-POWER8-on-POWER9-settings-in-kvm-setu.patch [bz#1580297] +- kvm-rpm-Add-nvme-VFIO-driver-to-rw-whitelist.patch [bz#1416180] +- Resolves: bz#1416180 + (QEMU VFIO based block driver for NVMe devices) +- Resolves: bz#1505664 + ("qemu-kvm: System page size 0x1000000 is not enabled in page_size_mask (0x11000). Performance may be slow" show up while using hugepage as guest's memory) +- Resolves: bz#1542080 + (Qemu core dump at cirrus_invalidate_region) +- Resolves: bz#1580297 + (qemu-kvm-rhev: Support POWER8-on-POWER9 settings in kvm-setup) +- Resolves: bz#1583959 + (Incorrect vcpu count limit for 7.4 machine types for windows guests) +- Resolves: bz#1584984 + (Vm starts failed with 'passthrough' smartcard) + +* Fri Jun 01 2018 Miroslav Rezanina - 2.12.0-3.el7 +- kvm-qemu-img-Check-post-truncation-size.patch [bz#1523065] +- kvm-s390x-add-RHEL-7.6-machine-type-for-ccw.patch [bz#1562138] +- kvm-redhat-define-HW_COMPAT_RHEL7_5.patch [bz#1557054] +- kvm-redhat-define-pseries-rhel7.6.0-machine-types.patch [bz#1557054] +- kvm-pc-pc-rhel75.5.0-compat-code.patch [bz#1578068] +- kvm-vga-catch-depth-0.patch [bz#1575541] +- kvm-spec-Enable-Native-Ceph-support-on-all-architectures.patch [bz#1578664] +- kvm-spec-Use-hardening-flags-for-ksmctl-build.patch [bz#1558516] +- Resolves: bz#1523065 + ("qemu-img resize" should fail to decrease the size of logical partition/lvm/iSCSI image with raw format) +- Resolves: bz#1557054 + (RHEL 7.6 new pseries machine type (ppc64le)) +- Resolves: bz#1558516 + (ksmctl is built without any hardening flags set [rhel-7.6]) +- Resolves: bz#1562138 + (RHEL 7.6 new qemu-kvm-ma machine type (s390x)) +- Resolves: bz#1575541 + (qemu core dump while installing win10 guest) +- Resolves: bz#1578068 + (Backwards compatibility of pc-*-rhel7.5.0 and older machine-types) +- Resolves: bz#1578664 + (Enable Native Ceph support on non x86_64 CPUs) + +* Wed May 16 2018 Miroslav Rezanina - 2.12.0-2.el7 +- kvm-AArch64-Add-virt-rhel7.6-machine-type.patch [bz#1558723] +- kvm-configuration-Use-gcrypt-instead-of-nettle.patch [bz#1549543] +- kvm-spec-Change-License-line.patch [bz#1549106] +- kvm-spapr-Add-ibm-max-associativity-domains-property.patch [bz#1570525] +- kvm-Revert-spapr-Don-t-allow-memory-hotplug-to-memory-le.patch [bz#1570525] +- kvm-tcg-workaround-branch-instruction-overflow-in-tcg_ou.patch [bz#1574577] +- kvm-s390-ccw-force-diag-308-subcode-to-unsigned-long.patch [bz#1523857] +- kvm-pc-bios-s390-ccw-size_t-should-be-unsigned.patch [bz#1523857] +- kvm-pc-bios-s390-ccw-rename-MAX_TABLE_ENTRIES-to-MAX_BOO.patch [bz#1523857] +- kvm-pc-bios-s390-ccw-fix-loadparm-initialization-and-int.patch [bz#1523857] +- kvm-pc-bios-s390-ccw-fix-non-sequential-boot-entries-eck.patch [bz#1523857] +- kvm-pc-bios-s390-ccw-fix-non-sequential-boot-entries-enu.patch [bz#1523857] +- kvm-cpus-Fix-event-order-on-resume-of-stopped-guest.patch [bz#1566153] +- Resolves: bz#1523857 + ([Pegas1.2 FEAT] KVM: Interactive Bootloader - qemu part) +- Resolves: bz#1549106 + (Incorrect License information in RPM specfile) +- Resolves: bz#1549543 + (Use of Nettle crypto library prevents FIPS compliance, need to go back to libgcrypt) +- Resolves: bz#1558723 + (Create RHEL-7.6 QEMU machine type for AArch64) +- Resolves: bz#1566153 + (IOERROR pause code lost after resuming a VM while I/O error is still present) +- Resolves: bz#1570525 + ([POWER][QEMU-KVM] Can't hotplug memory to initially memory-less NUMA node) +- Resolves: bz#1574577 + (qemu-kvm segfaults when run guestfsd under TCG) + +* Thu Apr 26 2018 Miroslav Rezanina - 2.12.0-1.el7 +- Rebase to QEMU 2.12.0 [bz#1562219] +- Resolves: bz#1562219 + (Rebase qemu-kvm-ma for RHEL-7.6) * Tue Feb 20 2018 Miroslav Rezanina - 2.10.0-21.el7 - kvm-migration-Recover-block-devices-if-failure-in-device.patch [bz#1538494] @@ -2548,7 +3345,7 @@ useradd -r -u 107 -g qemu -G kvm -d / -s /sbin/nologin \ - Resolves: bz#1517051 (POWER9 - Virt: QEMU: Migration of HPT guest on Radix host fails) -* Tue Dec 05 2017 Miroslav Rezanina - 2.10.0-11.el7 +* Tue Dec 05 2017 Miroslav Rezanina - ma-2.10.0-11.el7 - kvm-qcow2-don-t-permit-changing-encryption-parameters.patch [bz#1406803] - kvm-qcow2-fix-image-corruption-after-committing-qcow2-im.patch [bz#1406803] - kvm-qemu-doc-Add-UUID-support-in-initiator-name.patch [bz#1494210] @@ -2602,7 +3399,7 @@ useradd -r -u 107 -g qemu -G kvm -d / -s /sbin/nologin \ - Resolves: bz#1505701 (-blockdev fails if a qcow2 image has backing store format and backing store is referenced via node-name) -* Thu Nov 30 2017 Miroslav Rezanina - 2.10.0-10.el7 +* Thu Nov 30 2017 Miroslav Rezanina - ma-2.10.0-10.el7 - kvm-qcow2-fix-return-error-code-in-qcow2_truncate.patch [bz#1414049] - kvm-qcow2-Fix-unaligned-preallocated-truncation.patch [bz#1414049] - kvm-qcow2-Always-execute-preallocate-in-a-coroutine.patch [bz#1414049] @@ -2749,7 +3546,7 @@ useradd -r -u 107 -g qemu -G kvm -d / -s /sbin/nologin \ - Resolves: bz#1510001 (Pegas1.0 - qemu crashed during "info cpus" in monitor with change in default cpu in hotplug/unplug sequence (kvm)) -* Wed Nov 08 2017 Miroslav Rezanina - 2.10.0-5.el7 +* Wed Nov 08 2017 Miroslav Rezanina - ma-2.10.0-5.el7 - kvm-qemu-kvm-rhev-only-allows-pseries-rhel7.5.0-machine-.patch [bz#1478469] - kvm-pc-bios-keymaps-keymaps-update.patch [bz#1503128] - kvm-migration-Reset-rather-than-destroy-main_thread_load.patch [bz#1508799]